C语言【动态内存管理 后篇】

动态内存管理 后篇

  • 经典例题
    • ‍♂️题目1
    • ‍♂️题目2
    • ‍♂️题目3
    • ‍♂️题目4
  • C/C++程序的内存开辟

前面的一篇文章动态内存管理 前篇,我们已经了解过了动态内存管理的相关信息,接下来,让我们来一起来踩“坑”。当然,今天的踩坑,是为了面试不踩坑哦

经典例题

‍♂️题目1

void GetMemory(char* p)
{
	p = (char*)malloc(100);
}

void Test(void)
{
	char* str = NULL;
	GetMemory(str);
	strcpy(str, "hello world");
	printf(str);
}

int main()
{
	Test();
	return 0;
}

我们来找一找上面的代码有什么问题?
好了,不绕弯子了,来看看到底错了哪些地方

  1. GetMemory(str)中是传值,而不是传址。当出了GetMemory函数,p指向的地址发生了变化,但str依旧是NULL,然后就进入了strcpy函数,这样就形成了非法访问内存(NULL是操作系统的,我们用户没有权限访问)
  2. 在GetMemory函数内部,动态申请了内存,直到程序结束也没有释放内存,这样会导致内存泄漏


printf(str)???这样写也能行???为什么吗??
我们来看看下面的代码:

#include

int main()
{
	char ptr[] = "hehehe";
	char* p = "hehehe";

	printf("%s\n", ptr);
	printf("%s\n", p);
	printf("hehehe");
	return 0;
}

//运行结果:
*****
hehehe
hehehe
hehehe
*****

纳尼??这是为什么呢?
在解释这个问题前,我们先想一下printf的第一个参数是什么?答案是:必须是指针。那就意味printf(“hehehe”)里面的“hehehe”不是我们所看到的那样,而是一个地址。那么它是谁的地址?下面的代码会给我们答案:

#include

int main()
{
	char* p = "hehehe";
	
	printf("%p\n", "hehehe");
	printf("%p\n", p);

	return 0;
}

//运行结果:
*****
00AF7B54
00AF7B54

*****

奥,那我就明白了:ptr指针指向的是字符串的第一个字符,那么运行结果告诉我们,printf(“hehehe”)里面传的就是第一个字符的地址。

修改:

//修改后
// #include
#include

void GetMemory(char** p)  //二级指针接收
{
	*p = (char*)malloc(100);  //解引用就是一级指针
}

void Test(void)
{
	char* str = NULL;
	GetMemory(&str);   //传址
	strcpy(str, "hello world");
	printf(str);

	//释放空间
	free(str);
	str = NULL;

}

int main()
{
	Test();
	return 0;
}

‍♂️题目2

#include
#include

char* GetMemory(void)
{
	char p[] = "hello world";
	return p;
}

void Test(void)
{
	char* str = NULL;
	str = GetMemory();
	printf(str);
}

int main()
{
	Test();
	return 0;
}

这个除了没有释放空间就没有其他的问题了吧。
但真相是这样吗??
让我们看看运行结果是什么吧

嗯??没释放空间也不会导致这种结果吧…


让我们来全面的分析一下吧:

  1. 关于函数返回信息的问题,这一类问题也叫作“返回栈空间地址的问题”:函数返回地址,地址信息存在,但函数内部的栈空间就还给操作系统了,操作系统可以把此空间作为别的变量的地址
  2. 函数动态申请空间,直到程序结束也没有释放掉空间,会导致内存泄漏

返回栈空间地址的问题???这是什么啊??

栈区主要存放运行函数而分配的局部变量、函数参数、返回数据、返
回地址等

那我们就明白了为什么叫做返回栈空间地址,那问题呢??
当函数调用结束(出了函数),在函数里面的空间就会返还给操作系统,我们用户没有操作权限。操作系统会把这个空间重新分配给其他变量,这样我们就不得而知了

修改:

#include
#include

char* GetMemory(void)
{
	char* p = "hello world";  //将第一个字符的地址传给p

	//static char p[]="hello world";    //被static修饰的变量存放在数据段(静态区),
	                                   //数据段的特点是在上面创建的变量,直到程序结束才销毁

	return p;
}

void Test(void)
{
	char* str = NULL;
	str = GetMemory();
	printf(str);
	
	//释放
	free(str);
	str = NULL;
}

int main()
{
	Test();
	return 0;
}

‍♂️题目3

#include
#include

void GetMemory(char** p, int num)
{
	*p = (char*)malloc(num);
}

void Test(void)
{
	char* str = NULL;
	GetMemory(&str, 100);
	strcpy(str, "hello");
	printf(str);
}

int main()
{
	Test();
	return 0;
}

这个就很简单了,没有释放空间

修改:

#include
#include

void GetMemory(char** p, int num)
{
	*p = (char*)malloc(num);
}

void Test(void)
{
	char* str = NULL;
	GetMemory(&str, 100);
	strcpy(str, "hello");
	printf(str);

	//释放
	free(str);
	str = NULL;
}

int main()
{
	Test();
	return 0;
}

‍♂️题目4

#include
#include

void Test(void)
{
	char* str = (char*)malloc(100);
	strcpy(str, "hello");
	free(str);
	if (str != NULL)
	{
		strcpy(str, "world");
		printf(str);
	}
}

int main()
{
	Test();
	return 0;
}

这个问题是啥?感觉没问题啊??不会是str没有置空吧?
哈哈,其实这个问题很隐蔽,不注意看是看不出来的

free的动作是将该内存块返还给操作系统,我们没有操作权限,故str是野指针,造成了非法访问内存

修改:

#include
#include

void Test(void)
{
	char* str = (char*)malloc(100);
	strcpy(str, "hello");
	free(str);
	str = NULL;  //在这里置空,也是为了符合下面判断的逻辑
	            //那么也不会进入if里面造成非法访问

	if (str != NULL)
	{
		strcpy(str, "world"); 
		printf(str);
	}
}

int main()
{
	Test();
	return 0;
}

C/C++程序的内存开辟

在在这里,终于把C语言中的动态内存管理的知识讲解完了。想必大家大概的框架是有的,但是对一些专业术语跟底层逻辑不是很清楚。比如:什么是堆区,什么又是栈区?内存中的每一个区域的作用是什么?等等

C语言【动态内存管理 后篇】_第1张图片
C/C++程序内存分配的几个区域:

  1. 栈区(stack):在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结
    束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是
    分配的内存容量有限。 栈区主要存放运行函数而分配的局部变量、函数参数、返回数据、返
    回地址等。
  2. 堆区(heap):一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。分
    配方式类似于链表。
  3. 数据段(静态区)(static)存放全局变量、静态数据。程序结束后由系统释放。
  4. 代码段:存放函数体(类成员函数和全局函数)的二进制代码。字符串常量就在其中
  • 实际上普通的局部变量是在栈区分配空间的,栈区的特点是在上面创建的变量出了作用域就销毁。
    但是被static修饰的变量存放在数据段(静态区),数据段的特点是在上面创建的变量,直到程序
    结束才销毁。所以生命周期变长。

C语言【动态内存管理 后篇】_第2张图片
码文不易,各位看官一键三连哦
各位的鼓励与支持是我前进最大的动力

你可能感兴趣的:(c语言,c++,算法)