C语言结构体变量之间用“=“赋值会怎么样

背景

很多用了很久C语言的同学都不知道结构体变量可以像基本类型变量那样通过赋值预算符直接赋值,比如我,今天才知道其实可以的;
看了如下两篇文章:
C语言中结构体直接赋值?
c语言结构体可以通过等号复制么?
看了人家的文章之后我想自己试下有数组或者指针成员的结构体类型变量赋值的情况,并将自己的代码和实验记录下来。

成员含数组

代码如下:

#define STR_NUM_MAX 10
typedef struct tagMyTest
{
    int a;
    char b[STR_NUM_MAX];
} MyTest;

int main()
{
    MyTest foo = {3, "good!"};
    MyTest bar;
    bar = foo;
    bar.b[2] = 'k';  // 只对bar进行修改
    printf("foo: a: %d, b: %s\n", foo.a, foo.b);
    printf("bar: a: %d, b: %s\n", bar.a, bar.b);
}

执行得到的结果为:

foo: a: 3, b: good!
bar: a: 3, b: gokd!

看得出对变量bar赋值之后,数组成员是互不影响的

成员含指针

代码如下:

#define STR_NUM_MAX 10
typedef struct tagYouTest
{
    int a;
    char *b;
} YouTest;

int main()
{
    char *t = (char *)malloc(STR_NUM_MAX);
    memset(t, 0, STR_NUM_MAX);

    strcpy(t, "good!");
    YouTest foo1 = {3, t};
    YouTest bar1;
    bar1 = foo1;
    //memcpy(&bar1, &foo1, sizeof(YouTest));  // 改为memcpy,效果是一样的
    *(bar1.b + 2) = 'k';
    printf("foo1: a: %d, b: %s\n", foo1.a, foo1.b);
    printf("bar1: a: %d, b: %s\n", bar1.a, bar1.b);
    free(t);
    t = NULL;
}

执行得到的结果为:

foo1: a: 3, b: gokd!
bar1: a: 3, b: gokd!

看得出对变量bar赋值之后,变量foo也跟着变了;而且把"="换成"memcpy"也是一样的效果;
再做一个实验,把上文中的bar1的指针成员改为指向堆内存会怎么样,因为我上面的写法它是指向的局部栈内存的;代码如下:

int main()
{
    char *t = (char *)malloc(STR_NUM_MAX);
    memset(t, 0, STR_NUM_MAX);
    char *u = (char *)malloc(STR_NUM_MAX);
    memset(u, 0, STR_NUM_MAX);

    strcpy(t, "good!");
    YouTest foo1 = {3, t};
    YouTest bar1 = {0, u};  // 把bar1改为用堆内存地址初始化
    bar1 = foo1;
    //memcpy(&bar1, &foo1, sizeof(YouTest));
    *(bar1.b + 2) = 'k';
    printf("foo1: a: %d, b: %s\n", foo1.a, foo1.b);
    printf("bar1: a: %d, b: %s\n", bar1.a, bar1.b);
    free(t);
    t = NULL;
    free(u);
    u = NULL;
}

执行得到的结果跟上面一样的,一改都改:

foo1: a: 3, b: gokd!
bar1: a: 3, b: gokd!

总结

经过以上实验可以得出,结构体类型的变量之间赋值,是将sizeof(此结构体)的一段内存的内容整体都拷贝过去,底层使用的memcpy;所以成员是数组时赋值没有问题;
而对于指针成员,因为指针变量的内容是地址,所以拷贝过去也是地址,并不是此地址的内容,所以相当于是两个指针成员指向了同一个地址,所以就会一改全改,不管你这个指针指向的是栈还是堆


版权声明:本文为hahamofu原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。