Объявление переменной в прототипе функции и в блочном коде: разница? - PullRequest
0 голосов
/ 07 января 2019

Почему int array[] вызывает ошибку компиляции в основном, но не в прототипе функции? Должно ли это означать, что лучше всегда писать int * array в прототипе функции?

void myfoo (int array[]) { // No compilation error
;}

void myfoo1 (int *array1) { // No compilation error
;}

int main() {
    int array[]; // Compilation error
    int* array1; // No compilation error
}

Ответы [ 3 ]

0 голосов
/ 07 января 2019
void myfoo (int array[]) { // No compilation error
;}

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

void myfoo1 (int *array1) { // No compilation error
;}

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

int main() {
    int array[]; // Compilation error
    int* array1; // No compilation error
}

int array[];

Это определение массива. Но компилятор не может определить размер массива. Так что он не знает, сколько памяти будет выделено. Поэтому вы должны указать либо размер, либо инициализировать его некоторыми значениями, как показано ниже.

int array[3];

или

int array[] = {1,2,1};

.

int* array1;

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

0 голосов
/ 07 января 2019

По сути, причина, по которой объявлению массива внутри блока для main нужен размер, а объявлению массива в параметре функции - нет, заключается в том, что объявление в main является , определяющим массив, тогда как параметр функции просто получает массив, определяемый чем-то другим.

Таким образом, определение в main нуждается в размере, поскольку оно должно зарезервировать хранилище для массива.

Параметр функции просто получает массив, поэтому ему нужно только знать, где начинается массив. Не нужно знать размер. (То есть компилятору не нужно знать размер, чтобы скомпилировать код. Функция может нуждаться в том, чтобы знать размер, чтобы выполнить свое предназначение, но это дело программиста, а не компилятора.)

Из-за правил C, массивы никогда не могут быть переданы в качестве аргументов функции. Всякий раз, когда массив задается в качестве параметра функции, компилятор автоматически преобразует его в указатель на свой первый элемент. Точно так же параметр функции может быть указателем, но не может быть массивом. Когда вы объявляете параметр функции как массив, компилятор автоматически настраивает его для объявления указателя. Поэтому объявление функции void myfoo(int array[]) автоматически настраивается на void myfoo(int *array).

Конкретное правило, требующее, чтобы объявление в main имело размер: C 2018 6.7 7:

Если идентификатор объекта объявлен без привязки, тип объекта должен быть завершен к концу его декларатора или к концу его инициатора-декларатора, если у него есть инициализатор;…

0 голосов
/ 07 января 2019

В вашем коде внутри функции запись int array[]; для определения массива является семантической ошибкой.

В этом случае array - это переменная без привязки, ( "область видимости блока идентификатор объекта, объявленного без спецификатора класса хранения extern ") и согласно спецификации:

Если идентификатор объекта объявлен без привязки, тип объекта должен быть завершить к концу своего объявления, [....]

Пустой [] (с пробелом или без пробелов) не создает допустимой конструкции для определения массива, так как размер массива остается неизвестным (обратите внимание на отсутствие явного списка в скобках) инициализатора тоже). Таким образом, ваш компилятор жалуется, так как тип не завершен, и он не имеет представления об общем объеме памяти, который будет зарезервирован для этой переменной массива.

С другой стороны, для параметров функции параметр типа массива фактически уменьшается до указателя на тип, поэтому указание размера массива не является обязательным. Цитирование главы §6.7.6.3

Объявление параметра в виде «массива типа» должно быть скорректировано для «квалифицированного указателя на». type ’’, где квалификаторы типа (если таковые имеются) указаны в [и] вывод типа массива. [...]

и

Если декларатор функции не является частью определения этой функции, параметры могут иметь неполный тип и может использовать нотацию [*] в своих последовательностях спецификаторов объявления указать типы массивов переменной длины.

Итак, в основном, заявление

 void myfoo (int array[])

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

void myfoo (int *array)

так, это принимается компилятором.

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