[英]memcpy of structure having pointers as members in C
我有一個結構,有一些指針作為成員,我正在嘗試做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-> username怎么不是“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;
}
這個:
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);
這將刪除無意義(並且可能是危險的)強制轉換 ,並確保該類型的大小是正確的,將編程器檢查的依賴項替換為編譯器處理的依賴項。
第三,它是一個典型的“症狀”的開始C程序員沒有意識到你可以分配結構。 所以,而不是
memcpy(s, student2, sizeof *s);
你可以寫:
*s = *student2;
讓編譯器做正確的事情。 這可能是性能上的勝利,因為結構可以包含很多填充,分配可以知道並且不能復制,但memcpy()
不能忽略。
它的工作原理是僥幸。 在你的changeme()
函數中,你正在為student2
創建一個新的指針,但你沒有為它分配內存。
其次,在同一個函數中,您將student2
復制到s
后進行更改。 淺拷貝並不意味着副本中的任何指針都是共享的 - 這意味着指針本身的值也會被復制。 因此,當您在memcpy
之后更改student2->username
,它不會更改s->username
的值。
隨着您的進步,您還需要更加謹慎地在這些結構中分配內存。 AFAICR,如果使用常量文字字符串,則指針將指向程序內存空間中的一塊靜態初始化數據。 然而,更嚴格的設計會為這些元素free()
malloc()
和free()
動態內存。 如果您需要靜態初始化值,則可以使用strdup()
或類似方法將字符串從靜態空間復制到堆內存中。
復制后將用戶名設置為“somebodyelse”。 這只會更改函數“changeme()”中的本地副本。 嘗試在 “changeme()”中打印出student2,你會明白我的意思。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.