Просчет размера массива внутри функции - PullRequest
0 голосов
/ 10 февраля 2011

Следующая программа на C:

int doStuff(int afm[]);

int main(){
    int afm1[9] = {1,2,3,4,5,6,7,8,9}; //size=9

    int afmLength = sizeof(afm1)/sizeof(int);
    printf("main: Length Of Array=%d\n", afmLength);  //9 OK

    int k = doStuff(afm1);

    system("PAUSE");
    return 0;   
}

int doStuff(int afm[]){
    int afmLength = sizeof(afm)/sizeof(int);    
    printf("doStuff: Length Of Array=%d\n", afmLength);  //1 WRONG

    return 1;
}

производит следующий вывод:

main: Length Of Array=9
doStuff: Length Of Array=1

Почему размер массива правильно рассчитан в main, но неверен внутри функции?

Ответы [ 3 ]

7 голосов
/ 10 февраля 2011

Потому что в main у вас есть массив, а в функции у вас есть указатель на этот массив.

int doStuff(int afm[])

эквивалентно

int doStuff(int *afm)
2 голосов
/ 10 февраля 2011

Добавляя к ответу Дэвида Хеффернана (который является правильным), у вас должен быть другой параметр, который будет длиной массива, передаваемой в ваш метод doStuff.

0 голосов
/ 10 февраля 2011

Из стандарта языка C (черновик n1256 ):

6.3.2.1 L-значения, массивы и обозначения функций
...
3 За исключением случаев, когда это операнд оператора sizeof или унарный оператор & или строковый литерал, используемый для инициализации массива, выражение, которое имеет тип ‘‘ array of type ’’ преобразуется в выражение с указателем типа 101 ‘на тип ’, которое указывает на начальный элемент объект массива и не является lvalue. Если объект массива имеет класс хранения регистров, поведение не определено.

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

Когда вы вызываете doStuff(afm1);, выражение afm1 неявно преобразуется из типа "массив из 9 элементов int" в "указатель на int", и значение выражения такое же, как &afm1[0] , Так что doStuff получает значение указателя, а не массив.

В контексте объявления параметров функции T a[] и T a[N] оба интерпретируются как T *a:

6.7.5.3 Объявление функций (включая прототипы)
...
7 Объявление параметра в виде массива type ’должно быть скорректировано с учетом‘ ‘квалифицированного указателя на type ’’, где квалификаторы типа (если таковые имеются) указаны в [ и ] вывод типа массива. Если ключевое слово static также появляется в пределах [ и ] вывод типа массива, затем для каждого вызова функции значение соответствующего фактический аргумент должен обеспечивать доступ к первому элементу массива с как минимум элементы, как указано в выражении размера.

Поскольку doStuff получает значение указателя , а не массив, трюк sizeof не работает. В общем, вы должны явно указать функции, какой размер массива вы ей передаете; вы не можете определить это по самому значению указателя.

Итак, когда вы звоните doStuff из main, вам нужно будет сделать что-то вроде

doStuff(afm1, sizeof afm1/sizeof *afm1);
...
int doStuff(int *afm, size_t afmsize)
{
  ...
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...