2015-05-18 3 views
1

Можно ли написать код, как показано ниже?Объявление массива внутри функции

void func(int v[], int size) { 
int array_local[size]; 

for(int i = 0; i < size; i++) array_local[i] = v[i]; 

/* 
Other stuff... 
*/ 

} 

Или я могу наткнуться на какую-то ошибку?

+1

Зависит от того, что вы делаете, а также от значения 'size'. Однако ничего в данном коде не так. –

+1

Обратите внимание, что массивы переменной длины хранятся в стеке, и у вас ограниченное пространство стека, поэтому этот случай является проблемой. Также обратите внимание, если вы хотите, чтобы код был переносимым [VLA - это функция C99] (http://stackoverflow.com/a/16588397/1708801) и [до недавнего времени Visual Studio не поддерживала C99] (http: // stackoverflow .com/q/27826409/1708801), и насколько я знаю, массивы переменной длины все еще отсутствуют. –

+1

Это нормально в C99, если размер достаточно мал, чтобы не переполнять стек.Вам будет лучше с 'size' типа' size_t'. – dasblinkenlight

ответ

2

Да, это прекрасно и действует на и выше C99. Он называется VLA.

Чтобы быть на более безопасной стороне, вы должны пометить значение size перед использованием его в качестве количества элементов массива. Поскольку у вас есть size, определяемый как int, вы должны запретить передачу значения от -5 до size.

Тем не менее, для оставшейся части кода (как общее предложение)

  1. v[i] не должно вызывать в перерасходу памяти.
  2. Массив является локальным для функции. Вы никогда не должны пытаться вернуть адрес массива (либо через указатель, либо через инструкцию return).
+0

Могу ли я объявить массив с двойным размером, что-то вроде «int array_local [2 * size]»? – user8469759

+0

@ Lukkio да, конечно, вы можете, если 1) предлагаемые проверки на 'size' сделаны. и 2) размер '2 *' не вызывает stackoverflow. :-) –

2

Это безопасно, если вызывающий абонент гарантирует, что v имеет не менее size элементов, иначе, конечно, это вызовет проблемы, вам не о чем беспокоиться, потому что вы ничего не можете с этим поделать.

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

Кроме того, приведенный выше код не нужно скопировать массив, можно просто

memcpy(array_local, v, size * sizeof(int)); 
+0

Размер - это параметр. Он уже убедился, что вызывающий определяет размер локального массива. – SBI

+1

Я так много думал, но тогда вы должны написать, что 'v' должны иметь как минимум элементы' size'. 'array_local' автоматически делает. – SBI

1

Это называется Variable Length Array, и они существуют только на C99. До тех пор, пока ваш компилятор поддерживает флаг компиляции -c99, и вы его используете, код действителен.

Что касается должен использовать его, это зависит от того, насколько вы ожидаете size. При распределении стека у вас нет защиты от выделения слишком большого объема памяти. Если бы вы использовали динамический распределитель, например malloc, вы можете проверить возвращаемое значение NULL, тогда как с VLA вы просто взорвите стек, если попросите слишком много. Если size будет небольшим, с ним проблем нет.

1

Вы можете реализовать то же самое другим способом с использованием динамического распределения памяти и безопасно быть реализованы:

void func(int v[], int size) { 
int *array_local = (int*)malloc(sizeof(int) * size); 

for(int i = 0; i < size; i++) *(array_local + i) = *(v + i); 

/* 
Other stuff... 
*/ 

} 
+0

кроме 1) в C, не отбрасывайте возвращаемое значение из malloc (и семейства) 2) всегда проверяйте (! = NULL) возвращаемое значение, чтобы гарантировать успешную операцию. Я использую эту форму с момента первой работы с C, около 30 лет назад. – user3629249

+0

Согласовано с пунктом 2. Но в пункте 1: если вы не будете выводить вывод malloc, как вы назначаете память указателю. Компилятор также даст ошибку. Typecast не нужен только в случае void *. –