Подтвердить что ты не робот

Определение размера массива с использованием константы int

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

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;
}
4b9b3361

Ответ 1

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

const int a = 5;

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

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

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

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

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

(Обратите внимание, что это поведение const только в 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 не поддерживает VLA (хотя gcc поддерживает его как расширение даже в C89/C90). Поэтому, если вы используете компилятор, который не поддерживает C99, вы не можете использовать VLA. Например, визуальная студия не полностью поддерживает все функции C99 и C11. Хотя Visual Studio 2015 поддерживает большинство функций C99, VLA не являются одним из них.

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

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

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

От 6.10.8.3 Макросы условных функций

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

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

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

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

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

Ответ 2

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

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

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

Ответ 3

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

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

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 a pre-1999 implementation,
   * or it 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. Я не знаю.