C/C++

Объясните мне разное поведение sizeof для статической константы и динамического массива. C.

Чего я хотел?
Проверить количество элементов массива.

Код:
 #include  
#include

int main()
{
const char text[] = "123456";
const int numbers [] = {1, 2, 3, 4, 5, 6};

printf("%lu\n", sizeof(text) / sizeof(*text));
printf("%lu\n", sizeof(numbers) / sizeof(*numbers));

char * str;
int * nums;

str = (char*) malloc(7 * sizeof(char));
nums = (int*) malloc(6 * sizeof(int));

for(int x = 0; x < 6; x++)
{
str[x] = x + 1 + '0';
nums[x] = x + 1;
}
str[6] = '\0';

printf("%lu\n", sizeof(str) / sizeof(*str));
printf("%lu\n", sizeof(nums) / sizeof(*nums));

free(nums);
free(str);

return 0;
}

Консоль:
 7 
6
8
2

Почему-то результаты проверки размера массивов совершенно отличаются.
Для строки я добавли 7 элементов, думая, что последний резервируется для строкового терминатора, а вышло, что 8 элементов зарезервировано.
А почему показывает только 2 элемента для массива чисел -- воообще не понятно.
Олег Лосев
Олег Лосев
9 833
 printf("%lu\n", sizeof(text) / sizeof(*text));  
получаем 7 т.к. 6 букв в строке + терминирующий 0
 printf("%lu\n", sizeof(numbers) / sizeof(*numbers));  
получаем 6 т.к. это массив из 6 элементов
Случаи 3-4
 sizeof( str )
sizeof( nums )
оба sizeof просто вернут размер указателя - 8 байт в твоем случае.
т.к. размер char 1 байт
 printf("%lu\n", sizeof(str) / sizeof(*str));  
это 8 / 1 = 8, а размер int у тебя - 4 байта, поэтому
 printf("%lu\n", sizeof(nums) / sizeof(*nums)) 
это 8 / 4 = 2
Сергей Баймурзин
Сергей Баймурзин
38 458
Лучший ответ
Олег Лосев А как проверять количество элементов, минуя указатель в динамических массивах?
Статический массив внутри области видимости, где он был обьявлен, является совокупностью составляющих его элементов, как структура. Поэтому его размер будет определяться как сумма размеров всех его элементов. Тем не менее он легко преобразуется в указатель, поэтому при передаче в функцию, требующую указатель - будет передан адрес первого элемента этого массива. Размер при этом не передается.
Что до динамических массивов - то та же самая аналогия. Массив как структура создается за границами функции мейн операционной системой, там размер известен. Но мы получаем только адрес первого элемента при помощи malloc или new - следовательно размер утрачивается.
Кстати параметры функции не могут быть массивом, поэтому даже параметр написанный как void foo (int arr[100]); на деле является (int* arr). Разница только для двумерного. Там например int arr[][100] преобразуется в указатель на функцию int(*)[100] который ведет себя как двумерный указатель, но принимает одномерный массив. И умеет первое разыменовывание индексировать по этому размеру. Второй размер (число строк) правда нужно все равно передавать отдельно.
Виталик Жужнев
Виталик Жужнев
51 416