关于 C 中结构的一些事情——我不明白

Some things about structures in C - which I dont understand

我知道我们可以将一个结构分配给另一个结构,但我们不能将一个结构的元素分配给另一个结构。

struct Date {
    int sec;
    int min;
    int hour;
};

struct Date d1={1,2,3};
struct Date d2={10,20,4};

所以我知道它是有效的:

d1=d2;

但它不是(因为我们不能分配结构的元素)

d1.sec=d2.sec

但现在我想知道,如果一个结构的元素是另一个结构,就像这样:

struct DateTime {
struct Date d;
struct Time t;
};

struct DateTime dt1;
struct DateTime dt2;

所以如果我们这样做:

dt1=dt2;

我们是否正在将结构(日期和时间)从 dt2 分配给结构(日期和时间)到 dt1?

另外现在(当一个结构的元素是另一个结构时)我们可以分配元素,像这样:

dt1.d = dt2.d

struct 字段分配给彼此是完全正常的。您不能分配给数组,但是 structs 对此提供了一种例外,因为将一个 struct 分配给另一个会导致目标接收第一个 struct 的副本].在下面的代码中,您无法分配 copy_my_a.str = my_a.str;,因为这些是数组字段。不过你可以分配copy_my_a = my_a;

嵌套的 struct 以相同的方式复制,因此如果分配包含另一个 structstruct,则整个 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.strmy_a.str的副本,所以整个数组都被复制到了新的struct。在此处更改原始字符串不会影响复制。同样,在my_b的拷贝中,copy_my_b.strmy_b.str的拷贝,但这里拷贝的不是数组,只是一个指针。更改指向的字符串将在两个 struct 中可见,因为它们通过指针共享相同的数组。

如果您正在使用此类 struct 的副本并通过指针修改共享字符串而没有意识到该字符串是共享的,这可能会让您感到困惑,如代码中的最后一个示例所示:

#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!