C语言动态内存分配图文讲解

 更新时间:2023年01月17日 11:12:00   作者:戊子仲秋  
给数组分配多大的空间?你是否和初学C时的我一样,有过这样的疑问。这一期就来聊一聊动态内存的分配,读完这篇文章,你可能对内存的分配有一个更好的理解

思维导图

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

我们现在学习了一些内存开辟的方式:

int main()
{
	int i;//在内存栈区开辟4个字节空间
	char arr[5];//在栈空间上开辟5个字节的连续空间
	return 0;
}

但是,这样开辟的内存是静态的,固定的:

1. 空间开辟大小是固定的。

2. 数组在申明的时候,必须指定数组的长度,它所需要的内存在编译时分配。

如果想要在编译过程中开辟空间,就需要用到动态内存。

2.动态内存函数的介绍

2.1 malloc

void* malloc (size_t size)

2.2 free

void free (void* ptr)

例:

#include <stdio.h>
#include <stdlib.h>
int main()
{
	//申请40给字节,用来存放10个整形
	int* p = (int*)malloc(40);//malloc申请的空间不会初始化
	if (p == NULL)            //直接返回起始地址
	{
		perror("malloc");//如果空间开辟失败要报错并返回
		return 1;
	}
	//使用空间
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d\n", *(p + i));
	}
	//释放申请的内存
	free(p);
	p = NULL;
	return 0;
}

输出:

输出:
-842150451
-842150451
-842150451
-842150451
-842150451
-842150451
-842150451
-842150451
-842150451
-842150451

malloc不会自己初始化,所以打印随机值。

例:

#include <stdio.h>
#include <stdlib.h>
int main()
{
	//申请40给字节,用来存放10个整形
	int* p = (int*)malloc(40);//malloc申请的空间没有初始化
	if (p == NULL)            //直接返回起始地址
	{
		perror("malloc");//如果空间开辟失败要报错并返回
		return 1;
	}
	//使用空间
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		*(p + i) = i + 1;//初始化赋值
		printf("%d ", *(p + i));
	}
	//释放申请的内存
	free(p);
	p = NULL;
	return 0;
}

输出:

输出:1 2 3 4 5 6 7 8 9 10

2.3 calloc

void* calloc (size_t num, size_t size)

例:

#include <stdio.h>
#include <stdlib.h>
int main()
{
	int* p = (int*)calloc(10, sizeof(int));//10是要初始化的个数,sizeof(int)是每个的大小
	if (NULL == p)
	{
		perror("calloc");//判断内存是否申请成功
		return 1;
	}
	//使用
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", *(p + i));//calloc申请空间后,会把空间初始化成0
	}                                              //再返回起始地址
	//释放
	free(p);
	p = NULL;
}

输出:

输出:0 0 0 0 0 0 0 0 0 0

2.4 realloc

void* realloc (void* ptr, size_t size)

realloc函数可以追加更多动态内存。

例:

#include <stdio.h>
#include <stdlib.h>
int main()
{
	int* p = (int*)malloc(5 * sizeof(int));//开辟一段动态内存20个字节
	if (NULL == p)
	{
		perror("malloc");//检查是否创建成功
		return 1;
	}
	//使用
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		*(p + i) = i + 1;
	}
	//不够用,增加5个整形的空间
	int* ptr = (int*)realloc(p, 10 * sizeof(int));//这里是开辟到40个字节
	//realloc函数开辟内存空间有两种情况:
	//1.原内存块后面空间足够,在原内存块后面追加内存
	//2.原内存块后面空间不够,另外找一片区域开辟内存,将原内存块释放
	if (ptr != NULL)
	{
		p = ptr;//为什么不直接用p接收?
		//如果内存追加失败,直接用p接收的话,原本已经开辟的动态内存空间就会被覆盖
	}
	for (i = 0; i < 10; i++)
	{
		printf("%d ", *(p + i));
	}
	//释放
	free(p);
	p = NULL;
	return 0;
}

输出:

输出:1 2 3 4 5 -842150451 -842150451 -842150451 -842150451 -842150451

3.常见的动态内存错误

例1:

开辟动态内存记得要判断,最后释放内存。

#include <stdio.h>
#include <stdlib.h>
int main()
{
	int* p = (int*)malloc(100);
	//内存开辟后没有判断是否开辟成功
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		*(p + i) = 0;//危险代码,我们无法知道是否存在非法访问
	}
	//并且最后也没有将开辟的内存还给操作系统
	return 0;
}

例2:

动态内存开辟了多少就用多少,小心越界访问。

#include <stdio.h>
#include <stdlib.h>
int main()
{
	int* p = (int*)malloc(100);//开辟了100字节空间
	//判断
	if (p == NULL)
	{
		perror("malloc");
		return 1;
	}
	int i = 0;
	for (i = 0; i < 100; i++)//造成越界访问
	{
		*(p + i) = 0;//一个整形4个字节
	}
	//释放
	free(p);
	p = NULL;
	return 0;
}

例3:

不要乱释放其他内存空间。

int main()
{
	int a = 10;
	int* p = &a;
	//你没有权限乱释放其他的内存空间
	free(p);//不能对栈区的内存释放
	return 0;
}

例4:

不要多次释放内存空间。

#include <stdio.h>
#include <stdlib.h>
int main()
{
	//开辟空间
	int* p = (int*)malloc(100);
	//判断
	if (p == NULL)
	{
		perror("malloc");
		return 1;
	}
	//使用
	int i = 0;
	for (i = 0; i < 25; i++)
	{
		*p = i;
		p++;//p指针不断往后移动
	}
	//释放的时候指针应该指向起始地址,否则程序又会出错
	free(p);
	p = NULL;
	return 0;
}

例5:

#include <stdio.h>
#include <stdlib.h>
int main()
{
	//创建
	int* p = (int*)malloc(100);
	//判断
	if (p == NULL)
	{
		return 1;
	}
	//释放
	free(p);
	free(p);//已经释放了,重复释放会导致程序出错
	return 0;
}

这就要说到最后置为空指针的好处了:

#include <stdio.h>
#include <stdlib.h>
int main()
{
	//创建
	int* p = (int*)malloc(100);
	//判断
	if (p == NULL)
	{
		return 1;
	}
	//释放
	free(p);
	p = NULL;//置为空指针后程序就不会崩溃了
	free(p);//p为空指针时,程序不会报错
	return 0;
}

例5:

在实现函数时开辟了动态内存要记得及时释放或者返回地址,

不然就再也找不到那段内存空间了,最后导致内存泄漏。

#include <stdio.h>
#include <stdlib.h>
void test()
{
	int* p = (int*)malloc(100);
	//忘记释放
}//出了函数就找不到了,因为变量p被销毁了
//造成内存泄漏
int main()
{
	test();
	return 0;
}
 

例6:

这道题也是类似的:

#include <stdio.h>
#include <stdlib.h>
void test()
{
	int* p = (int*)malloc(100);
	if (p == NULL)
	{
		return;
	}
	//使用
	if (1)
		return;//出问题//内存泄漏
	//释放
	free(p);
	p = NULL;
}
int main()
{
	test();
	return 0;
}

要小心出现内存泄漏,记得释放空间。

到此这篇关于C语言动态内存分配图文讲解的文章就介绍到这了,更多相关C语言动态内存分配内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • C++中declspec(dllexport)和declspec(dllimport) 的用法介绍

    C++中declspec(dllexport)和declspec(dllimport) 的用法介绍

    这篇文章介绍了C++中declspec(dllexport)和declspec(dllimport) 的用法,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-04-04
  • c++智能指针unique_ptr的使用

    c++智能指针unique_ptr的使用

    本文主要介绍了c++智能指针unique_ptr的使用,与shared_ptr作用类似,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-12-12
  • C语言中如何判断质数

    C语言中如何判断质数

    这篇文章主要介绍了C语言中的判断质数问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-03-03
  • c++深入浅出讲解堆排序和堆

    c++深入浅出讲解堆排序和堆

    在c++里有很多排序方法,比如相对简单的冒泡排序、选择排序、插入排序,还有 STL里的sort函数  手写快排  归并排序等,还有就是堆排序,这次主要说堆排序和堆
    2022-03-03
  • Typedef在C语言和C++中的用法和区别

    Typedef在C语言和C++中的用法和区别

    在C语言和C++中,typedef是一个非常常用的关键字,用于为数据类型定义别名,尽管它在两种语言中都有相似的功能,但由于C++具有更丰富的类型系统,因此在实际应用中,typedef在两者间的使用存在一些微妙的差异
    2024-01-01
  • C语言超详细分析多进程的概念与使用

    C语言超详细分析多进程的概念与使用

    在一个项目中并发执行任务时多数情况下都会选择多线程,但有时候也会选择多进程,例如可以同时运行n个记事本编辑不同文本,由一个命令跳转到另外一个命令,或者使用不同进程进行协作
    2022-08-08
  • VC实现获取当前正在运行的进程

    VC实现获取当前正在运行的进程

    这篇文章主要介绍了VC实现获取当前正在运行的进程,涉及VC针对系统进程的相关操作技巧,需要的朋友可以参考下
    2015-05-05
  • Visual Studio Code (vscode) 配置C、C++环境/编写运行C、C++的教程详解(Windows)【真正的小白版】

    Visual Studio Code (vscode) 配置C、C++环境/编写运行C、C++的教程详解(Windows

    这篇文章主要介绍了Visual Studio Code (vscode) 配置C、C++环境/编写运行C、C++的教程详解(Windows)【真正的小白版】,图文详解介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-03-03
  • 使用C语言实现三子棋游戏

    使用C语言实现三子棋游戏

    这篇文章主要为大家详细介绍了使用C语言实现三子棋游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-07-07
  • 嵌入式C语言轻量级程序架构内核编写

    嵌入式C语言轻量级程序架构内核编写

    这篇文章主要介绍了嵌入式C语言轻量级程序架构内核编写,文章将让大家学到轻量级程序架构的内核实现原理、轻量级程序架构的设计思想、了解单片机常用的程序架构等更多C语言轻量级程序架构相关内容,需要的朋友可以参考一下
    2022-03-03

最新评论