簡體   English   中英

在C中具有指針作為成員的結構的memcpy

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM