子函数内部分配内存

本文探讨了C语言中在子函数内进行内存分配的三种方法,包括直接分配并返回指针、通过指针参数分配以及使用二级指针。详细分析了为什么直接在子函数中通过指针参数分配内存可能会失败,并提供了内存释放的注意事项。最后,给出了完整的测试代码示例。

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

第二天,子函数内部分配内存


平时使用 malloc都是直接在main函数中分配,用完 free掉,这不,我又用到这个了,子函数中分配内存,这指定得用指针了!

下面一共有三种方法,其中第一种方法是无效的,来分析一下

1、内存分配

第一种void func1(Stu* p):形参是一个指针,在函数内部分配内存并给age赋值,为啥不行呢?

void func1(Stu* p)
{
	p = (Stu*)malloc(sizeof(Stu));
	p->age = 10;
	return;
}

Stu *p1 = NULL;
func1(p1);

假设指针p的地址是0x1,则其值为NULL,执行了p = (Stu*)malloc(sizeof(Stu));发生了什么?

把分配的内存的首地址放到p中,于是其值从NULL变成0x3(假设该内存的首地址为0x3),p就可以只用这块内存了。这应该就是内存分配赋值过程

假设p1地址为0x2,则其值为NULL。当执行func1(p1);时,这种参数传递叫值传递func1在函数内部会复制一个临时指针使*p=*p1,注意哦,它俩只是值相同,但地址不同,一个0x1一个0x2,函数内部使用的是临时指针p,分配后也是分配给了p,即p的值为分配内存的首地址0x3。p1地址上的值仍为NULL,所以就失败喽

下面是修改之前的解释,没有删除,可以看看

p是个指针变量,和形参int p相比,差别也只是一个放地址一个放int型数据,那你说这东西跟咱们学c语言的时候,swap函数交换a、b的值,而使用值传递有啥区别,下面Swap_err1函数肯定不能完成a、b值交换啊,人家形参的空间跟你实参有啥关系。

void Swap_err1(int a,int b)
{
	int tmp;
	tmp=a;
	a=b;
	b=tmp;
}



第二种Stu* func2(void):函数内部直接分配内存并返回,虽然是内部分配,但是它把这个指针返回给别人用了,并没有用临时指针。

Stu* func2(void)
{
	Stu* p;
	p = (Stu*)malloc(sizeof(Stu));
	p->age = 10;
	return p;
}



第三种void func3(Stu** p):见下图,为了便于描述,把一级指针二级指针定义为p1和p2,则二级指针p2就是func3的形参

有p2=&p1,则*p2 = (Stu*)malloc(sizeof(Stu));就等价于p1 = (Stu*)malloc(sizeof(Stu));,p1就指向Stu的地址了,然后就可以指针赋值了。

有人会说,按照第一种的解释,那这个二级指针不也是一个变量嘛,它也没什么特别的,为啥它可以呢?

答:二级指针p2传进func3后,咱就当它也是值传递,该函数会生成一个副本指针q,则q=p2,*q=*p2=0x1关键就在这里,q虽然是副本,但是副本里的值可是正儿八经存在的,就是指针p1的地址0x1,执行*p2 = (Stu*)malloc(sizeof(Stu));的时候,因为 *p2=0x1,这不就是在说,分配一块内存,首地址放在地址为0x1的地方!所以内存地址为0x1的地方的值就是Stu的首地址了,即p1指向了Stu了,如图1

修改前的第一种解释,随意看

再来看看第一种为啥不行,形参p1传进来,生成一个副本q,则q=p1=NULL,注意哦,它俩虽然值一样,但是q和p1的地址不一样,分配的内存存放在q的地址了,跟p1可没半毛钱关系,func1函数确实是分配了内存,但那时人家q指向的,如图2

在这里插入图片描述
                图1

在这里插入图片描述
                图2

2、内存释放

有分配就得有释放,这俩成对使用的,咱们都知道,指针指向某块空间,释放时不光要释放空间,还要把指针置为NULL

释放空间没什么好说的,如果不把p置为NULL,就成了野指针,它还是指向这块空间啊,别人再使用p访问这块空间怎么办?可能就冲突了

void func_free(dataStc** p)
{
	free(*p);
	*p = NULL;
	return;
}

3、完整测试代码

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
 
typedef struct stu
{
	int weight;
	int age;
}Stu;
 
void func1(Stu* p)
{
	p = (Stu*)malloc(sizeof(Stu));
	p->age = 10;
	return;
}
 
Stu* func2(void)
{
	Stu* p;
	p = (Stu*)malloc(sizeof(Stu));
	p->age = 10;
	return p;
}
 
void func3(Stu** p)
{
	*p = (Stu*)malloc(sizeof(Stu));
	(*p)->age = 10;
	return;
}

void func_free(Stu** p)
{
	free(*p);
	*p = NULL;
	return;
}

 
int main()
{
	Stu *p1 = NULL;
	Stu *p2 = NULL;
	Stu *p3 = NULL;
 
	func1(p1);
	p2 = func2();
	func3(&p3);
 
	if (p1 == NULL)
		printf("p1=NULL\n");
	else
		printf("p1->age:%d\n", p1->age);
    
	if (p2 == NULL)
		printf("p2=NULL\n");
	else
		printf("p2->age:%d\n", p2->age);
    
	if (p3 == NULL)
		printf("p3=NULL\n");
	else
		printf("p3->age:%d\n", p3->age);

    func_free(&p2);
    func_free(&p3);
        
	return 0;
}
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值