C语言中free()函数释放struct结构体中的规律

本文探讨了在C语言中,使用结构体时free()函数的行为。通过对比两种不同的结构体声明方式,分析了free()函数对内存的影响,特别是在处理指针变量时的区别。实验表明,free()仅释放指针本身占用的内存,而非指针所指向的内容,这对避免内存泄漏有重要意义。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

并不是什么新鲜的事情,不过值得注意。
首先我们知道,在使用struct来定义并声明一个变量时,将会自动划分出一个连续的储存空间(虽然根据某些对齐原则会出现内存间隙,但是大体上来说还是连续的)
这一块连续空间将会包括结构体中的其他变量所需要的内存。就像这样。
这是一个名为X的结构体变量
这是一个名为X的结构体变量
而free()函数的作用是对动态分配的内存进行释放,这也就意味着当使用free函数清空一个结构体时,只会清空这个大框里的内存,而不会对a,b,c,d指向的内存进行清理。
当然,一般来说直接定义变量于结构体内会更加方便。
但是考虑一下两种声明

struct stuff{
	char home[10];
	int num;
	char name[10];
};

struct stuff{
	char *home;
	int num;
	char name[10];
};

两者的不同在于,第二种使用的是char指针,所以进行gets(),或者初始化时,*home将会把值储存在常量区。

那么我们考虑一下以下代码
目的是为了查看,在free前后,*home与name的变化

#include <stdio.h>
#include <string.h>
struct stuff{
	char *home;
	int num;
	char name[10];
};

int main(void){
	struct stuff *TOM=(struct stuff *)malloc(sizeof(struct stuff));
	
	TOM->home="LONDON";
	TOM->num=201;
	strcpy(TOM->name,"TOM");
	
	char *p1=TOM->home;
	char *p2=TOM->name;

	printf("home=%s pointer of home%p  name=%s\n",TOM->home,TOM->home,TOM->name);
	free(TOM);
	printf("home=%s pointer of home%p  name=%s\n",p1,p1,p2);

	return 0;
}

运行结果:
home=LONDON pointer of home0000000000404000  name=TOM
home=LONDON pointer of home0000000000404000  name=

嗯,我们可以发现home的值仍然保存着,而name的内存被释放。
综上我们可以得出什么结论呢?
free()只能释放指针所指向的那片内存。也就是说,如果我们不断地声明第二种类型的结构体的话,即使调用free()也会造成内存的浪费。最明显的应该是体现在链表类结构。
所以如果要进行插入与删除的操作的话还是考虑第一种结构体靠谱。

2018.10.26
小白刚刚学到结构体,故记之

<think>嗯,用户问的是如何在C语言函数中传递结构体数据。这个问题看起来涉及到结构体的定义、函数参数的传递方式,可能还有指针的使用。首先,我需要回忆C语言结构体的基本知识。结构体是用户自定义的数据类型,可以将不同类型的数据组合在一起。比如,定义一个学生的结构体,包含姓名和年龄。 然后,函数传参方面,C语言有值传递和地址传递两种方式。对于结构体这样的复合数据类型,如果直接传递结构体变量,会发生值拷贝,也就是形参是实参的一个副本,这样在函数内部修改形参不会影响实参。这可能会消耗较多的内存,尤其是结构体较大的时候,影响性能。所以通常建议使用指针传递结构体,这样可以避免复制整个结构体的开销,并且允许函数修改原始数据。 接下来,我需要考虑用户可能需要示例代码。应该展示两种传参方式:传值和传指针。例如,定义一个结构体,然后写两个函数,一个接受结构体变量,另一个接受结构体指针。在传值的函数中修改结构体的字段,不会影响原变量;而传指针的函数则可以修改原结构体的内容。 还要注意引用的资料,用户提供的引用中有提到结构体作为函数参数和返回值的情况。例如,引用[4]提到结构体变量作为实参传递时,会开辟同样内存,修改形参不影响实参。而引用[2]则提到某些编译器不允许直接返回结构体,可能需要用指针。因此,在示例中应该展示传指针的方法,并说明返回结构体指针的情况。 可能还需要提到动态内存分配,比如在函数内部创建结构体并返回指针,但要注意内存管理,避免内存泄漏。此外,const关键字的使用,可以保护结构体数据不被意外修改,这也是一个值得注意的点。 用户可能还关心效率问题,特别是结构体较大时,传递指针更高效。需要解释为什么值传递会有性能问题,而指针传递更优。同时,可能存在的风险,比如指针传递可能导致原数据被修改,这时候可以用const来限制。 最后,生成相关问题,可能涉及结构体传参的优化、不同传递方式的区别、返回值处理,以及内存管理的问题。这些都需要根据已有的知识点来设计,帮助用户进一步学习。</think>### C语言函数结构体数据传递的三种方式 根据C语言结构体传参特性,以下是三种典型方式及示例代码: #### 方式一:值传递(发生完整拷贝) ```c #include <stdio.h> typedef struct { char name[20]; int age; } Student; void modify_by_value(Student s) { s.age += 1; // 修改副本数据 printf("函数内年龄: %d\n", s.age); // 输出:21 } int main() { Student stu = {"张三", 20}; modify_by_value(stu); printf("主函数年龄: %d\n", stu.age); // 输出:20(原值未变)[^4] return 0; } ``` #### 方式二:指针传递(推荐方式) ```c void modify_by_pointer(Student* p) { p->age += 1; // 修改原始数据 strcpy(p->name, "李四"); } int main() { Student stu = {"张三", 20}; modify_by_pointer(&stu); printf("修改后姓名: %s,年龄: %d\n", stu.name, stu.age); // 输出:李四,21 return 0; } ``` #### 方式三:动态内存传递(需手动释放) ```c Student* create_student(const char* name, int age) { Student* p = (Student*)malloc(sizeof(Student)); strcpy(p->name, name); p->age = age; return p; // 返回堆内存指针[^2] } int main() { Student* pStu = create_student("王五", 22); printf("动态创建:%s %d\n", pStu->name, pStu->age); // 输出:王五 22 free(pStu); // 必须释放内存 return 0; } ``` ### 关键特性对比 | 传递方式 | 内存开销 | 修改原数据 | 适用场景 | |----------|----------|------------|----------| | 值传递 | 复制整个结构体 | 否 | 小型结构体只读访问 | | 指针传递 | 4/8字节指针 | 是 | 中大型结构体读写操作 | | 动态传递 | 堆内存分配 | 是 | 需要跨函数生命周期保存数据 | ### 最佳实践建议 1. 优先使用`const Student*`指针传参保护数据:`void read_only(const Student* p)` 2. 超过16字节的结构体必须使用指针传递提升性能 3. 动态创建的结构体必须配对使用`malloc/free` 4. 使用`typedef`简化结构体类型声明(如示例中的`Student`)[^1]
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值