Ale*_*x H 0 c struct reference shallow-copy
编辑:修复了评论中提到的错误并且问题仍然存在,所以这个问题并不是真正的重复 - 只是我的 C 编程技能在这一点上不是很好,下面给出的解决方案回答了问题并且没有t 解决局部变量错误。
警告:对 C 相当陌生
我知道当我们将一个结构体分配给另一个结构体时,会执行一个浅拷贝。但是,我无法理解为什么会发生这种情况的结果:
假设以下我尝试初始化一个结构体,使用赋值运算符将其称为 Type2 结构体的 Type1 成员,那么应该已经执行了浅拷贝。这意味着复制了 Type2 成员的地址:
typedef struct {
uint8_t someVal;
} Type1
typedef struct {
Type1 grid[3][3];
} Type2
//Constructor for Type2 "objects"
Type2 Type2_Constructor(void) {
Type1 empty = {.value = o}
Type2 newType2;
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++) {
//Shallow copy empty struct
newType2.grid[i][j] = empty;
}
return newType2;
}
int main (void) {
Type2 type2Object = Type2_Constructor();
for (int i = 0; i < 3; i ++)
for (int j = 0; j < 3; j++){
printf("%u",type2OBject.grid[i][j].value);
printf("\n\r%p\n\r",&(type2Object.grid[i][j].value));
printf("\n\r");
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我希望看到:
0
0xMemoryLocation
0
0xMemoryLocation
0
0xMemoryLocation
.
.
.
Run Code Online (Sandbox Code Playgroud)
事实上,我看到的是这样的,地址增加了 2 个字节:
0
0x7fff57eaca18
0
0x7fff57eaca1a
0
0x7fff57eaca1c
0
0x7fff57eaca1e
0
0x7fff57eaca20
.
.
.
Run Code Online (Sandbox Code Playgroud)
既然浅拷贝应该是直接拷贝地址,为什么 &(type2Object.grid[i][j].value) 不一样呢?
感谢所有的帮助!
想想指针。如果您有两个相同类型的指针变量,让我们调用它们a
和b
。如果你这样做a = b
,你做一个浅拷贝,只复制实际指针b
来a
,而不是内存b
点。这意味着a
和 都b
指向同一个内存。
深拷贝会将b
指向的内容复制到一些新分配的内存中。深拷贝会导致a
并b
指向不同的内存。
以你的结构:
typedef struct {
Type1 grid[3][3];
} Type2
Run Code Online (Sandbox Code Playgroud)
如果你有
Type2 a;
Type2 b = { ... }; // Some initialization, not relevant exactly what
Run Code Online (Sandbox Code Playgroud)
然后是一个任务
a = b; // Copy structure b to a
Run Code Online (Sandbox Code Playgroud)
这是一个浅拷贝。但是因为结构体的数据是一个数组所以整个数组都被复制了,看起来像一个深拷贝。
如果结构中有指针,则只会复制指针。另一个示例,具有新结构:
typedef struct {
char *pointer;
} Type3;
Type3 a;
Type3 b = { "abcd" };
a = b;
printf("a.pointer = %s\n", a.pointer);
printf("b.pointer = %s\n", b.pointer);
Run Code Online (Sandbox Code Playgroud)
上面的代码将打印两个相同的字符串a.pointer
和b.pointer
。但它是同一个指针。如果我们添加一个新的指针打印输出:
printf("a.pointer = %p\n", (void *) a.pointer);
printf("b.pointer = %p\n", (void *) b.pointer);
Run Code Online (Sandbox Code Playgroud)
以上两行将在赋值后打印相同的值。两个指针都指向同一个内存。这是一个浅拷贝。
此外,像上面显示的那样的结构赋值与执行 eg 没有什么不同
memcpy(&a, &b, sizeof a);
Run Code Online (Sandbox Code Playgroud)
实际上,我认为您的困惑在于,您认为引用另一个结构就像 Java、C# 或 C++ 中的引用,而实际上并非如此。
结构中grid
数组中的每个元素都是该Type2
结构的唯一实例Type1
。并且作为唯一实例,它们都占用不同的内存,导致您打印的地址都不同。
当你做
newType2.grid[i][j] = empty;
Run Code Online (Sandbox Code Playgroud)
您将empty
结构实例的内容复制到结构实例中newType2.grid[i][j]
。使用memcpy
上面显示的调用,赋值所做的实际上是
memcpy(&newType2.grid[i][j], &empty, sizeof newType2.grid[i][j]);
Run Code Online (Sandbox Code Playgroud)
它对 的内容进行按位复制empty
。
关于指针和数组之间的区别,请考虑以下定义:
int a[] = { 1, 2, 3, 4 };
int *p = a;
Run Code Online (Sandbox Code Playgroud)
在内存中它看起来像这样:
+---+---+---+---+ | 1 | 2 | 3 | 4 | +---+---+---+---+ ^ | +---+ | p | +---+
也就是说,您的数组及其内容占用的空间足以容纳四个int
值。然后你有指向p
数组中第一个元素的指针(数组衰减到指向它们的第一个元素的指针,在a
上面的数组的情况下,a
用作指针等于&a[0]
)。