Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Условие выхода из цикла, если не известна длина массива.

68K
19 февраля 2013 года
BlGhost
24 / / 25.11.2012
Вопрос в следующем... Есть такой массив:

 
Код:
const char * FunctionArray[]=

{"Function1","Function2","Function3","Function4"}
Необходимо пробежаться по нему циклом, причем не использовать его размерность. Например, при пробегании по строке можно было бы использовать символ завершения строки, как условие выхода, а тут как быть? При перескоке на 5-й несуществующий элемент, там же мусор...
360
19 февраля 2013 года
P*t*
474 / / 15.02.2007
Нужно либо хранить размер массива, либо делать его на один элемент больше и добавлять пустой указатель NULL по аналогии с символом завершения строки.
Для константных массивов можно получать размер используя sizeof(массив)/sizeof(тип элемента).
326
01 ноября 2013 года
sadovoya
757 / / 19.11.2005
Ну, конкретно для этого можно так:

:)


 
Код:
...
    int i = 0;
    do {
        cout << FunctionArray[i] << endl;
    } while ((FunctionArray[i++])[8] != '4');
...
446
01 ноября 2013 года
Meander
487 / / 04.09.2011
У меня мусора нет

 
Код:
int i = 0;
  while(FunctionArray[i])
    std::cout << FunctionArray[i++] << std::endl;
414
02 ноября 2013 года
CassandraDied
763 / / 24.05.2012
Таких массивов просто не должно быть. Если есть что-то, по чему надо пробегаться, то это что-то должно хранить свой размер. Получать его где-то как-то и передавать с собой. Если есть что-то, что не имеет размера, то оно не используется для обработок, а только для передачи из одного места в другое.
326
02 ноября 2013 года
sadovoya
757 / / 19.11.2005
Может ТС просто думал, что определить длину си-строки можно только по нуль-терминатору. Отсюда столь странный вопрос :)
414
02 ноября 2013 года
CassandraDied
763 / / 24.05.2012
Цитата: sadovoya
Может ТС просто думал, что определить длину си-строки можно только по нуль-терминатору. Отсюда столь странный вопрос :)


Вот это уже интереснее. А как ещё её можно определить? :)

326
02 ноября 2013 года
sadovoya
757 / / 19.11.2005
Легко, если пользоваться статическим массивом вместо сырых указателей:

 
Код:
char c_str[] = "C-String";
    const int len_without_0 = sizeof(c_str)/sizeof(char) - 1;
    cout << "The length without null-terminator is " << len_without_0 << endl;
414
02 ноября 2013 года
CassandraDied
763 / / 24.05.2012
Точняк. Совсем забыл об этой фиче.
326
02 ноября 2013 года
sadovoya
757 / / 19.11.2005
Компилятор -- он лапочка, сам посчитает за нас размерность для незаполненных [ ] при инициализации. Моя любимая фишка с массивами :)
414
02 ноября 2013 года
CassandraDied
763 / / 24.05.2012
А передачу такой "строки" в функцию разве все с++ компиляторы одобрят? Включая старые. Кажется, всё равно придётся с поинтером работать на каком-нибудь старье.
326
02 ноября 2013 года
sadovoya
757 / / 19.11.2005
Ни старые, ни новые не передадут размерность в функцию, а только адрес начала массива. Поэтому в функцию надо передавать размерность помимо указателя.
Либо шаблоны параметризировать размерами, либо куча иных решений.
414
02 ноября 2013 года
CassandraDied
763 / / 24.05.2012
Не передадут, но его так же можно получить твоим способом.
ideone.com/EsjX5q
326
02 ноября 2013 года
sadovoya
757 / / 19.11.2005
А вы строку поменяйте (кстати для вашего примера 3 - неверный ответ, должен быть 4). На самом деле в вашей функии sizeof(x) = числу байт адреса (4) Теперь понимаете?
414
02 ноября 2013 года
CassandraDied
763 / / 24.05.2012
Это не мой пример. :)
326
02 ноября 2013 года
sadovoya
757 / / 19.11.2005
Ну вот тут те-же 3 выводится (и так будет всегда, с любой строкой на всех машинах с 4-байтными адресами)
414
02 ноября 2013 года
CassandraDied
763 / / 24.05.2012
What a heck? То есть, для инициализированного массива компилер смог получить длину, а для переданного в функцию затрудняется?
326
02 ноября 2013 года
sadovoya
757 / / 19.11.2005
Статический массив имеет привилегию при инициализации не указывать размерность - компилятор сам способен ее вычислить по перечню в { }. Откуда такой подарок -- не знаю. Типичней случай, когда он за нас нефига не делает. Я бы сказал проще - ф-ции, принимающие массивы трактуют их как указатели. Иначе скрытно надо разменость либо где-то помнить, либо вычислять. Возможны накладные расходы, а С++ в плане эффективности щепетилен.
414
02 ноября 2013 года
CassandraDied
763 / / 24.05.2012
Интересно узнать, какие ещё есть профиты от этой способности вычислять размерность массива. Кроме как упрощённой инициализации. Похоже на костыль.
326
02 ноября 2013 года
sadovoya
757 / / 19.11.2005
Думаю, что упрощенная инициализация -- весь профит. Ну, хоть вручную считать размер не надо.
326
02 ноября 2013 года
sadovoya
757 / / 19.11.2005
Может кому интересно. Некоторые компиляторы, по крайней мере gcc, позволяют такие странности:

 
Код:
void foo(int count){

    sometype Array[count];

    //...
}
Но это -- нестандартное поведение. Стандарт такое запрещает. Стандарт запрещает даже случай, когда прототип такой:

 
Код:
void foo(const int count);
и в foo передаем константный аргумент (const int some= ... ; foo(some)).

Запрет понятен. Для статического массива размер должен быть даже не просто константа, а константа известная на момент компиляции.
Вдруг мы делаем что-то типа такого:

 
Код:
int x;
cin >> x;
const int y = x;
foo(y);
Тогда значение y известно при выполнении программы, а при компиляции просто зарезервировано под него место и запрещено изменение после инициализации. Т.е. на этапе компиляции в foo неизвестно, сколько под массив выделить.

Получается, что нестандартное поведение реализуется на самом деле так:

 
Код:
void foo(int count){
    sometype *Array = new sometype [count];
    //...
    delete [] Array;
}
Или чем-то похожим.

Короче, знайте, что такие штуки непереносимы между компиляторами. Лучше включить в настройках компилятора оповещения об нестандартных конструкциях.
414
02 ноября 2013 года
CassandraDied
763 / / 24.05.2012
Вообще, странно присваивать константной переменной значение другой неконстантной переменной. Информация интересная. И давно gcc начал такое разрешать? Не с 11-го ли стандарта?
326
03 ноября 2013 года
sadovoya
757 / / 19.11.2005
Стандарт C++11 тоже вряд ли такое разрешил. Это все самодеятельность gcc, его "расширения" языка так сказать. Расширениями не только он балуется. Просто в настройках компилятора надо следование стандарту установить, либо не устанавливать. Я теперь всегда ставлю по крайней мере опцию "оповещать" о нестандартности кода.
326
03 ноября 2013 года
sadovoya
757 / / 19.11.2005
Кстати, gcc c оповещением о нестандартности форбидит такой код:

Код:
void foo(const int count) {

    int Array[count];

    //...
}


int main() {
    foo(5);
    return 0;
}
И правильно. Вдруг где-то еще foo(44) или с другой цифирью.

Соображает и с шаблонами на предмет известности констант на момент компиляции:

Код:
#include <iostream>

template<int count>
void foo() {

    int Array[count];

    //...
}


int main() {

    int x;
    std::cin >> x;

    const int c = x;
    foo<c>(); //не скомпилируется !!!

    const int d = 5;
    foo<d>(); //нормально

    return 0;
}

P.S.
Цитата:
Вообще, странно присваивать константной переменной значение другой неконстантной переменной.


CassandraDied, это вы о чем?

326
01 декабря 2013 года
sadovoya
757 / / 19.11.2005
Оказывается стандарт Си разрешил массивы переменной длины (в C99). Может я не прав, и в С++ они тоже появились, а вовсе это не самодеятельность gcc... Одно ясно, что для совместимости со старыми стандартами их не следует использовать. Да и механизм их не очень ясен.
414
01 декабря 2013 года
CassandraDied
763 / / 24.05.2012
Цитата: sadovoya
CassandraDied, это вы о чем?


Я бы никогда не стал инициализировать константу какой-либо переменной. Даже, если она является аргументом функции. Обычно константам присваивается вычисленное на месте значение.

Цитата: sadovoya

Оказывается стандарт Си разрешил массивы переменной длины (в C99). Может я не прав, и в С++ они тоже появились, а вовсе это не самодеятельность gcc... Одно ясно, что для совместимости со старыми стандартами их не следует использовать. Да и механизм их не очень ясен.


Чёткие парни в энтерпрайзе не пользуются массивами. Только контейнеры, только автоматическое высвобождение памяти!

326
02 декабря 2013 года
sadovoya
757 / / 19.11.2005
CassandraDied, в обоих ваших высказываниях не от шарпа ли что? :)
414
02 декабря 2013 года
CassandraDied
763 / / 24.05.2012
К счастью (а может и к сожалению), нет ничего от шарпа. Обычный Qt + C++. В достаточно большом проекте, в котором сейчас участвую, встречал использование массивов очень редко. Только в хардкорных местах, где концентрация WinApi зашкаливает, таких как свой аллокатор памяти или дампер отладочной информации; в общем, где использовать контейнеры было бы просто неудобно.
И я начинаю склоняться к мысли, что в большинстве случаев действительно можно избежать использования массива или динамически выделенной памяти, которая потом будет использоваться, как массив. А если бы ещё и с++1х использовать, с их новой move семантикой и достаточно быстрыми новыми умными указателями, то от использования массивов можно отказаться ещё в большем спектре решаемых задач.
326
02 декабря 2013 года
sadovoya
757 / / 19.11.2005
Ясно, Qt :)
Да можно, конечно. Есть еще Java с уборкой мусора тоже.
Просто C++ тем и хорош, что сочетает высокий уровень и низкий.

Знаете кого-то, кто может ответить? Поделитесь с ним ссылкой.

Ваш ответ

Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог