C语言——动态内存管理

142 阅读3分钟

1 为什么会存在动态内存分配

有时候需要的空间大小只有在程序运行时才能知道。例:

    char name[10] = { 0 };
    scanf("%s",name);
    //1 若用户只输入了lily,只需用5个空间来存储该名字(包括'\0'),就浪费了5 byte
    //2 若用户输入的内容超过数组大小,也会产生问题

所以需要动态的内存管理。

2 动态内存管理的相关函数

malloc函数

原型:

void* malloc(size_t size)

功能:

向堆区(内存中专门用来动态内存管理的空间)申请size个字节的空间,

申请成功返回该空间的起始地址(void*类型);.

申请失败返回NULL(没有足够空间).

使用:

申请示例:

        int* pa = (int*)malloc(4*sizeof(int));
        //申请16个字节的空间,来存放整数
	//但由于返回的是void*类型指针,所以强制类型转换成(int*),用int*指针类型接收
	if (pa == NULL)
	{
		printf("%s", strerror(errno));//判断是否是空指针,并打印出空指针原因
		return 0;
	}

使用示例:

        //通过pa指针变量来使用堆区申请的空间
	for (int i = 0; i < 4; i++)
	{
		//让这块空间存放 0 1 2 3
		*(pa + i) = i;   //或pa[i] = i
	}
	for (int i = 0; i < 4; i++)
	{
		printf("%d ", *(pa + i));
	}

注意:

(1)当这块空间使用完后,要使用free函数释放这块空间!!!

(2)如果size为0,则是标准未定义的行为

(3)返回值的类型是void*,具体要怎么使用这块空间取决于使用者。

free函数

原型:

void free(void* ptr) //无返回值

功能:

用来释放动态开辟的内存空间,ptr是之前动态开辟的空间的首地址。

为什么要释放?

开辟的动态内存若使用完且不需要再使用,不free:

程序结束,动态申请的内存由操作系统自动回收;

程序不结束(一直运行或长时间运行),申请的内存不使用,就会导致内存泄漏(空间浪费)。

所以要养成用完动态内存后free的习惯

使用:

使用示例:(接上面代码)

        free(pa);//释放完这部分动态内存后,这部分空间属于操作系统,不能非法访问
	pa = NULL;//但pa指针仍然指向这里的首地址,pa会变成野指针,所以free后应给它赋空指针

注意:

(1) ptr是之前动态内存开辟的首地址.

(2) 如果ptr不是动态开辟的地址,则free的行为是未定义的.

(3) 如果free(NULL),什么都不会发生.

calloc函数

原型:

void* calloc(size_t num, size_t size)

功能:

向堆区申请num × size个字节空间,需要传2个参数,每个元素类型的大小 和 元素数目;

(与malloc函数类似)

但还会把这块空间的内容全部初始化为0.

使用:

使用示例:

image.png

realloc函数

原型:

void* realloc(void* memblock, size_t size)

功能:

个人认为这是动态内存管理的灵魂函数。。。。

有时我们发现过去申请的空间小了(或过大了),此时realloc可以对之前申请的动态空间做调整。

扩容的两种情况:

memblock是之前开辟的动态内存的起始地址,会把这个空间大小改成size个字节.

1 若后面有足够的未使用空间:

就直接追加到后面,从而达到扩容的效果,返回原来的起始地址.

image.png

2 若后面的空间某些地方被使用:

realloc会在内存重新找一块区域,并把之前的数据拷贝一份放在前面,返回新的起始地址。

另外,它还会自动free之前的动态空间

image.png

使用:

        char* arr = (char*)calloc(10, sizeof(char));
	if(arr == NULL)
	{
		perror("calloc");//如果申请失败,结束main函数并打印失败原因
		return 0;
	}
	scanf("%s", arr);
	if ((int)strlen(arr) < 5)
	{
		//要注意'\0'也要存的
		//如果用户输入的字符串长度太短,把动态内存调小
		char* tem = realloc(arr, 5);//先判断是不是空指针
		if (tem == NULL)
		{
			perror("realloc");
			return 0;
		}
		else
		{
			arr = tem;
			printf("%s", arr);
		}
	}