Присвоить несколько значений массиву в C

Есть ли способ сделать это в сжатой форме?

GLfloat coordinates[8];
...
coordinates[0] = 1.0f;
coordinates[1] = 0.0f;
coordinates[2] = 1.0f;
coordinates[3] = 1.0f;
coordinates[4] = 0.0f;
coordinates[5] = 1.0f;
coordinates[6] = 0.0f;
coordinates[7] = 0.0f;
return coordinates;

Что-то вроде coordinates = {1.0f, ...};?


person UnstableFractal    schedule 20.08.2010    source источник
comment
Вы возвращаете указатель на локальную переменную? Некоторые из вещей, которые люди сказали в ответах/комментариях ниже, предполагают либо то, что задействованные переменные являются автоматическими, либо нет. Может поможет, если укажете.   -  person Steve Jessop    schedule 21.08.2010
comment
После инициализации структуры нет простого способа массового назначения членов (кроме создания копии другой структуры с помощью memcpy). Я часто ловлю себя на том, что хочу, чтобы у меня была эта функция.   -  person bta    schedule 21.08.2010
comment
Я думаю, что ваш первоначальный ответ лучший - он интуитивно понятен, хотя и немного многословен, но это не беспокоит современных компиляторов.   -  person Yan King Yin    schedule 29.10.2015


Ответы (7)


Если вы действительно хотите назначить значения (в отличие от инициализации), вы можете сделать это следующим образом:

 GLfloat coordinates[8]; 
 static const GLfloat coordinates_defaults[8] = {1.0f, 0.0f, 1.0f ....};
 ... 
 memcpy(coordinates, coordinates_defaults, sizeof(coordinates_defaults));

 return coordinates; 
person James Curran    schedule 20.08.2010
comment
Более того, сделайте ее статической константой, и компиляторы смогут оптимизировать переменную прямо из кода. - person Zan Lynx; 21.08.2010
comment
@Zan Lynx: Разве большинство компиляторов не будут достаточно умны, чтобы сделать это в любом случае? Ну что ж. Хорошая практика, чтобы быть явным, я полагаю. - person Chris Cooper; 21.08.2010
comment
@Chris Cooper: нет, если это глобальный (который может быть изменен в коде, который компилятор не видит). Из этих фрагментов кода нельзя сказать, скрывается ли ... начало функции. - person Steve Jessop; 21.08.2010
comment
@Steve: Хороший звонок. Спасибо за разъяснения. - person Chris Cooper; 21.08.2010

Хотя в вашем случае подойдет обычная инициализация, есть трюк, чтобы обернуть массив в структуру (которую можно инициализировать после объявления).

Например:

struct foo {
  GLfloat arr[10];
};
...
struct foo foo;
foo = (struct foo) { .arr = {1.0, ... } };
person domen    schedule 20.08.2010

Старый школьный способ:

GLfloat coordinates[8];
...

GLfloat *p = coordinates;
*p++ = 1.0f; *p++ = 0.0f; *p++ = 1.0f; *p++ = 1.0f;
*p++ = 0.0f; *p++ = 1.0f; *p++ = 0.0f; *p++ = 0.0f;

return coordinates;
person Pavel Minaev    schedule 20.08.2010
comment
Элегантно, я даю вам это, но управление некоторым разумным набором данных инициализации (с возможной необходимостью их настройки) будет громоздким. Я бы предпочел некоторый синтаксис, в котором достаточно только данных (и, возможно, некоторых разделителей для наглядности). К тому же это арифметика указателей. MISRA сойдет с ума по этому поводу. - person OpalApps; 04.04.2019

Вы можете использовать:

GLfloat coordinates[8] = {1.0f, ..., 0.0f};

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

Два других способа, которые приходят на ум, - это разбить содержимое, если оно исправлено:

GLfloat base_coordinates[8] = {1.0f, ..., 0.0f};
GLfloat coordinates[8];
:
memcpy (coordinates, base_coordinates, sizeof (coordinates));

или предоставьте функцию, которая в любом случае выглядит как ваш код инициализации:

void setCoords (float *p0, float p1, ..., float p8) {
    p0[0] = p1; p0[1] = p2; p0[2] = p3; p0[3] = p4;
    p0[4] = p5; p0[5] = p6; p0[6] = p7; p0[7] = p8;
}
:
setCoords (coordinates, 1.0f, ..., 0.0f);

имея в виду, что эти многоточия (...) являются заполнителями, а не элементами, которые буквально вставляются в код.

person paxdiablo    schedule 20.08.2010

Точно, вы почти поняли:

GLfloat coordinates[8] = {1.0f, ..., 0.0f};
person Felix Kling    schedule 20.08.2010
comment
@smsteel Этот синтаксис применяется только к объявлениям - person Michael Mrozek; 21.08.2010
comment
Это плохо. Есть ли другой способ упростить это? :) - person UnstableFractal; 21.08.2010

Я пошел с методом инициализации массива:

#include <stdarg.h>

void int_array_init(int *a, const int ct, ...) {
  va_list args;
  va_start(args, ct);
  for(int i = 0; i < ct; ++i) {
    a[i] = va_arg(args, int);
  }
  va_end(args);
}

называется вроде,

const int node_ct = 8;
int expected[node_ct];
int_array_init(expected, node_ct, 1, 3, 4, 2, 5, 6, 7, 8);

Инициализация массива C99, например:

const int node_ct = 8;
const int expected[node_ct] = { 1, 3, 4, 2, 5, 6, 7, 8 };

И в configure.ac:

AC_PROG_CC_C99

компилятор на моем ящике разработчика был совершенно счастлив. Компилятор на сервере пожаловался:

error: variable-sized object may not be initialized
   const int expected[node_ct] = { 1, 3, 4, 2, 5, 6, 7, 8 };

а также

warning: excess elements in array initializer
   const int expected[node_ct] = { 1, 3, 4, 2, 5, 6, 7, 8 };

для каждого элемента

Он вообще не жалуется, например:

int expected[] = { 1, 2, 3, 4, 5 };

Мне нравится проверка размера и то, что поддержка varargs действует более надежно, чем поддержка инициализатора массива.

Найдите PR с образцом кода на https://github.com/wbreeze/davenport/pull/15/files

Что касается https://stackoverflow.com/a/3535455/608359 от @paxdiablo, мне понравилось; но чувствовал себя неуверенно из-за того, что количество раз, когда указатель инициализации продвигается, синхронизировано с количеством элементов, выделенных для массива. В худшем случае указатель инициализации выходит за пределы выделенной длины. Таким образом, разница в PR содержит,

  int expected[node_ct];
- int *p = expected;
- *p++ = 1; *p++ = 2; *p++ = 3; *p++ = 4;
+ int_array_init(expected, node_ct, 1, 2, 3, 4);

Метод int_array_init безопасно назначит мусор, если количество аргументов меньше, чем у node_ct. Мусорное присваивание должно быть легче поймать и отладить.

person Douglas Lovell    schedule 19.07.2019
comment
Я проголосовал за вариативный подход, который делает код более читаемым. Но это немного похоронено в вашем ответе. Возможно, вам следует отредактировать свой пост, чтобы уделить ему внимание, которого он заслуживает. - person Faibbus; 01.06.2021

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

static inline void set_coordinates(
        GLfloat coordinates[static 8],
        GLfloat c0, GLfloat c1, GLfloat c2, GLfloat c3,
        GLfloat c4, GLfloat c5, GLfloat c6, GLfloat c7)
{
    coordinates[0] = c0;
    coordinates[1] = c1;
    coordinates[2] = c2;
    coordinates[3] = c3;
    coordinates[4] = c4;
    coordinates[5] = c5;
    coordinates[6] = c6;
    coordinates[7] = c7;
}

а затем просто позвоните

GLfloat coordinates[8];
// ...
set_coordinates(coordinates, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f);
person dpi    schedule 13.06.2018