c语言怎么free结构体,C语言 结构体复制后free的问题

结构体赋值和指针赋值是两个不同的概念。在你的例子里,s1, s2 都是指针,那么 s2 = s1是指针赋值,赋值之后s2,s1就之指向同样的内存地址,所以会导致访问已经free的内存。结构体赋值是会把各个member的值copy的。

补充一下:

我们可以看看编译器是怎么实现结构体赋值的。比如:

#include

typedef struct A {

int x;

int y;

} A;

int main() {

A a = {1, 2};

A aa = a;

printf("aa.x = %d\n", aa.x);

}

下面是clang生成的llvm IR.

%struct.A = type { i32, i32 }

@main.a = private unnamed_addr constant %struct.A { i32 1, i32 2 }, align 4

@.str = private unnamed_addr constant [11 x i8] c"aa.x = %d\0A\00", align 1

; Function Attrs: nounwind uwtable

define i32 @main() #0 {

%a = alloca %struct.A, align 4

%aa = alloca %struct.A, align 4

%1 = bitcast %struct.A* %a to i8*

call void @llvm.memcpy.p0i8.p0i8.i64(i8* %1, i8* bitcast (%struct.A* @main.a to i8*), i64 8, i32 4, i1 false)

%2 = bitcast %struct.A* %aa to i8*

%3 = bitcast %struct.A* %a to i8*

call void @llvm.memcpy.p0i8.p0i8.i64(i8* %2, i8* %3, i64 8, i32 4, i1 false)

%4 = getelementptr inbounds %struct.A, %struct.A* %aa, i32 0, i32 0

%5 = load i32, i32* %4, align 4

%6 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str, i32 0, i32 0), i32 %5)

ret i32 0

}

这里有两个llvm.memcpy, 第一个是给a赋值,第二个是给aa赋值。所以C编译器仅仅是做了一个memcpy,把a的内容拷贝到aa所在的内存。所以相互兼容的结构体间可以这样赋值,但是这样做有没有意义就要看具体情况了吧。

你说的第二种情景,其实就是结构体赋值,因为new_b2->stra不是指针。所以不会访问free掉的内存。

下面的例子更可以说明问题:

typedef struct A {

int x;

int y;

} A;

int main() {

A a1 = {1, 2};

A a2 = a1;

A *s1 = (A *) malloc(sizeof(A));

A *s2 = (A *) malloc(sizeof(A));

*s1 = a1;

*s2 = *s1;

printf("s2->x = %d\n", s2->x);

s2 = s1;

free(s1);

printf("s2->x = %d\n", s2->x);

}

再看*s2 = *s1 和 s2 = s1LLVM代码:

%11 = load %struct.A*, %struct.A** %s2, align 8

%12 = load %struct.A*, %struct.A** %s1, align 8

%13 = bitcast %struct.A* %11 to i8*

%14 = bitcast %struct.A* %12 to i8*

call void @llvm.memcpy.p0i8.p0i8.i64(i8* %13, i8* %14, i64 8, i32 4, i1 false)

%15 = load %struct.A*, %struct.A** %s2, align 8

%16 = getelementptr inbounds %struct.A, %struct.A* %15, i32 0, i32 0

%17 = load i32, i32* %16, align 4

%18 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([12 x i8], [12 x i8]* @.str, i32 0, i32 0), i32 %17)

%19 = load %struct.A*, %struct.A** %s1, align 8

store %struct.A* %19, %struct.A** %s2, align 8

%20 = load %struct.A*, %struct.A** %s1, align 8

%21 = bitcast %struct.A* %20 to i8*

call void @free(i8* %21) #1

%22 = load %struct.A*, %struct.A** %s2, align 8

%23 = getelementptr inbounds %struct.A, %struct.A* %22, i32 0, i32 0

%24 = load i32, i32* %23, align 4

%25 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([12 x i8], [12 x i8]* @.str, i32 0, i32 0), i32 %24)

*s2 = *s1赋值的时候,LLVM是把s1指向的内容memcpy到s2指向的内存。这里LLVM要先derefence这两个指针。而s2 = s1赋值的时候不用memcpy而是直接把s1的内容store到s2.

希望这个例子能说明这两种赋值的区别。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值