C/C++中在子函数中使用malloc分配内存和free释放内存的方法

1. malloc函数

// 定义于头文件
void* maalloc (size_t size);
/* 返回值
成功时,返回指向新分配内存的指针。为避免内存泄漏,必须用 free() 或 realloc() 解分配返回的指针。
失败时,返回空指针。
*/

分配size字节的未初始化内存。
若分配成功,则返回任何拥有基础对齐的对象类型对齐的指针。
若 size 为零,则 malloc 的行为是实现定义的。例如可返回空指针。亦可返回非空指针;但不应当解引用这种指针,而且应将它传递给 free 以避免内存泄漏。

malloc 是线程安全的:它表现得如同只访问通过其参数可见的内存区域,而非任何静态存储。

令 free 或 realloc 归还一块内存区域的先前调用,同步于令 malloc 分配相同或部分相同的内存区域的调用。此同步出现于任何通过解分配函数所作的内存访问后,和任何 malloc 所作的内存访问前。所有操作每块特定内存区域的分配和解分配函数有单独全序。(C11起)

示例:

#include    
#include  
 
int main(void) 
{
    int *p1 = malloc(4*sizeof(int));  // 足以分配 4 个 int 的数组
    int *p2 = malloc(sizeof(int[4])); // 等价,直接命名数组类型
    int *p3 = malloc(4*sizeof *p3);   // 等价,免去重复类型名
 
    if(p1) {
        for(int n=0; n<4; ++n) // 置入数组
            p1[n] = n*n;
        for(int n=0; n<4; ++n) // 打印出来
            printf("p1[%d] == %d\n", n, p1[n]);
    }
 
    free(p1);
    free(p2);
    free(p3);
}

结果:

p1[0] == 0
p1[1] == 1
p1[2] == 4
p1[3] == 9

参考:C++ 参考手册

2. malloc 函数的调用方法

当使用 malloc函数 分配内存有几种常用方法,如下所示。其中,最容易想到的是第一种。事实证明这种也是错误的!

#include 
#include 
#include 
 
void func1(int* p);	// 一级指针做形参 
int* func2(void);	// 使用int* 做返回值(推荐使用这种) 
void func3(int** p);// 二级指针做形参 
 
void freeFunc(int** p)
{
	free(*p);
	*p = NULL;	// 当调用free函数后,立即将该指针指向NULL,防止出现野指针。
	return;
}

int main(int argc, const char * argv[]) {
	
	int *p1 = NULL;
	int *p2 = NULL;
	int *p3 = NULL;
	
	func1(p1);
	p2 = func2();
	func3(&p3);
 
	if (p1 == NULL)
		printf("p1=NULL\n");
	else {
		printf("*p1:%d\n", *p1);
		freeFunc(&p1);
		if (p1 == NULL)
			printf("p1=NULL\n");
		else
			printf("p1!=null\n");
	}
		
	if (p2 == NULL)
		printf("p2=NULL\n");
	else {
		printf("*p2:%d\n", *p2);
		freeFunc(&p2);
		if (p2 == NULL)
			printf("p2=NULL\n");
		else
			printf("p2!=null\n");
	}
		
	if (p3 == NULL)
		printf("p3=NULL\n");
	else {
		printf("*p3:%d\n", *p3);
		freeFunc(&p3);
		if (p3 == NULL)
			printf("p3=NULL\n");
		else
			printf("p3!=null\n");
	}
		
	return 0;
}

// 此时形参为一级指针,为临时变量,当退出该函数时,p将会被销毁
void func1(int* p)
{
	p = (int*)malloc(sizeof(int));
	*p = 10;
	return;
}
 
int* func2(void)
{
	int* p;
	p = (int*)malloc(sizeof(int));
	*p = 10;
	return p;
}
 
void func3(int** p)
{
	*p = (int*)malloc(sizeof(int));
	**p = 10;
	return;
}

执行结果如下所示:
C/C++中在子函数中使用malloc分配内存和free释放内存的方法_第1张图片

结论:只有后两种方法能正确分配内存。即直接返回内存指针,或将二级指针作为参数传入子函数。这是因为,在子函数中,内存指针只是被当做一个变量来处理的(虽然这个变量被定义为dataStc *),对其赋值后再返回,它的值当然没改变。

参考博客:在子函数中malloc分配内存和free释放内存的方法(基于C)

3. 使用free(参数) 函数 释放内存

在子函数中释放内存,很容易想到的是写个下面这样的函数释放内存:

void freeFunc(int** p)
{
	free(p);
	return;
}

因为在该方法中 p 是作为形参传入的,因为在子函数中对形参的修改不会改变子函数之外的内容,因此当该子函数退出后,该指针p的指向和调用该函数之前是相同的,因此p并没有被置为NULL,此时指针p成为了野指针(不同于空指针),当再次调用该指针指向的内容时,可能会造成不可预知的后果。

因此,释放内存有以下两种方法:

  1. 当调用func_free(p)函数之后,立即将其置为NULL
freeFunc(p);
p = NULL;
// 当令p为NULL后,即可使用if语句进行判断
if (p == NULL) {
	...
} else {
	...
}
  1. 在free后,将p赋为NULL。由于这里又将输入变量p修改了,因此仍然需要传递二级指针。正确的代码为:
void freeFunc(int** p)
{
	free(*p);
	*p = NULL;	// 当调用free函数后,立即将该指针指向NULL,防止出现野指针。
	return;
}

你可能感兴趣的:(C/C++,c++,c语言,开发语言)