平时使用
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;
}