如果这是一个愚蠢的问题,请不要投票给我,我只是想了解。
我有一个带有一些指针作为成员的结构,我正在尝试做memcpy而且我被建议我不应该在这种情况下使用memcpy作为memcpy做一个浅拷贝(意思是它复制指针)而是深拷贝(意思是复制什么指针指向)。
但我不确定为什么它在以下程序中没有任何区别: 请查看代码和输出,请解释为什么在这种情况下它不是浅层副本?
#include <stdio.h>
#include <malloc.h>
#include <string.h>
struct student {
char *username;
char *id;
int roll;
};
void print_struct(struct student *);
void print_struct_addr(struct student *);
void changeme(struct student *);
int main (void) {
struct student *student1;
char *name = "ram";
char *id = "200ABCD";
int roll = 34;
student1 = (struct student *)malloc(sizeof(struct student));
student1->username = name;
student1->id = id;
student1->roll = roll;
print_struct_addr(student1);
print_struct(student1);
changeme(student1);
print_struct(student1);
print_struct_addr(student1);
return 0;
}
void print_struct(struct student *s) {
printf("Name: %s\n", s->username);
printf("Id: %s\n", s->id);
printf("R.No: %d\n", s->roll);
return;
}
void print_struct_addr(struct student *s) {
printf("Addr(Name): %x\n", &s->username);
printf("Addr(Id): %x\n", &s->id);
printf("Addr(R.No): %x\n", &s->roll);
return;
}
void changeme(struct student *s) {
struct student *student2;
student2->username = "someone";
student2->id = "200EFGH";
student2->roll = 35;
print_struct_addr(student2);
memcpy(s, student2, sizeof(struct student));
student2->username = "somebodyelse";
return;
}
输出:
Addr(Name): 9b72008
Addr(Id): 9b7200c
Addr(R.No): 9b72010
Name: ram
Id: 200ABCD
R.No: 34
Addr(Name): fa163c
Addr(Id): fa1640
Addr(R.No): fa1644
Name: someone
Id: 200EFGH
R.No: 35
Addr(Name): 9b72008
Addr(Id): 9b7200c
Addr(R.No): 9b72010
如果memcpy执行浅拷贝,那么student1-&gt;用户名怎么不是“somebodyelse”。
请解释在哪种情况下,这段代码可能会产生问题,我想在main()中的changeme()调用之后在student1中找到student2信息,之后应该能够使用这个修改过的student1数据。
我被建议不要在这里使用memcpy(),但似乎工作正常。
由于
这是修改后的代码:但我仍然没有看到浅拷贝的概念:
#include <stdio.h>
#include <malloc.h>
#include <string.h>
struct student {
char *username;
char *id;
int roll;
};
void print_struct(struct student *);
void print_struct_addr(struct student *);
void changeme(struct student *);
int main (void) {
struct student *student1;
char *name = "ram";
char *id = "200ABCD";
int roll = 34;
student1 = malloc(sizeof(*student1));
student1->username = name;
student1->id = id;
student1->roll = roll;
print_struct_addr(student1);
print_struct(student1);
changeme(student1);
print_struct(student1);
print_struct_addr(student1);
return 0;
}
void print_struct(struct student *s) {
printf("Name: %s\n", s->username);
printf("Id: %s\n", s->id);
printf("R.No: %d\n", s->roll);
return;
}
void print_struct_addr(struct student *s) {
printf("Addr(Name): %x\n", &s->username);
printf("Addr(Id): %x\n", &s->id);
printf("Addr(R.No): %x\n", &s->roll);
return;
}
void changeme(struct student *s) {
struct student *student2;
student2 = malloc(sizeof(*s));
student2->username = strdup("someone");
student2->id = strdup("200EFGH");
student2->roll = 35;
print_struct_addr(student2);
memcpy(s, student2, sizeof(struct student));
student2->username = strdup("somebodyelse");
free(student2);
return;
}
答案 0 :(得分:11)
此:
struct student *student2;
student2->username = "someone";
student2->id = "200EFGH";
student2->roll = 35;
写入未分配的内存,调用未定义的行为。在写作之前,您需要确保student2
指向某个有效的地方。
要么分配它,要么使用堆栈上的实例,因为你还是要从它复制。
当然,初始化student2
然后用它覆盖s
的整个业务不必要地复杂化,您应该直接修改s
。
另外,这个:
student1 = (struct student *)malloc(sizeof(struct student));
更好用C语写成:
student1 = malloc(sizeof *student1);
这将删除pointless (and potentially dangerous) cast,并确保该类型的大小正确,将程序员检查的依赖项替换为编译器处理的依赖项。
第三,这是C程序员开始没有意识到你可以分配结构的经典“症状”。所以,而不是
memcpy(s, student2, sizeof *s);
你可以写:
*s = *student2;
让编译器正确。这可能是性能上的胜利,因为结构可以包含很多填充,分配可以知道而不是复制,但memcpy()
不能忽略。
答案 1 :(得分:2)
它完全有效是侥幸。在changeme()
函数中,您正在为student2
创建一个新指针,但您没有为其分配内存。
其次,在同一功能中,您将更改为student2
后将其复制到s
。
浅拷贝并不意味着副本中的任何指针都是共享的 - 这意味着指针本身的值也会被复制。因此,当您在student2->username
之后更改memcpy
时,它不会更改s->username
的值。
随着您的进步,您还需要更加谨慎地在这些结构中分配内存。 AFAICR,如果使用常量文字字符串,则指针将指向程序内存空间中的一块静态初始化数据。然而,更严格的设计会为这些元素malloc()
和free()
动态记忆。如果您需要静态初始值,则可以使用strdup()
或类似于复制从静态空间到堆内存的字符串。
答案 2 :(得分:0)
在复制后,您将用户名设置为“somebodyelse”。这只会更改函数“changeme()”中的本地副本。尝试打印出<2> “changeme()”中的student2 ,你会看到我的意思。