2016-01-25 5 views
11

Когда я пытаюсь запустить это, это дает мне ошибку, говоря, что значение в переменной a не является константой. Это не имеет смысла для меня, потому что я явно сделал переменную a константой. Является ли размер массива более постоянным? Значение, только #define a 5, или инициализируя его как int arr[5] или используя malloc? Что случилось с тем, что я сделал?Определение размера массива с помощью константы int

int main{ 

    const int a = 5; 
    int i; 
    int arr [a]; 

    for (i = 0; i < 5; i++) { 
     arr[i] = i * 2; 
    } 

    printf("%d", arr[1]); 
    return 0; 
} 
+1

Ваше утверждение о том, что доступные альтернативы в основном или '# define' или' malloc' верное - выберите один из этих двух вариантов, чтобы исправить это. Ответ, сделанный l3x, хорошо объясняет, почему. – GrandOpener

ответ

9

В C, const следует читать как только для чтения. Он не определяет время компиляции.

const int a = 5; 

Здесь a, является не постоянным выражением в соответствии с требованиями C standard:

6.7.9 Инициализация
4 Все выражения в инициализатора для объекта, который имеет статический или нить длительность хранения должна быть постоянной выражениями или строковыми литералами.

Таким образом, ошибка указывает, что вы используете компилятор C89/C90. Вы можете прочитать ввод от пользователя для a и объявить variable length array, который является C99-функцией, которая имеет автоматическую продолжительность хранения.

Использование #define - это еще один способ. Но это просто текстовая замена и определяет массив с автоматическим временем хранения. Это то же самое, что и определение int arr[5];.

Если вы хотите выделить память в динамическом хранилище (обычно называемое «кучей»), вы должны использовать malloc() семейные функции, которые будут иметь жизненный цикл без выполнения программы, пока вы не назовете на нее free().

(Обратите внимание, что это поведение const только в C. C++ отличается этим и будет работать так, как вы ожидали).


Если я скомпилировать код в C89, он терпит неудачу с:

#include <stdio.h> 

int main(){ 

    const int a = 5; 
    int i; 
    int arr [a]; 

    for (i = 0; i < 5; i++) { 
     arr[i] = i * 2; 
    } 

    printf("%d", arr[1]); 
    return 0; 
} 

$ gcc -Wall -Wextra -std=c89 -pedantic-errors test.c 
test.c: In function âmainâ: 
test.c:7:4: error: ISO C90 forbids variable length array âarrâ [-Wvla] 
    int arr [a]; 
    ^

потому, что C89 не поддерживает Власа (Хотя GCC поддерживает как an extension даже в C89/C90). Поэтому, если вы используете компилятор, который не поддерживает C99, вы не можете использовать VLA. Например, визуальная студия не полностью поддерживает все функции C99 и C11. Хотя, Visual studio 2015 support most C99 features, VLA не являются одним из них.

Но тот же код компилируется в C99 и C11 без каких-либо проблем:

$ gcc -Wall -Wextra -std=c99 -pedantic-errors t.c 
$ gcc -Wall -Wextra -std=c11 -pedantic-errors t.c 

Это потому, что были добавлены массивы переменной длины (Vlas) в C99. Обратите внимание, что VLA стали дополнительными в стандарте C11. Таким образом, реализация не может поддерживать VLA в C11. Вам необходимо протестировать против __STDC_NO_VLA__, чтобы проверить, не поддерживает ли VLA вашу реализацию.

От 6.10.8.3 Conditional feature macros

__STDC_NO_VLA__
Целого числа константы 1, предназначено для указания того, что реализация не поддерживает массивы переменной длины или переменно модифицированных типов.

Я лично не использую VLA, так как отказ распределения не может быть портативно найден, если размер массива достаточно велик. Например.

size_t size = 8*1024; 
int arr[size]; 

В приведенном выше фрагменте, если arr распределение не удалось, вы не будете знать его до времени выполнения. Что такое «достаточно маленький» размер, для которого распределение памяти зависит от платформы. Таким образом, на одной машине распределение 1 МБ может преуспеть, а другое - потерпеть неудачу, а худшая часть состоит в том, что не удается поймать этот сбой.

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

+0

Или если вы действительно хотите, чтобы размер массива был жестко закодирован, используйте директиву '# define', называемую' arraySize', или что-то в этом роде. – rlam12

+0

Я не понимаю, почему вы только передавали ссылку на VLA. Разве это не то, что пытается сделать ОП? Если она использует версию MSVC даже 2015 года, она не поддерживает VLA. Она даже упомянула о ваших методах в вопросе, так ясно понимает их. –

+0

@WeatherVane Вы правы, это требует немного большего объяснения. Я сделал обновление. Благодарю. –

0

A const -значенная переменная - это не то же самое, что и постоянное выражение ; постоянное выражение имеет свое значение, известное во время компиляции, тогда как переменная с условием const (обычно) не имеет значения (даже если она выглядит так, как должна).

Обратите внимание, что в C99 и более поздних версиях можно объявлять массивы переменной длины, где размер массива неизвестен до времени выполнения. Вы должны использовать C99 или более поздней версии компилятора, и при условии, что эта функция была необязательной в стандарте 2011 года, вы должны проверить функцию макросъемки, чтобы увидеть, если Власа доступны:

static const int a = 10; // a is not a constant expression 

#if defined(__STDC__) && defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L && !defined(__STDC_NO_VLA__) 
/** 
* VLAs are available in this environment 
*/ 
#define USE_VLA 1 
#endif 

#ifdef USE_VLA 
    int arr[a]; 
#else 
    /** 
    * VLAs are not available, either because it's a pre-1999 implementation, 
    * or it's a post-2011 implementation that does not support optional 
    * VLAs. We'll have to use dynamic memory allocation here, meaning we'll 
    * also need an explicit free call when we're done with arr 
    */ 
    int *arr = malloc(sizeof *arr * a); 
#endif 
... 
    do_something_interesting_with(a); 
... 
#ifndef USE_VLA 
    free(a); 
#endif 

По крайней мере, вплоть до самого последнего времени , Компилятор Microsoft C не поддерживал VLA. Однако они добавили некоторые функции C99, такие как смешанные декларации и код, поэтому, возможно, последняя версия поддерживает VLA. Я не знаю.

1

Возможно, используйте перечисление, чтобы определить значение a.

enum { a = 5 }; 
int arr [a]; 

Возможно, это не намерение перечисления, но члены перечислений являются ближе всего к константе в C. В отличие от общей практики определения все, используя #define, видимость a ограничивается объем и здесь это то же самое, что и arr.

+0

Удивительная идея !!! – outoftime

Смежные вопросы