Как повторно инициализировать массив в C (не C ++)? - PullRequest
7 голосов
/ 20 марта 2012

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

Должен ли я определить его с помощью указателя: int *data[], или я могу просто кодировать: int data[] = {};?

Например, я определил это как:

int main(void) {
    int data[] = {44, 22, 1, 2, 3, 1000, 3};

Теперь, как мне повторно инициализировать массив data?

Ответы [ 4 ]

11 голосов
/ 20 марта 2012

Инициализация происходит только один раз, когда вы создаете массив:

int foo[] = {0,1,2,3,4}; // creates a 5-element array of int and
                         // initializes it

После того, как массив был определен, вы можете назначить отдельным элементам :

foo[0] = 5;
foo[1] = 4;
foo[2] = 3;
foo[3] = 2;
foo[4] = 1;

но вы не можете назначить сам массив;IOW, вы не можете написать что-то вроде

foo = {5,4,3,2,1};

Однако вы можете использовать memcpy для копирования содержимого одного массива в другой:

int foo[5];
int bar[5] = {1,2,3,4,5};
int i;

memcpy(foo, bar, sizeof bar); // Copies *contents* of bar to foo

for (i = 0; i < sizeof foo / sizeof *foo; i++)
  printf("foo[%d] = %d\n", i, foo[i]);

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

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

void foo(int x)
{
  int arr[x];
  ...
}

Обратите внимание, что, как и обычные массивы, VLA не могутизменить размер после того, как они были определены.

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

int *foo = malloc(sizeof *foo * N); // where N is the number of elements

Вы все еще можете назначитьдля отдельных элементов:

foo[0] = 5;
foo[1] = 4;
foo[2] = 3;
...

или вы можете использовать memcpy, как показано выше.Обратите внимание, что вы должны помнить free массив, когда вы закончите:

free(foo);

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

int *tmp = realloc(foo, sizeof *foo * NEW_NUMBER_OF_ELEMENTS);
if (tmp)
  foo = tmp;

Почему бы просто не присвоить результат realloc обратно foo?Если операция realloc завершится неудачно, она вернет NULL.Если это происходит и мы присваиваем результат обратно foo, мы теряем отслеживание памяти, которую мы уже выделили, что приводит к утечке памяти.

C99 ввел синтаксис литерала массива;Вы можете написать что-то вроде

int *foo = (int[]){1,2,3,4,5};

и затем индексировать в foo как массив:

printf("foo[%d] = %d\n", i, foo[i]);

, хотя я почти уверен, что не может изменитьсодержимое foo[i], аналогично тому, как попытка изменить содержимое строкового литерала не определена (хотя я не нашел главы и стиха об этом).

4 голосов
/ 20 марта 2012

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

Вы можете явно выполнить цикл по массиву и заполнить его снова, если вам нужно назначить новые значения для каждого из них
OR
Используйте memset () или memcpy () для установки всех элементов на определенное значение или копирования в него определенных элементов или, соответственно,

1 голос
/ 19 октября 2015

Мое частичное решение для назначения новых значений (работает в gcc с c99 -синтаксисом):

#define arr_set(type, arr, ...) { \
    int arr_size = sizeof((type[]){__VA_ARGS__}) / sizeof(type); \
    type *parr = (type[]){__VA_ARGS__}; \
    for (int i = 0; i < arr_size; i++) \
        arr[i] = *parr++; }

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

Полный пример:

#include <stdio.h>

#define arr_set(type, arr, ...) { \
    int arr_size = sizeof((type[]){__VA_ARGS__}) / sizeof(type); \
    type *parr = (type[]){__VA_ARGS__}; \
    for (int i = 0; i < arr_size; i++) \
        arr[i] = *parr++; }

#define print_buf_int(buf) { \
    for (int i = 0; i < sizeof(buf)/sizeof(buf[0]); i++) \
        printf("%d ", (int)buf[i]); \
    printf("\n"); }

#define print_buf_char(buf) { \
    for (int i = 0; i < sizeof(buf)/sizeof(buf[0]); i++) \
        if (buf[i]) \
            printf("%c ", (char)buf[i]); \
        else \
            printf("null "); \
    printf("\n"); }

#define print_buf_str(buf) { \
    for (int i = 0; i < sizeof(buf)/sizeof(buf[0]); i++) \
        printf("%s ", (char*)buf[i]); \
    printf("\n"); }

int main()
{
    int brr[8] = {};
    int arr[8] = {3, 4, 5, 1, 0, 2};
    print_buf_int(arr);

    arr_set(int, arr, 9, 8 ,7);
    print_buf_int(arr);

    arr_set(int, arr, 0, 1, 2, 3, 4, 5, 6, 7);
    print_buf_int(arr);

    arr_set(int, arr, 11, 22, 33, 44, 55, 66, 77, 88, 99);  // 'brr' gets overwritten!!!
    print_buf_int(arr);
    print_buf_int(brr);

    unsigned char crr[13] = {'a', 'b', 'c', [12] = 'z'};
    print_buf_char(crr);

    arr_set(char, crr, 'd', 'e', 'f', '1', '2', '3');
    print_buf_char(crr);

    unsigned short srr[] = {111, 222, 333, 444, 555};
    print_buf_int(srr);

    arr_set(unsigned short, srr, -1, 0, 666);
    print_buf_int(srr);

    char *prr[] = {"hello", "variadic", "world"};
    print_buf_str(prr);

    arr_set(char*, prr, "good", "bye");
    print_buf_str(prr);
}

Вывод:

3 4 5 1 0 2 0 0 
9 8 7 1 0 2 0 0 
0 1 2 3 4 5 6 7 
11 22 33 44 55 66 77 88 
99 0 0 0 0 0 0 0 
a b c null null null null null null null null null z 
d e f 1 2 3 null null null null null null z 
111 222 333 444 555 
65535 0 666 444 555 
hello variadic world 
good bye world 
1 голос
/ 20 марта 2012

Инициализация (если есть) должна быть сделана во время создания переменной.Потому что во время компиляции компилятор присваивает это значение переменной.Любые другие назначения после этой строки выполняются только во время выполнения.

В вашем случае вы можете инициализировать массив во время его создания.В следующий раз, когда вы назначаете какое-то значение, это не означает «инициализация»;скорее это только назначение во время выполнения.

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

...