Почему я не могу использовать параметр функции в качестве размера массива в C?

Я пытаюсь создать простую функцию расширения массива, которая создает новый массив с теми же значениями, что и предыдущий массив, расширенный на значение:

char* test(char array[], int expandBy) {
    char newArray[sizeof(array) + expandBy];
    strncpy(newArray, array, sizeof(array));

    return newArray;
}

Однако я получаю ошибку времени компиляции expression must have a constant value. Все ответы, которые я видел на подобные вопросы, предполагают использование макроса, но я не могу использовать макрос, если заранее не знаю значение.

Кто-нибудь знает, как я могу это исправить, или есть ли альтернатива этому?


person Alex Quilliam    schedule 11.11.2017    source источник
comment
У вас гораздо более серьезная проблема, чем ошибка компилятора: вы возвращаете указатель на локальную переменную. Локальные переменные выходят из области видимости после возврата функции, и это оставит вас с блуждающим указателем на массив, который больше не существует. Попытка разыменовать возвращенный указатель приведет к неопределенное поведение.   -  person Some programmer dude    schedule 11.11.2017
comment
Еще одно не связанное с этим замечание: есть случай, когда strncpy будет не добавлять терминатор. Обратите внимание на это.   -  person Some programmer dude    schedule 11.11.2017
comment
Как только вы передаете массив функции, он распадается на указатель. В этот момент sizeof сообщает вам размер указателя, а не длину массива. Если это строка с нулевым завершением, вы можете использовать strlen, чтобы найти длину содержимого, но это может не соответствовать длине фактического массива. stackoverflow.com/questions/492384/   -  person Retired Ninja    schedule 11.11.2017
comment
@Someprogrammerdude: на самом деле имеет значение время жизни объекта newArray, а не область его имени. Область видимости – это где отображается имя. Время жизни — это когда существует объект.   -  person Eric Postpischil    schedule 11.11.2017
comment
Кстати, я подозреваю, что OP не компилирует это с современной стандартной версией C. Я не вижу в их коде ни одного выражения, которое генерировало бы эту ошибку о постоянном значении. Но если они используют версию C, которая не поддерживает массивы переменной длины, они получат эту ошибку в объявлении newArray, потому что оно использует значение времени выполнения для измерения. Таким образом, причина, по которой OP получила ошибку, на самом деле не связана с тем фактом, что sizeof(array) не дает размер «массива».   -  person Eric Postpischil    schedule 11.11.2017
comment
Или, что более вероятно, они компилируются как C++, а не C, несмотря на их тег в вопросе и заголовок.   -  person Eric Postpischil    schedule 11.11.2017


Ответы (2)


Это потому, что передача массива в функцию фактически передает указатель, поэтому sizeof дает вам размер указателя вместо размера массива, простое решение

char *test(char *array, size_t current_size, size_t expand_size)
{
    char string[current_size + expand_size + 1];
    // Rest of your code
}

Но тогда было бы ошибкой возвращать массив string из этой функции, так как он действителен только внутри функции.

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

Кроме того, в целом вам следует избегать strncpy(), потому что терминатор null не гарантируется с помощью этой функции, оказывается, очень легко получить массив без завершения null, который вы предполагаете, что это строка, но это, конечно, не так.

person Iharob Al Asimi    schedule 11.11.2017

Я нашел две ошибки в вашем коде.

Во-первых, передача массива в функцию — это точно передача указателя на первый элемент массива. Итак, sizeof(array)возвращает размер указателя, а не всего массива.

Во-вторых, массив в функции хранится в стеке, он будет уничтожен после выхода программы из функции. Вы не можете получить ничего, кроме ошибок, при возврате массива, созданного char newArray[size].

Вот мой код, который может вам помочь:

#include <stdlib.h>
#include <string.h>

char *NewArray(char arr[], int arr_size, int expand_size)
{
    int new_size = arr_size + expand_size;
    char *new_arr = malloc(sizeof(char) * new_size);
    strncpy(new_arr, arr, new_size * sizeof(char));

    return new_arr;
}
person K.Q D    schedule 11.11.2017
comment
Небольшое примечание: вы используете sizeof(char) * new_size для вычисления размера, переданного в malloc, но только new_size для размера, переданного в strncpy. Они одинаковы с char, конечно, но было бы неплохо использовать один и тот же стиль в обоих местах — либо использовать sizeof(char) * new_size, чтобы сделать размер явным и заметным на случай, если тип когда-либо изменится, либо использовать new_size в обоих местах для краткости. Или, возможно, sizeof *arr * new_size, чтобы размер автоматически менялся при изменении типа массива. - person Eric Postpischil; 11.11.2017
comment
Вы не можете получить ничего, кроме ошибок, при возврате массива, созданного char newArray[size] Правда, но OP этого не делает, так зачем упоминать об этом? - person alk; 11.11.2017