Почему я не могу создать массив, размер которого определяется глобальной переменной?

Почему массив a не инициализируется глобальной переменной size?

#include<stdio.h>

int size = 5;

int main()
{
    int a[size] = {1, 2, 3, 4, 5};
    printf("%d", a[0]);

    return 0;
}

Ошибка компиляции отображается как

объект переменного размера не может быть инициализирован

По моему мнению, массив должен быть инициализирован size.

И какой будет ответ, если я буду настаивать на использовании глобальной переменной (если это возможно)?


person Ashish Yadav    schedule 11.03.2010    source источник
comment
Используйте -std=c99 при компиляции с помощью GCC, чтобы включить массивы переменного размера.   -  person Mikael S    schedule 11.03.2010
comment
Они уже включены - если бы он был в режиме с89, ошибка была бы что-то вроде ISO C90 forbids variable length array 'a'.   -  person Steve Jessop    schedule 11.03.2010


Ответы (7)


In C99, 6.7.8/3:

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

6.6/2:

Константное выражение может оцениваться во время трансляции, а не во время выполнения.

6.6/6:

Целочисленное константное выражение должно иметь целочисленный тип и должно иметь только операнды, являющиеся целочисленными константами, константы перечисления, символьные константы, выражения sizeof, результаты которых являются целочисленными константами, и константы с плавающей запятой, являющиеся непосредственными операндами приведения типов.

6.7.5.2/4:

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

a имеет тип массива переменной длины, потому что size не является целочисленным константным выражением. Таким образом, он не может иметь список инициализаторов.

В C90 нет VLA, поэтому код незаконен по этой причине.

В C++ также нет VLA, но вы можете сделать size const int. Это потому, что в C++ вы можете использовать const int переменных в ICE. В Си нельзя.

Предположительно, вы не предполагали, что a имеет переменную длину, поэтому вам нужно:

#define size 5

Если вы действительно хотели, чтобы a имела переменную длину, я полагаю, вы могли бы сделать что-то вроде этого:

int a[size];
int initlen = size;
if (initlen > 5) initlen = 5;
memcpy(a, (int[]){1,2,3,4,5}, initlen*sizeof(int));

Или, может быть:

int a[size];
for (int i = 0; i < size && i < 5; ++i) {
    a[i] = i+1;
}

Однако трудно сказать, что здесь «должно» произойти в случае, когда size != 5. На самом деле не имеет смысла указывать начальное значение фиксированного размера для массива переменной длины.

person Steve Jessop    schedule 11.03.2010

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

int a[] = {1,2,3,4,5};

Затем вы даже можете позволить компилятору сообщить вам размер, получив общий размер массива в байтах sizeof(a) и разделив его на размер одного элемента sizeof(a[0]):

int size = sizeof(a) / sizeof(a[0]);
person indiv    schedule 11.03.2010
comment
Что, если бы я также хотел, например, инициализировать все нулями? int myArray [numRows][numCols] = {{0}}; Есть ли способ пропустить переменные numRows и numCols в левой части, но не записывать все нули в правой? - person VeraKozya; 17.02.2018
comment
Разве не было бы менее двусмысленно называть количество фактических элементов в массиве как length, а количество байтов, составляющих массив на уровне памяти, как size? Преимущество этого заключается в большей совместимости со стандартным значением, используемым оператором sizeof, который просто вычисляет и возвращает количество необработанных байтов массива. - person programmersn; 10.07.2018

Компилятор не может предположить, что значение size по-прежнему равно 5 к тому времени, когда функция main() получает управление. Если вам нужна настоящая константа в проекте C в старом стиле, используйте:

#define size 5
person Seva Alekseyev    schedule 11.03.2010
comment
Хорошая точка зрения. Решением может быть также использование новомодных const int size = 5 - person Fusion; 19.07.2019

size - это переменная, и C не позволяет вам объявлять (редактировать: C99 позволяет вам объявлять их, просто не инициализируя их, как вы делаете) массивы с переменным размером, подобным этому. Если вы хотите создать массив, размер которого является переменной, используйте malloc или сделать размер постоянным.

person IVlad    schedule 11.03.2010

Похоже, ваш компилятор не совместим с C99... кстати говоря, какой компилятор вы используете? Если это gcc, вам нужно передать переключатель '-std=c99'.... если вы используете компилятор до C99, это утверждение недопустимо, если это так, сделайте следующее:

int main() { 
   int a[5]={1,2,3,4,5}; 
   printf("%d",a[0]); 
   return 0; 
}

В стандартных компиляторах до C99 вместо переменной используйте константу.

Изменить: вы можете узнать больше о стандарте C99 здесь... и здесь ....

person t0mm13b    schedule 11.03.2010
comment
В C99 вы можете объявить массив переменного размера, но вы не можете инициализировать его таким образом. Проблема именно в том, что говорится в сообщении об ошибке. - person Jeffrey L Whitledge; 11.03.2010
comment
В этом случае проблема не в поддержке VLA или нет, а в предоставлении инициализатора vla, что недопустимо. - person nos; 11.03.2010
comment
Это очень интересно, я понятия не имел, что вы можете сделать это. Однако сообщение немного вводит в заблуждение, поскольку в нем не упоминается, что проблема заключается в инициализации, а не в объявлении. В любом случае, +1 за то, что научил меня чему-то новому. - person IVlad; 11.03.2010
comment
Компилятор соответствует (6.7.8/3). - person Steve Jessop; 11.03.2010

Компилятору необходимо знать размер массива при его объявлении. Потому что размер массива не меняется после его объявления. Если вы поместите размер массива в переменную, вы можете себе представить, что значение этой переменной изменится при выполнении программы. В этом случае компилятор будет вынужден выделить этому массиву дополнительную память. В данном случае это невозможно, поскольку массив представляет собой статическую структуру данных, размещенную в стеке. Я надеюсь, что это поможет.

person Abderrahmen    schedule 04.09.2016

#include<stdio.h> 

/* int size=5; */
#define size 5 /* use this instead*/
/*OR*/
int a[size]={1,2,3,4,5};  /* this*/

int main() 
{ 
    int a[size]={1,2,3,4,5}; 
    printf("%d",a[0]); 
    return 0; 
} 

int size означает, что size является переменной, а C не допускает массивов переменныхsize.

Я использую VS2008, где использую

const int size=5;  

позволяет

int a[size]={1,2,3,4,5}; 
person Pratik Deoghare    schedule 11.03.2010
comment
почему я не могу использовать глобальные переменные? - person Ashish Yadav; 11.03.2010
comment
@ashish: потому что глобальные переменные по-прежнему являются переменными (подсказка в названии). Предположим, что кто-то присвоил значение 1 size где-то перед вашим кодом для определения a. Тогда вы попытаетесь инициализировать массив размера 1 с помощью списка инициализаторов размера 5. Вместо того, чтобы пытаться разобраться в этом беспорядке, стандарт запрещает это. - person Steve Jessop; 11.03.2010
comment
size является переменной, а C не допускает массивов переменного размера. мы должны добавить к вашему комментарию, что: если мы инициализируем переменную, C позволяет определить массив с использованием этой переменной. Например. размер целого числа = 5; интервал [размер]; в полном порядке. - person Pedram; 22.02.2017