Количество элементов массива в C ++ - PullRequest
20 голосов
/ 30 января 2011

Допустим, у меня есть массив arr. Когда следующее не даст количество элементов массива: sizeof(arr) / sizeof(arr[0])?

Я могу сказать только об одном случае: массив содержит элементы, которые имеют различные производные типы от типа массива.

Прав ли я, и есть ли (я почти уверен, должно быть) другие подобные случаи?

Извините за тривиальный вопрос, я разработчик Java, и я довольно новичок в C ++.

Спасибо!

Ответы [ 9 ]

30 голосов
/ 30 января 2011

Допустим, у меня есть массив обр. когда следующее не даст количество элементов массива: sizeof (обр) / sizeof (обр [0])?

Одна вещь, которую я часто видел, как новые программисты делают это:

void f(Sample *arr)
{
   int count = sizeof(arr)/sizeof(arr[0]); //what would be count? 10?
}

Sample arr[10];
f(arr);

Таким образом, новые программисты думают, что значение count будет равно 10. Но это неправильно.

Даже это не так:

void g(Sample arr[]) //even more deceptive form!
{
   int count = sizeof(arr)/sizeof(arr[0]); //count would not be 10  
}

Это все потому, что как только вы передаете массив любой из этих функций, он становится указатель типа, и поэтому sizeof(arr) даст размер указатель , а не массив!


EDIT:

Ниже приведен элегантный способ передачи массива в функцию, не позволяя ему распадаться на тип указателя:

template<size_t N>
void h(Sample (&arr)[N])
{
    size_t count = N; //N is 10, so would be count!
    //you can even do this now:
    //size_t count = sizeof(arr)/sizeof(arr[0]);  it'll return 10!
}
Sample arr[10];
h(arr); //pass : same as before!
9 голосов
/ 30 января 2011

Массивы в C ++ сильно отличаются от массивов в Java тем, что они полностью неуправляемы. Компилятор или среда выполнения не имеют ни малейшего представления, какой размер у массива.

Информация известна только во время компиляции, если размер определен в объявлении:

char array[256];

В этом случае sizeof (массив) дает правильный размер.

Однако, если вы используете указатель в качестве массива, «массив» будет просто указателем, а sizeof не даст вам никакой информации о фактическом размере массива.

STL предлагает множество шаблонов, которые позволяют иметь массивы, некоторые с информацией о размере, некоторые с переменными размерами, и большинство из них с хорошими средствами доступа и проверки границ.

6 голосов
/ 30 января 2011

Не существует случаев, когда для массива arr значение sizeof(arr) / sizeof(arr[0]) не является количеством элементов по определению массива и sizeof.

На самом деле, это даже прямо упоминается (§5.3.3 / 2):

.... При применении к массиву результатом является общее количество байтов в массиве. Это означает, что размер массива n элементов в n раз превышает размер элемента.

Акцент мой. Разделите на размер элемента, sizeof(arr[0]), чтобы получить n .

4 голосов
/ 30 января 2011

Нет, это все равно приведет к правильному значению, потому что вы должны определить массив как все элементы одного типа или указатели на тип.В любом случае размер массива известен во время компиляции, поэтому sizeof (arr) / sizeof (arr [0]) всегда возвращает количество элементов.

Вот пример того, как правильно использовать это:

int nonDynamicArray[ 4 ];

#define nonDynamicArrayElementCount ( sizeof(nonDynamicArray) / sizeof(nonDynamicArray[ 0 ]) )

Я пойду сюда еще раз, чтобы показать , когда , чтобы использовать это правильно.Вы не будете использовать это очень часто.Это в первую очередь полезно, когда вы хотите определить массив, чтобы вы могли добавлять в него элементы, не меняя при этом много кода.Это конструкция, которая в первую очередь полезна для обслуживания .Канонический пример (когда я все равно об этом думаю ;-) - это создание таблицы команд для некоторой программы, в которую вы намереваетесь добавить больше команд позже.В этом примере для поддержки / улучшения вашей программы все, что вам нужно сделать, это добавить еще одну команду в массив, а затем добавить ее обработчик:

char        *commands[] = {  // <--- note intentional lack of explicit array size
    "open",
    "close",
    "abort",
    "crash"
};

#define kCommandsCount  ( sizeof(commands) / sizeof(commands[ 0 ]) )

void processCommand( char *command ) {
    int i;

    for ( i = 0; i < kCommandsCount; ++i ) {
        // if command == commands[ i ] do something (be sure to compare full string)
    }
}
1 голос
/ 22 июля 2016

Используйте макрос "_countof (array)" от Microsoft. Эта ссылка на Microsoft Developer Network объясняет это и предлагает пример, который демонстрирует разницу между «sizeof (массив)» и макросом «_countof (массив)».

Microsoft и макрос "_countof (array)"

1 голос
/ 30 января 2011

Допустим, у меня есть массив обр. Когда следующее не даст количество элементов массива: sizeof(arr) / sizeof(arr[0])?

В случаях, когда arr на самом деле не массив (а указатель на начальный элемент). Другие ответы объясняют, как это происходит.

Я могу сказать только об одном случае: массив содержит элементы, которые имеют различные производные типы от типа массива.

Этого не может быть (по сути, по той же причине, по которой Java-массивы не очень хорошо работают с генериками). Массив статически типизирован; он резервирует «слоты» памяти, которые рассчитаны для определенного типа (базовый тип).

Извините за тривиальный вопрос, я разработчик Java, и я довольно новичок в C ++.

Массивы C ++ не являются объектами первого класса. Вы можете использовать boost :: array, чтобы заставить их вести себя больше как массивы Java, но имейте в виду, что у вас все еще будет семантика значений, а не ссылочная семантика, как и во всем остальном. (В частности, это означает, что вы не можете на самом деле объявить переменную типа, аналогичную Foo[] в Java, и не заменить массив на другой с другим размером; размер массива является частью типа.) Используйте .size() с этим классом, где вы будете использовать .length в Java. (Он также предоставляет итераторы, которые предоставляют обычный интерфейс для итераторов C ++.)

1 голос
/ 30 января 2011

Прежде всего, вы можете обойти эту проблему, используя std::vector вместо массива. Во-вторых, если вы поместите объекты производного класса в массив суперкласса, вы испытаете нарезку, но хорошая новость заключается в том, что ваша формула будет работать. Полиморфные коллекции в C ++ достигаются с помощью указателей. Здесь есть три основных варианта:

0 голосов
/ 15 июля 2016

_countof (my_array) в MSVC

Я могу сказать только об одном случае: массив содержит элементы, которые имеют различные производные типы от типа массива.

Элементы массива в C ++ являются объектами, а не указателями, поэтому вы не можете иметь объект производного типа в качестве элемента.

И, как упоминалось выше, sizeof (my_array) (также как _countof ()) будет работать только в пределах определения массива.

0 голосов
/ 02 ноября 2015

Я знаю, это старая тема, но как насчет простого решения, такого как цикл while?

int function count(array[]) {

    int i = 0;

    while(array[i] != NULL) {

        i++;

    }

    return i;

}

Я знаю, что это медленнее, чем sizeof (), но это еще один пример подсчета массива.

...