уточнение размера массива - PullRequest
8 голосов
/ 09 мая 2011

Я готовлюсь к завтрашнему выпускному экзамену в Си, и у меня есть вопрос относительно оператора sizeof.

Допустим, размер int составляет 32 бит, а указатель - 64 бит.

Если была функция:

int
foo (int zap[])
{
    int a = sizeof(zap);
    return a;
}

Поскольку zap является указателем, foo вернет 8, поскольку именно столько байтов необходимо для хранения этого конкретного указателя. Однако со следующим кодом:

int zip[] = { 0, 1, 2, 3, 4, 5 };
int i = sizeof(zip);

i будет 6 * sizeof(int) = 6 * 4 = 24

Почему sizeof(zip) возвращает количество элементов, умноженное на размер каждого элемента, тогда как sizeof(zap) возвращает размер указателя? Неужели размер zap не указан, а zip - нет? Компилятор знает , что zip является 6 элементами, но не знает, насколько большим может быть zap.

Ответы [ 6 ]

8 голосов
/ 09 мая 2011

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

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

int bar[] = {1,2,3,4};
foo(bar);

массив преобразуется в указатель на первый элемент, и это то, что получает функция.

Однако это правило преобразования импликов применяется не всегда. Например, как вы обнаружили, оператор sizeof работает с массивом, и даже оператор & (address-of) работает с исходным массивом (т.е. sizeof(*&bar) == 4*sizeof(int)).

Функция в C не может получить массив в качестве параметра, она может получить только указатель на первый элемент или указатель на массив ... или вы должны заключить массив в структуру.

Даже если вы поместите число в скобках в объявлении функции ...

void foo(int x[4])
{
    ...
}

это число полностью игнорируется компилятором ... это объявление для компилятора полностью эквивалентно

void foo(int *x)
{
    ...
}

и, например, даже вызов его при передаче массива с другим размером не вызовет никакой ошибки ...

int tooshort[] = {1,2,3};
foo(tooshort);  /* Legal, even if probably wrong */

(на самом деле компилятор МОЖЕТ выдавать предупреждение, но код является совершенно допустимым C и должен приниматься, если компилятор следует стандарту)

Если вы считаете, что это правило для массивов в аргументах функции странное, тогда я согласен, но именно так определяется язык Си.

2 голосов
/ 09 мая 2011

zip - это блок памяти 6 * sizeof(int), поэтому он имеет размер 24 (в вашей архитектуре).zap (это также может быть записано как int *zap в объявлении вашей функции), однако может указывать на любой адрес памяти, и компилятор не может узнать, сколько места было выделено, начиная с этого (или даже содержащего этот) адрес.

2 голосов
/ 09 мая 2011

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

int
foo (int zap[])

полностью эквивалентно

int
foo (int *zap)

Компилятор понятия не имеет, насколько большим может быть zap (поэтому он оставляет задачу выяснить это для программиста).

0 голосов
/ 09 мая 2011

В некоторых ситуациях массивы распадаются на указатели. Вызов функций - один из них.

0 голосов
/ 09 мая 2011

Размер zip известен во время компиляции, а размер zap - нет.Вот почему вы получаете размер указателя на sizeof(zap) и размер массива на sizeof(zip).

0 голосов
/ 09 мая 2011

, потому что он был статически инициализирован с 6 элементами.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...