Как sizeof знает размер массива?

У меня есть следующие коды:

main() {
    int array[5] = {3,6,9,-8,1};
    printf("the size of the array is %d\n", sizeof(array));
    printf("the address of array is %p\n", array);
    printf("the address of array is %p\n", &array);
    int * x = array;
    printf("the address of x is %p\n", x);
    printf("the size of x is %d\n", sizeof(x));
}

Выходной сигнал

the size of the array is 20
the address of array is 0x7fff02309560
the address of array is 0x7fff02309560
the address of x is 0x7fff02309560
the size of x is 8

Я знаю, что переменная array будет отображаться как указатель на первый элемент массива, поэтому я понимаю, что размер x равен 8. Но я не знаю, почему размер массива равен 20. Разве это не должно быть 8 (в 64-разрядной машине)?

Кроме того, как программа знает, что ей 20? Насколько я знаю в C, он не сохраняет количество элементов. Откуда sizeof(array) и sizeof(x) разные? Я отслеживал несколько сообщений, относящихся к распаду массива, но не знаю об этой проблеме.

Ответы

Ответ 1

В большинстве случаев имя массива распадается на указатель на первый элемент массива. Однако есть пара исключений из этого правила. Двумя наиболее важными являются когда имя массива используется как операнд оператора sizeof или оператора address-of (&). В этих случаях имя массива остается идентификатором для массива в целом.

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

Когда вы берете адрес массива, вы получаете одно и то же значение (т.е. тот же адрес), как если бы вы просто использовали имя массива без адреса. Тип отличается, хотя, когда вы явно принимаете адрес, то, что вы получаете, является указателем типа "указатель на массив из N элементов типа T". Это означает (например), что в то время как array+1 указывает на второй элемент массива, &array+1 указывает на другой массив, расположенный за конец всего массива.

Предполагая массив из по меньшей мере двух элементов, *(array+1) будет ссылаться на второй элемент массива. Независимо от размера массива, &array+1 выдаст адрес за конец массива, поэтому попытка разыменования этого адреса дает поведение undefined.

В вашем случае, учитывая, что размер массива равен 20, а размер одного элемента массива равен 4, если array был, скажем, 0x1000, то array+1 будет 0x1004 и &array+1 будет 0x1014 (0x14 = 20).

Ответ 2

Ваш массив имеет статическую длину, поэтому его можно определить во время компиляции. Ваш компилятор знает sizeof(int) = 4 и длину вашего статического массива [5]. 4 * 5 = 20

Изменить: ваши компиляторы int, вероятно, 32-разрядные, но адресация 64-разрядные. Поэтому sizeof(pointer) возвращает 8.

Ответ 3

Обратите внимание, что sizeof является не библиотечной функцией. sizeof

унарный оператор времени компиляции [...], который может быть использован для вычисления размер любого объекта
K & R

Итак, sizeof не знает, насколько велик массив, компилятор знает, насколько велик массив, и по определению

когда применяется к массиву, результатом является общее количество байтов в массиве.
K & R

Ответ 4

Указатель и массив - это два разных типа данных.

Массив может содержать элементы аналогичного типа данных. Память для массива смежна.

Указатель используется для указания на допустимую ячейку памяти.

sizeof(type) дает вам количество байтов передаваемого вами типа.

Теперь, если вы передаете массив, компилятор знает, что это массив и количество элементов в нем, и он просто умножает многие элементы с соответствующим значением размера типа данных.

В этом случае:

5*4 = 20

Опять sizeof(int) или sizeof(pointer) зависит от платформы. В этом случае вы видите sizeof(pointer) как 8.

Ответ 5

Нет, массивы не распадаются как операнды оператора sizeof. Это одно из немногих мест, где массивы не распадаются. Если int - 4 байта на вашем компьютере, то общее количество байтов массива должно быть 20 (4 * 5). Нам даже не нужен объект для проверки этого.

sizeof(int[5]) // 20
sizeof(int*)   // 8 on a 64-bit machine

Ответ 6

C11: 6.5.3.4 (p2)

Оператор sizeof дает размер (в байтах) своего операнда, который может быть выражение или имя в скобках типа. Размер определяется по типу операнд. [...]

В объявлении

int array[5]  

тип array - это массив из 5 int s. Компилятор определит размер array этого типа.

Ответ 7

Попробуйте это

int x = sizeof(array)/sizeof(int);
printf("the size of the array is %d\n", x);