为什么struct shallow副本不起作用?

时间:2016-04-25 10:50:35

标签: c struct

我正在使用以下代码测试struct的浅层副本:

#include "stdio.h"
#include "conio.h"

int main() {

    struct str {
        char * name;
        int value;
    };

    struct str str_1 = {"go", 255};
    struct str str_2;

    str_2 = str_1;

    str_1.name = "back";

    printf("%s\n",str_1.name);
    printf("%s\n",str_2.name);

    printf("\n");
    system("pause");
    return 0;
}

我预计结果应为:

back 
back

但它是:

back
go

修改:我预计会因为浅版,str_1.namestr_2.name应始终指向相同位置。

编辑:通过动态分配,我得到了我的预期:

#include <stdio.h>
#include <conio.h>
#include <string.h>

int main() {

    struct str {
        char * name;
        int value;
    };

    struct str str_1; 
    struct str str_2;

    str_1.name = (char*) malloc(5);
    strcpy(str_1.name,"go");

    str_2 = str_1;

    strcpy(str_1.name,"back");

    printf("%s\n",str_1.name);
    printf("%s\n",str_2.name);

    printf("\n");
    system("pause");
    return 0;
}

结果是:

back 
back

我在这里误解了什么?

3 个答案:

答案 0 :(得分:2)

str_2 = str_1; 采取浅层副本。

并不意味着对namestr_1所指向的任何后续更改都将自动反映在str_2中。< / p>

(实际上,您应该使用const char*作为字符串类型,因为您要分配只读字符串文字)。

答案 1 :(得分:2)

拿一张纸慢慢地画出你认为在每一步发生的事情,这应该变得清晰。

让我们画出struct str

---------------------
| const char * name |
---------------------
| int value         |
---------------------

让我们在地址0xabcdef10表示一个字符串,如下所示:

--0xabcdef10---------------------
|  "string\0"                   |
---------------------------------

因此,当我们初始化str_1时,我们需要一些内存位置来保持&#34; go&#34;,让我们调用0xaaaaaa00

--0xaaaaaa00---------------------
|  "go\0"                       |
---------------------------------

然后我们用指向它的指针初始化str_1

struct str str_1 = {"go", 255};

--str_1---------------------------
| const char * name = 0xaaaaaa00 |
----------------------------------
| int value = 255                |
----------------------------------

现在我们采用str_1的浅表副本,并将其称为str_2

--str_2---------------------------
| const char * name = 0xaaaaaa00 |
----------------------------------
| int value = 255                |
----------------------------------

接下来我们执行str_1.name = "back";。和以前一样,我们首先要创建新字符串。让我们把它放在0xbbbbbb00

--0xbbbbbb00---------------------
|  "back\0"                     |
---------------------------------

然后我们将其分配给str_1.name,所以str_1现在看起来像:

--str_1---------------------------
| const char * name = 0xbbbbbb00 |
----------------------------------
| int value = 255                |
----------------------------------

请注意,我们尚未更改str_2

因此,当我们查看我们的最终&#34;记忆&#34;时,我们会看到:

--0xaaaaaa00---------------------
|  "go\0"                       |
---------------------------------
  ....

--0xbbbbbb00---------------------
|  "back\0"                     |
---------------------------------
  ....
--str_1---------------------------
| const char * name = 0xbbbbbb00 |
----------------------------------
| int value = 255                |
--str_2---------------------------
| const char * name = 0xaaaaaa00 |
----------------------------------
| int value = 255                |
----------------------------------

所以str_1指向新字符串,str_2指向旧字符串。

如果你描述为动态,你永远不会更新结构中的指针,你可以通过相同的练习来描绘在这种情况下内存会发生什么。

答案 2 :(得分:1)

str_2 = str_1;制作了结构本身的硬拷贝。例如,value成员对于每个结构都是唯一的。

但是你得到了任何指针成员的软拷贝,因为拷贝不会影响任何指针的指向数据。这意味着在复制之后,namestr_1的{​​{1}}指针指向文字str_2

然后"go"仅在str_1.name = "back";指向的地方发生变化。它不会改变str_1.name指向的地方。

当您使用malloc和strcpy时,您可以更改指向的数据并获取所有内容的完整硬拷贝。