Как инициализировать все члены массива одним и тем же значением? - PullRequest
885 голосов
/ 14 октября 2008

У меня большой массив в C (не C ++, если это имеет значение). Я хочу инициализировать все элементы с одинаковым значением. Я могу поклясться, что когда-то знал простой способ сделать это. Я мог бы использовать memset() в моем случае, но нет ли способа сделать это встроенным прямо в синтаксис C?

Ответы [ 21 ]

1148 голосов
/ 14 октября 2008

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

Не забывайте, очевидное решение:

int myArray[10] = { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 };

Элементы с пропущенными значениями будут инициализированы в 0:

int myArray[10] = { 1, 2 }; // initialize to 1,2,0,0,0...

Таким образом, все элементы будут инициализированы в 0:

int myArray[10] = { 0 }; // all elements 0

В C ++ пустой список инициализации также инициализирует каждый элемент в 0. Это не разрешено с C:

int myArray[10] = {}; // all elements 0 in C++

Помните, что объекты со статической продолжительностью хранения будут инициализироваться в 0, если нет указан инициализатор:

static int myArray[10]; // all elements 0

И то, что «0» не обязательно означает «все биты-ноль», поэтому использование выше лучше и более портативный, чем memset (). (Значения с плавающей точкой будут инициализируется до +0, указатели на нулевое значение и т. д.)

371 голосов
/ 16 октября 2008

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

int array[1024] = {[0 ... 1023] = 5};

Ознакомьтесь с подробным описанием: http://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Designated-Inits.html

171 голосов
/ 14 октября 2009

Для статической инициализации большого массива с одним и тем же значением без множественного копирования-вставки вы можете использовать макросы:

#define VAL_1X     42
#define VAL_2X     VAL_1X,  VAL_1X
#define VAL_4X     VAL_2X,  VAL_2X
#define VAL_8X     VAL_4X,  VAL_4X
#define VAL_16X    VAL_8X,  VAL_8X
#define VAL_32X    VAL_16X, VAL_16X
#define VAL_64X    VAL_32X, VAL_32X

int myArray[53] = { VAL_32X, VAL_16X, VAL_4X, VAL_1X };

Если вам нужно изменить значение, вы должны произвести замену только в одном месте.

Редактировать: возможные полезные расширения

(любезно предоставлено Джонатан Леффлер )

Вы можете легко обобщить это с помощью:

#define VAL_1(X) X
#define VAL_2(X) VAL_1(X), VAL_1(X)
/* etc. */

Вариант может быть создан с помощью:

#define STRUCTVAL_1(...) { __VA_ARGS__ }
#define STRUCTVAL_2(...) STRUCTVAL_1(__VA_ARGS__), STRUCTVAL_1(__VA_ARGS__)
/*etc */ 

, который работает со структурами или составными массивами.

#define STRUCTVAL_48(...) STRUCTVAL_32(__VA_ARGS__), STRUCTVAL_16(__VA_ARGS__)

struct Pair { char key[16]; char val[32]; };
struct Pair p_data[] = { STRUCTVAL_48("Key", "Value") };
int a_data[][4] = { STRUCTVAL_48(12, 19, 23, 37) };

имена макросов являются предметом переговоров.

61 голосов
/ 14 октября 2008

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

int myArray[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };

Компилятор выведет измерение из списка инициализатора. К сожалению, для многомерных массивов может быть опущено только самое внешнее измерение:

int myPoints[][3] = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9} };

в порядке, но

int myPoints[][] = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9} };

нет.

47 голосов
/ 22 марта 2012

Я видел код, который использовал этот синтаксис:

char* array[] = 
{
    [0] = "Hello",
    [1] = "World"
};   

Где это становится особенно полезным, если вы создаете массив, который использует перечисления в качестве индекса:

enum
{
    ERR_OK,
    ERR_FAIL,
    ERR_MEMORY
};

#define _ITEM(x) [x] = #x

char* array[] = 
{
    _ITEM(ERR_OK),
    _ITEM(ERR_FAIL),
    _ITEM(ERR_MEMORY)
};   

Это поддерживает порядок, даже если вы пишете некоторые из перечисляемых значений не по порядку.

Подробнее об этой технике можно узнать здесь и здесь .

21 голосов
/ 14 октября 2008
int i;
for (i = 0; i < ARRAY_SIZE; ++i)
{
  myArray[i] = VALUE;
}

Я думаю, что это лучше, чем

int myArray[10] = { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5...

в случае изменения размера массива.

11 голосов
/ 14 октября 2008

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

memset дает вам попадание во время выполнения для выполнения работы, но ни одно правильное совпадение с размером кода не застраховано от изменений размера массива. Я бы использовал это решение почти во всех случаях, когда массив был больше, скажем, нескольких десятков элементов.

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

7 голосов
/ 15 октября 2008

Вот еще один способ:

static void
unhandled_interrupt(struct trap_frame *frame, int irq, void *arg)
{
    //this code intentionally left blank
}

static struct irqtbl_s vector_tbl[XCHAL_NUM_INTERRUPTS] = {
    [0 ... XCHAL_NUM_INTERRUPTS-1] {unhandled_interrupt, NULL},
};

См:

C-расширений

Назначенные единицы

Тогда задайте вопрос: когда можно использовать расширения C?

Пример кода выше находится во встроенной системе и никогда не увидит свет от другого компилятора.

5 голосов
/ 14 октября 2009

слегка насмешливый ответ; написать заявление

array = initial_value

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

5 голосов
/ 14 октября 2008

Для инициализации «нормальных» типов данных (например, массивов int) вы можете использовать скобочную нотацию, но она обнулит значения после последней, если в массиве еще есть место:

// put values 1-8, then two zeroes
int list[10] = {1,2,3,4,5,6,7,8};
...