Совершенно нормально и обычно назначать struct
поля друг другу.Вы не можете присвоить массиву, но struct
s предоставляют своего рода исключение из этого, потому что назначение одного struct
другому приводит к тому, что пункт назначения получает копию первого struct
.В приведенном ниже коде вы не можете назначить copy_my_a.str = my_a.str;
, потому что это поля массива.Вы могли бы назначить copy_my_a = my_a;
, хотя.
Вложенные struct
скопированы таким же образом, поэтому, если назначен struct
, содержащий другой struct
, весь struct
, включая вложенный struct
.
Если struct
содержит поле массива, этот массив копируется в место назначения struct
.Поскольку это копия, она может быть изменена независимо от исходного массива.Но если struct
содержит указатель на какое-то выделение (массив, динамическое выделение и т. Д.), То копируется указатель, а не содержимое выделения (т. Е. Массив и т. Д.).Обычно это называется мелкая копия (хотя это не термин, используемый в Стандарте C).
При назначении structs
вы должны быть осторожны с этим;если вы измените массив с помощью указателя в одном struct
, это изменение будет видно во всех struct
с использованием этого указателя.
В приведенном ниже примере my_a
имеет поле массива, а my_b
имеет поле char *
.my_a.str
инициализируется для хранения строки ("my_a"
), а my_b.str
инициализируется указателем на первый элемент строки ("my_b"
).Копии каждого из двух struct
создаются путем назначения.
В копии my_a
, copy_my_a.str
является копией my_a.str
, поэтому весь массив был скопирован в новыйstruct
.Изменение исходной строки здесь не повлияет на копию.Аналогично, в копии my_b
, copy_my_b.str
является копией my_b.str
, но здесь это не скопированный массив, а только указатель.Изменение указанной строки будет видно в обоих struct
s, поскольку они совместно используют один и тот же массив через указатель.
Это может сбить вас с толку, если вы работаете с копиями таких struct
s и изменитеразделяемая строка через указатель без понимания того, что строка является общей, как в последнем примере в коде:
#include <stdio.h>
struct st {
char c;
int y;
};
struct exa {
int x;
struct st s;
char str[100];
};
struct exb {
int x;
struct st s;
char *str;
};
int main(void)
{
// .str holds an array: can't assign an array to an array
struct exa my_a = { .x = 1,
.s.c = 'x',
.s.y = 2,
.str = "my_a"
};
// .str holds a pointer to char: assign a pointer to arr[0]
char arr[100] = "my_b";
struct exb my_b = { .x = 1,
.s.c = 'x',
.s.y = 2,
.str = arr
};
struct exa copy_my_a = my_a;
struct exb copy_my_b = my_b;
puts("Nested structs are copied: ");
printf("my_a.s.c: %c\n", my_a.s.c);
printf("copy_my_a.s.c: %c\n", copy_my_a.s.c);
putchar('\n');
puts("copy_my_a.str is a copy of my_a.str, which is an array:");
printf("my_a.str: %s\n", my_a.str);
printf("copy_my_a.str: %s\n", copy_my_a.str);
putchar('\n');
puts("Changing the original array is not visible in the copy:");
for (size_t i = 0; i < sizeof "changed"; i++) {
my_a.str[i] = "changed"[i];
}
printf("my_a.str: %s\n", my_a.str);
printf("copy_my_a.str: %s\n", copy_my_a.str);
putchar('\n');
puts("copy_my_b.str is a copy of my_b.str, which is a pointer to arr[0]:");
printf("my_b.str: %s\n", my_b.str);
printf("copy_my_b.str: %s\n", copy_my_b.str);
putchar('\n');
puts("Changing the original array is visible in both structs:");
for (size_t i = 0; i < sizeof "changed"; i++) {
arr[i] = "changed"[i];
}
printf("my_b.str: %s\n", my_b.str);
printf("copy_my_b.str: %s\n", copy_my_b.str);
putchar('\n');
puts("But changing the array through .str is also visible in both structs:");
for (size_t i = 0; i < sizeof "oops!"; i++) {
copy_my_b.str[i] = "oops!"[i];
}
printf("my_b.str: %s\n", my_b.str);
printf("copy_my_b.str: %s\n", copy_my_b.str);
return 0;
}
Вывод программы:
Nested structs are copied:
my_a.s.c: x
copy_my_a.s.c: x
copy_my_a.str is a copy of my_a.str, which is an array:
my_a.str: my_a
copy_my_a.str: my_a
Changing the original array is not visible in the copy:
my_a.str: changed
copy_my_a.str: my_a
copy_my_b.str is a copy of my_b.str, which is a pointer to arr[0]:
my_b.str: my_b
copy_my_b.str: my_b
Changing the original array is visible in both structs:
my_b.str: changed
copy_my_b.str: changed
But changing the array through .str is also visible in both structs:
my_b.str: oops!
copy_my_b.str: oops!