Возможно ли создание массива с переменным количеством элементов?

Всякий раз, когда мне нужно создать массив с несколькими элементами, неизвестными до момента выполнения, я делаю это.

int n, i;
printf("Number of elements: ");
scanf("%d", &n);
int myArray[n];
for(i = 0; i < n; i++)
    myArray[i] = 0;

Однако 3 человека со степенью доктора компьютерных наук сказали мне не делать этого, потому что «это не гарантирует работу на каждом компиляторе», и что количество элементов в массиве должно быть известно во время компиляции. Поэтому они делают это так.

int myArray[1000];
int n, i;
printf("Number of elements: ");
scanf("%d, &n);
//we must stop at the n element
for(i = 0; i < n; i++)
    myArray[i] = 0;

Какой из них я должен использовать? Когда это не гарантирует работу? Это просто пустая трата памяти или необходимость поддерживать наследие?


person Community    schedule 29.07.2016    source источник
comment
Используйте динамическое выделение памяти, если вы хотите реализовать динамические массивы в C.   -  person clarasoft-it    schedule 29.07.2016
comment
Ни один. Используйте что-то вроде int * myArray = malloc( n * sizeof *myArray); и выполните очистку позже, когда закончите.   -  person WhozCraig    schedule 29.07.2016
comment
Он полностью соответствует версии стандарта C99. Это называется массивом переменной длины (VLA). По какой-то неизвестной причине комитет сделал VLA необязательными в текущей версии (C11) — вопреки установившейся практике обратной совместимости любой ценой. Я бы все же рекомендовал его использовать. Его поддерживает современный настольный компилятор (например, gcc и clang). Не используйте устаревшие компиляторы, такие как MSVC. У них есть и другие проблемы с современным C. Иногда приходится делать надрез. WQe также больше не использует конные экипажи. Или электронная почта Морзе. Ваши кандидаты наук должны двигаться дальше   -  person too honest for this site    schedule 29.07.2016
comment
@clarasoft-it: VLA - это не динамически выделяемый массив, а обычная автоматическая переменная.   -  person too honest for this site    schedule 29.07.2016
comment
На всякий случай мой комментарий неясен: используйте VLA, но убедитесь, что они не переполнят стек (как и для любой другой автоматической переменной!). Используйте современные компиляторы, никакого устаревшего хлама от продавцов, которые продают их за какие-то 1к баксов/евро/и т.д. не выходя вперед.   -  person too honest for this site    schedule 29.07.2016


Ответы (2)


"не гарантируется, что он будет работать на каждом компиляторе"

Да, в принципе правильно.

Первый подход, VLA, массив переменной длины, был частью C99 стандарта. Однако,

  • в C11 это стало необязательным. Вам лучше не полагаться на эту функцию.
  • C89 не имел этого в качестве порта стандарта. Однако для их поддержки существовали gcc расширения.

Цитирование C11, глава §6.7.6.2/p5

[....] Если размер представляет собой целочисленное константное выражение, а тип элемента имеет известный постоянный размер, тип массива не является типом массива переменной длины; в противном случае тип массива является типом массива переменной длины. (Массивы переменной длины — это условная функция, которую реализации не обязаны поддерживать; см. 6.10.8.3.)

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

Все вместе, чтобы ответить на вопрос

Возможно ли создание массива с переменным количеством элементов?

Это возможно, но только с поддержкой VLA. Без этого вам придется в лучшем случае насыщаться функциями указателя и выделения памяти.

person Sourav Ghosh    schedule 29.07.2016
comment
Привет Сурав! Я категорически не согласен с вашим выводом не использовать VLA. Тот факт, что люди все еще используют конные повозки, не означает, что на всех автомагистралях должна быть разрешена скорость 20 км/ч. Существует достаточно современных компиляторов, поддерживающих C99, то есть VLA. Компиляторы, которые не поддерживают C99/полный C11, скорее всего, не поддерживают и другие функции в современном C. C, кажется, единственный язык, привязанный к версии 27-летней давности только потому, что люди отказываются изучать что-то новое и просят современные функции от своих. продавцы. - person too honest for this site; 29.07.2016
comment
@ Олаф Сэр, спасибо за комментарии. Во-первых, я не против VLA, я просто попытался предложить их как альтернативу, как видите. Во-вторых, я пытался указать поддержку компилятора для каждого из них. Если вы считаете, что мой ответ каким-то образом предвзят, предложите изменения в формулировках или не стесняйтесь их изменять. :) - person Sourav Ghosh; 29.07.2016
comment
Динамическое выделение не заменяет VLA в целом. Мало того, что функции недоступны для большинства реализаций - учитывая, что большинство реализаций являются автономными без ненужных на тот момент частей стандартной библиотеки. Тогда их нельзя использовать, если вам нужны многомерные массивы, потому что вам уже нужен указатель на VLA для 2D, если вы используете динамическое размещение. - person too honest for this site; 29.07.2016
comment
@ Олаф Ты очень прав. Замена, нет. Альтернативный подход, да. В случае, если VLA отсутствуют (не поддерживаются), мы должны обойти их с помощью указателя и malloc(), согласны? Кроме того, VLA ограничены размером стека, по крайней мере, в gcc, а malloc(), вероятно, более щедры. :) - person Sourav Ghosh; 29.07.2016
comment
Нет, обходным путем является отказ от поддержки мусорных (и часто дорогих) компиляторов. Это может звучать жестко, но это единственный способ оказать на них давление. Без этого C никогда не выберется из депрессии C90. Ре. размер стека: отличается ли он от массивов фиксированного размера или других переменных или рекурсии? Извините, но это не аргумент против VLA, а автоматические переменные в целом (что, как вы, надеюсь, согласитесь, довольно глупо). Кстати. стандарт C не требует использования стека, вы можете очень хорошо выделять автоматические переменные, используя динамическое выделение памяти. И размер не зависит от компилятора - person too honest for this site; 29.07.2016

Если вам нужно что-то, совместимое с C89 и не использующее слишком много памяти, есть третий вариант, который заключается в динамическом выделении памяти:

int n, i;
printf("Number of elements: ");
scanf("%d", &n);
int *myArray = malloc(sizeof(int)*n);   // allocate space for n ints
if (myArray == NULL) {
    perror("malloc failed");
    exit(1);
}
for(i = 0; i < n; i++)
    myArray[i] = 0;

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

person dbush    schedule 29.07.2016
comment
@dbush Я всегда использую указатели и malloc всякий раз, когда мне нужно динамически изменить размер, в данном случае я этого не делаю. При использовании MinGW с флагом компилятора c89 работает первый способ. Почему я должен использовать это вместо этого? (Каковы преимущества) - person ; 29.07.2016
comment
@Sheldon Использование динамического распределения более портативно. Однако, если ваш компилятор поддерживает массивы переменной длины и вы не планируете его миграцию, его преимущество заключается в том, что вам не нужно беспокоиться об освобождении выделенной памяти. - person dbush; 29.07.2016
comment
@KevinDTimm: calloc обнуляет все биты. Это идентично значению 0 только для целых чисел. Хорошо здесь, но не верно для плавающей запятой или указателей. (В этом аспекте он отличается от инициализаторов по умолчанию, кстати.) Просто позвольте компилятору выяснить, как это оптимизировать. Хороший компилятор может использовать memset/memclr или даже свернуть обе части в calloc. если это работает. - person too honest for this site; 29.07.2016
comment
@Olaf - OP объявил массив int, я решаю его проблему, а не проблему других. Если бы ему нужно было решение общей проблемы, я полагаю, он бы спросил. - person KevinDTimm; 01.08.2016