关于 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
字段分配给彼此是完全正常的。您不能分配给数组,但是 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
中可见,因为它们通过指针共享相同的数组。
如果您正在使用此类 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!
我知道我们可以将一个结构分配给另一个结构,但我们不能将一个结构的元素分配给另一个结构。
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
字段分配给彼此是完全正常的。您不能分配给数组,但是 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
中可见,因为它们通过指针共享相同的数组。
如果您正在使用此类 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!