Почему sizeof (param_array) - размер указателя?

Я хочу получить длину массива, скажем int array[] = {1, 2, 3, 4}. Я использовал sizeof для этого.

int length(int array[])
{
     return sizeof(array) / sizeof(int);
}

int main()
{
    int array[] = {1, 2, 3, 4};
    printf("%d\n", length(array)); // print 1
    printf("%d\n", sizeof(array) / sizeof(int)); // print 4
}

Итак, почему функция sizeof(array) in length возвращает размер указателя array? Но в функции main он работает.

И как мне изменить функцию length, чтобы получить длину массива?

Ответ 1

В специальном правиле C указано, что для параметров функции типы массивов настраиваются на типы указателей. Это означает:

int length(int array[]);

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

int length(int *array);

Итак, когда вы вычисляете sizeof массив, на котором вы фактически вычисляете размер указателя.

(C99, 6.7.5.3p7) "Объявление параметра как" массив типа "должно быть отрегулировано на" квалифицированный указатель на тип ", где квалификаторы типа         (если они есть) - это те, которые указаны в [и] вывода типа массива."

Ответ 2

Массив распадается на указатель, когда вы передаете его в функцию.

Ответ 3

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

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

template <size_t _Size> inline int length(int(& array)[_Size])
{
    //return sizeof(array) / sizeof(int);
    return _Size;
};

int array[] = {1, 2, 3, 4};
printf("%d\n", length(array)); // print 4

С вашим массивом длины 4 это скомпилируется как метод, который принимает массив длиной 4 и возвращает статическую 4. Это также имеет то преимущество, что если вы попытаетесь передать что-то, что не является массивом, компилятор выдаст ошибку, а метод #define - нет.

int* foo = array;
printf("%d\n", length(foo)); 
    // error C2784: 'int length(int (&)[_Size])' : could not deduce template
    //     argument for 'int (&)[_Size]' from 'int *'
    // test.cpp(56) : see declaration of 'length'

Ответ 4

В основной программе компилятор знает длину массива. В подпрограмме это не так. В частности, в подпрограмме параметр типа int[] идентичен параметру типа int *. С другой стороны, в основной программе array имеет тип int[4]. (Вы можете проверить это, пытаясь назначить другое значение array в стороне main. Компилятор будет жаловаться.)

Ответ 5

C не хранит метаданные времени выполнения о размере массива с переменной. Вам придется где-то хранить это.

Переменная типа int [] в контексте длины вашего метода - это всего лишь указатель на блок памяти. Поэтому размер такой же, как размер любого другого указателя на вашей системе.

Когда sizeof имеет доступ к массиву во время компиляции (как и в вашей основной функции), он вместо этого возвращает количество байтов, занятых массивом.

Ответ 6

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

int length(int n, int (* array)[n])
{
     return sizeof(*array) / sizeof(int);
}

int main()
{
    int array[] = {1, 2, 3, 4};
    printf("%d\n", length(4, &array)); // print 1
    printf("%d\n", sizeof(array) / sizeof(int)); // print 4
}

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

Ответ 7

Потому что переменная массив внутри длины не такая же, как и внешняя. Вы должны сохранить sizeof (array)/sizeof (int) в основной функции.

Ответ 8

Чтобы изменить код, чтобы length мог получить длину массива, превратите его в макрос:

#define length(x) (sizeof(x)/sizeof(*x))

В вашем примере кода это будет вести себя так, как вы ожидаете.

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