Объявление и инициализация массивов в C - PullRequest
50 голосов
/ 29 июня 2010

Есть ли способ сначала объявить, а затем инициализировать массив в C?

До сих пор я инициализировал массив следующим образом:

int myArray[SIZE] = {1,2,3,4....};

Но мне нужно что-то сделатькак это

int myArray[SIZE];

myArray = {1,2,3,4....};

Ответы [ 8 ]

31 голосов
/ 29 июня 2010

В C99 вы можете сделать это, используя составной литерал в комбинации с memcpy

memcpy(myarray, (int[]) { 1, 2, 3, 4 }, sizeof myarray);

(при условии, что размер источника и размер цели совпадают).

В C89 / 90 вы можете эмулировать это, объявив дополнительный «исходный» массив

const int SOURCE[SIZE] = { 1, 2, 3, 4 }; /* maybe `static`? */
int myArray[SIZE];
...
memcpy(myarray, SOURCE, sizeof myarray);
13 голосов
/ 29 июня 2010

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

Вы можете сделать это с помощью кода, например:

myArray[0] = 1;
myArray[1] = 2;
myArray[2] = 27;
:
myArray[99] = -7;

или (если есть формула):

for (int i = 0; i < 100; i++) myArray[i] = i + 1;

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

static const int onceArr[]  = {  0,  1,  2,  3,  4,..., 99};
static const int twiceArr[] = {  0,  2,  4,  6,  8,...,198};
:
int myArray[7];
:
memcpy (myArray, twiceArr, sizeof (myArray));

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


Вы даже можете локализовать его для функции инициализации:

void initMyArray (int *arr, size_t sz) {
    static const int template[] = {2, 3, 5, 7, 11, 13, 17, 19, 21, ..., 9973};
    memcpy (arr, template, sz);
}
:
int myArray[100];
initMyArray (myArray, sizeof(myArray));

Статический массив (почти наверняка) будет создан во время компиляции, поэтому для этого не потребуется никаких затрат времени выполнения, и memcpy должен быть ослепительно быстрым, вероятно, быстрее, чем 1229 операторов присваивания, но совершенно определенно меньше набирать твоя часть: -).

4 голосов
/ 29 июня 2010

Есть ли способ сначала объявить, а затем инициализировать массив в C?

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

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

myArray[0] = 1;
myArray[1] = 2;
...

или

for(int i = 1; i <= SIZE; i++)
{
  myArray[i-1] = i;
}
2 голосов
/ 30 июня 2010

Это дополнение к принятому ответу AndreyT с комментариями Няна о несоответствующих размерах массивов.Я не согласен с их автоматической установкой пятого элемента на ноль.Вероятно, это должно быть 5 - число после 1,2,3,4.Поэтому я бы предложил использовать оболочку для memcpy (), которая выдает ошибку времени компиляции , когда мы пытаемся скопировать массивы разных размеров:

#define Memcpy(a,b) do {                    /* copy arrays */       \
    ASSERT(sizeof(a) == sizeof(b) &&        /* a static assert */   \
           sizeof(a) != sizeof((a) + 0));   /* no pointers */       \
    memcpy((a), (b), sizeof (b));           /* & unnecesary */      \
    } while (0)                             /* no return value */

Этот макрос будет генерировать время компиляцииошибка, если ваш массив имеет длину 1. Возможно, это особенность.

Поскольку мы используем макрос, составному литералу C99, кажется, нужна дополнительная пара скобок:

Memcpy(myarray, ((int[]) { 1, 2, 3, 4 }));

Здесь ASSERT () является «статическим утверждением».Если у вас его еще нет, я использую следующее на нескольких платформах:

#define CONCAT_TOKENS(a, b) a ## b
#define EXPAND_THEN_CONCAT(a,b) CONCAT_TOKENS(a, b)
#define ASSERT(e) enum {EXPAND_THEN_CONCAT(ASSERT_line_,__LINE__) = 1/!!(e)}
#define ASSERTM(e,m) /* version of ASSERT() with message */ \
    enum{EXPAND_THEN_CONCAT(m##_ASSERT_line_,__LINE__)=1/!!(e)}
1 голос
/ 29 июня 2010

Почему вы не можете инициализироваться при объявлении?

Какой компилятор C вы используете?Поддерживает ли он C99?

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

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

0 голосов
/ 28 июня 2017

Невозможно присвоить значения массиву сразу после инициализации.Лучшей альтернативой будет использование цикла.

for(i=0;i<N;i++)
{
     array[i] = i;
}

Вы можете жестко программировать и присваивать значения, такие как - array[0] = 1 и т. Д.

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

0 голосов
/ 09 января 2017

ОП исключил некоторую важную информацию из вопроса и поместил ее только в комментарии к ответу.

Мне нужно инициализировать после объявления, потому что будет по-другому в зависимости от условия, я имею в виду что-то вроде этого туАггау [РАЗМЕР]; if (condition1) {myArray {x1, x2, x3, ...}} еще if (условие2) {myArray {y1, y2, y3, ...}}. , и так далее ...

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

//static global since some compilers build arrays from instruction data
//... notably not const though so they can later be modified if needed
#define SIZE 8
static int myArrays[2][SIZE] = {{0,1,2,3,4,5,6,7},{7,6,5,4,3,2,1,0}};

static inline int *init_myArray(_Bool conditional){
  return myArrays[conditional];
}

// now you can use:
//int *myArray = init_myArray(1 == htons(1)); //any boolean expression

Не встроенная версия дает эту результирующую сборку на x86_64:

init_myArray(bool):
        movzx   eax, dil
        sal     rax, 5
        add     rax, OFFSET FLAT:myArrays
        ret
myArrays:
        .long   0
        .long   1
        .long   2
        .long   3
        .long   4
        .long   5
        .long   6
        .long   7
        .long   7
        .long   6
        .long   5
        .long   4
        .long   3
        .long   2
        .long   1
        .long   0

Для дополнительных условий / массивов просто измените 2 в myArrays на желаемое число и используйте аналогичную логику, чтобы получить указатель на правильный массив.

0 голосов
/ 29 июня 2010

Нет такого особого способа, которым вы можете инициализировать массив после его объявления один раз.

Есть только три варианта:

1.) инициализировать ихв разных строках:

int array[SIZE];

array[0] = 1;
array[1] = 2;
array[2] = 3;
array[3] = 4;
//...
//...
//...

Но я думаю, это не то, что вы хотите.

2.) Инициализируйте их, используя цикл for или while:

for (i = 0; i < MAX ; i++)  {
    array[i] = i;
}

Это ЛУЧШИЙ СПОСОБ для достижения вашей цели.

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

И могу ли я спросить вас, почему именно выхочу сделать это ???

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...