C инициализировать указатель на литерал массива без дополнительной переменной

Matthias спросил: 28 марта 2018 в 03:55 в: c

У меня есть переменная, которая должна содержать указатель на массив. Обычно это делается путем создания переменной с массивом, а затем сохранения указателя на эту переменную. Тем не менее, мне нужно сделать это, возможно, для 10 переменных, и я не хочу создавать дополнительный массив для каждого из них. Что я первый пробовал, было

int *numList = {1, 2, 3};

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

int (*numList)[3] = {1, 2, 3};

5 ответов

Matthias ответил: 28 марта 2018 в 06:08
Спасибо, это то, что я пытался сделать.
Есть решение
Jonathan Leffler ответил: 28 марта 2018 в 05:52

В C99 и C11 вы можете использовать составной литерал для достижения того, что запрашивается в заголовке вопроса, а именно инициализировать указатель, чтобы он указывал на литерал массива без каких-либо дополнительных переменных:

int *numList = (int []){ 1, 2, 3 };

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

Если бы вы были настолько заблуждены, что создали static int *numList = (int []){ 1, 2, 3}; внутри функции, вы бы настроили себя на мир вреда - не делайте Это. (В области видимости файла, вне какой-либо функции, это не представляет никаких проблем.) Указатель будет инициализирован не позднее, чем при первом вызове функции, но нет гарантии, что то, на что он указывает, имеет static длительность и последующие вызовы могут указывать на мусор.

neuro_sys ответил: 28 марта 2018 в 08:38

Стандарт гласит:

За исключением случаев, когда это операнд оператора sizeof или унарный оператор & или строковый литерал, используемый для инициализации массива, выражение, которое имеет тип '' массив типа '' и преобразуется в выражение с типом '' указатель на тип '' , которое указывает на initialelement объекта массива и не является lvalue.

Вы можете присвоить массив типу int[], поскольку "приведение массива к указателю" не требуется по самой причине того, что массивы, так сказать, разлагаются на указатели сами по себе.

Короче говоря, int[] трактуется как int* с практической точки зрения . Массивы эффективно указывают на их первый элемент:

int array[] = { 1, 2, 3 };

Теперь вы можете передать этот объект в функцию с прототипом void func(int *array); без приведение к int *. То есть вы можете назвать его как func(array).

Об этом можно сказать как array == &array. Следовательно, вам никогда не нужно явно преобразовывать массив в указатель, поскольку это будет избыточно.

Проверьте Что такое распадающийся массив? для получения дополнительной информации.

Jonathan Leffler ответил: 28 марта 2018 в 07:27
Ваша цитата, кажется, из C99; C11 §6.3.2.1 Lvalues, массивы и указатели функций перечисляют _Alignof и строковые литералы, используемые для инициализации массива в качестве других исключений. Общая тема 6.3 - "конверсии". Я не согласен с вашим утверждением, что "int [] является int *" - это неправильно. Массив легко преобразуется в указатель, но это не то же самое, что сказать, что массив такой же, как указатель. Вы также не обратились, а тем более не ответили на главный вопрос - как инициализировать pArray без определения array.
neuro_sys ответил: 28 марта 2018 в 08:20
Спасибо за разъяснения. Практически, насколько я знаю, вам не нужно явно приводить int [] к int *, поскольку преобразование происходит неявно. Это похоже на то, что не нужно приводить указатель к void *. Ответ на их вопрос с моей стороны состоял в том, что они не должны приводить массив целых чисел к указателю на int, а вместо этого назначать объект в int [], которым является этот объект. Когда они передают этот объект в другое место, приведение не будет необходимости.
neuro_sys ответил: 28 марта 2018 в 08:32
Я обновил вопрос, чтобы исправить проблемы, которые вы указали.
thomachan ответил: 28 марта 2018 в 05:16

Само имя массива является указателем на первый элемент массива.

т.е. в вашем примере

int numList[3]={1,2,3};

numList указывает в 1.

если вы хотите передать указатель этого массива на функцию типа

void sort(int *array)
{
//do something
}

, вы можете вызвать эту функцию с именем вашего массива как аргумент.

sort(numList);
deLock ответил: 28 марта 2018 в 05:14
Это неправда, что "Нет необходимости конвертировать массив в poin [t] er". Вы не можете работать с именем переменной массива, как с указателем. Например, вы не можете сделать array_name = 1;
thomachan ответил: 28 марта 2018 в 05:18
Это правда .. редактирование моего ответа ..
Eric Postpischil ответил: 28 марта 2018 в 05:25
Вы можете сделать *array_name = 1;. Массивы являются не указателями на свои первые элементы, но они автоматически преобразуются в указатели на свои первые элементы во многих контекстах, в том числе в *array_name = 1;. Тем не менее, этот ответ неверен, чтобы утверждать, что "само имя массива является указателем на первый элемент массива".
deLock ответил: 31 марта 2018 в 02:28
Автоматическое приведение к указателю не всегда разрешено. А также вы не можете делать что-то вроде array_name ++. Так что нет, array_name не является указателем, и вы не можете работать с ним как с одним. Поэтому мое возражение справедливо - это неправда, что "нет необходимости преобразовывать массив в указатель".
Jonathan Leffler Ibrahim ответил: 28 марта 2018 в 05:45
int (*numList)[3];

FYG, это указатель на массив из 3 целых чисел (квадратные скобки имеют более высокий приоритет, чем); Вы не можете инициализировать его таким образом.

Eric Postpischil ответил: 28 марта 2018 в 05:27
numList можно инициализировать в этом объявлении с помощью int (*numList)[3] = (int [][3]) {{3, 4, 5}};.
Jonathan Leffler ответил: 28 марта 2018 в 05:49
Хотя содержание является точным вплоть до комментария об инициализации, оно не дает ответа на вопрос.