文档章节

C语言基础及指针⑤动态内存分配

逝我
 逝我
发布于 2016/09/21 09:04
字数 1451
阅读 0
收藏 0

接续上篇C语言基础及指针④函数指针

在上一篇我们了解C语言中的函数及函数指针 , 使用函数指针 , 模拟了网络请求的回调方式 , 今天我们来学习动态内存分配。

我们在使用java的时候 , 所有的内存都交由JVM做处理 , 我们无法直接控制 , 虽然很少导致内存溢出 , 但是程序占用内存却会越来越大 , 所以我们在使用Android手机的时候 , 刚开始很流畅 , 用着用着就非常卡 , 在打开大文件或是播放gif的时候 , 如果采用java编写处理引擎 , 则会比较卡 , 因为开辟的内存空间无法控制 , GC回收又不是即时的 , 这时候就需要我们使用JNI技术 , 使用C语言进行处理 。接下来 ,我们就来学习C语言中的动态内存分配 。

C语言中内存的大致分配:

内存 描述 特性
栈区 是一个确定的常数(win 1~2M) 不同平台会有不同大小 超出会提示stackoverflow 自动分配 , 自动释放
堆区 用于动态内存分配 手动分配和释放 , 可占用80%内存
全局区或静态区 在程序中明确被初始化的全局变量、静态变量(包括全局静态变量和局部静态变量)和常量数据(如字符串常量) 只初始化一次
程序代码区 代码区指令根据程序设计流程依次执行,对于顺序指令,则只会执行一次(每个进程),如果反复,则需要使用跳转指令,如果进行递归,则需要借助栈来实现。 代码区的指令中包括操作码和要操作的对象(或对象地址引用)

C语言中动态分配内存是在堆区 , java语言中new一个对象 , 也会在堆内存中开辟一块空间 , 来存储我们创建的这个对象 。在C语言中 , 我们在堆区开辟一块空间使用的关键字是mallocmalloc函数定义:

void* __cdecl malloc(
    _In_ _CRT_GUARDOVERFLOW size_t _Size
    );

使用如下:

// 动态内存分配 , 使用malloc函数在对内存中开辟连续的内存空间 , 单位是:字节
// 申请一块40M的堆内存
int* p = (int*)malloc(1024 *1024 * 10 * sizeof(int));

下面我们来模拟一下病毒:

/*动态内存分配*/
void heapFunc() {
	// 动态内存分配 , 使用malloc函数在对内存中开辟连续的内存空间 , 单位是:字节
	// 申请一块40M的堆内存
	int* p = (int*)malloc(1024 *1024 * 10 * sizeof(int));
}


void main() {

	while (1)
	{
        // 睡一秒执行一次
		Sleep(1000);
		heapFunc();
	}

	getchar();

}

打开任务管理器 , 我们可以看到我们共存所占内存 , 正在以40M每秒的速度 , 蹭蹭的往上涨 , 以前的蠕虫病毒就是如此 , 不断的消耗内存 , 然后导致系统崩溃 。

在使用静态内存分配的时候 , 内存大小是固定的 , 很容易超出栈内存的最大值, 预估大小往往大大的超出使用大小 , 浪费内存 。使用malloc申请内存 , 最重要的一个点就是可以动态改变申请的内存大小 , 可以使用realloc函数来重新申请内存大小,realloc函数定义:

void* __cdecl realloc(
    _Pre_maybenull_ _Post_invalid_ void*  _Block,
    _In_ _CRT_GUARDOVERFLOW        size_t _Size
    );

使用如下:

// 重新申请内存大小 , 传入申请的内存指针 , 申请内存总大小
int* p2 = realloc(p, (len + add) * sizeof(int));

下面我们来应用一下:

void main() {

	int len;
	printf("请输入首次分配内存大小:");
	scanf("%d", &len);
	// 动态分配内存 , 内存空间是连续的
	int* p = (int*)malloc(len * sizeof(int));
	// 给申请的内存空间赋值
	int i = 0;
	for (; i < len ; i++)
	{    // 生成随机数赋值
		p[i] = rand() % 100;

		printf("array[%d] = %d , %#x\n", i, p[i], p);
	}

	// 在原有内存上面,重新分配内存大小
	printf("请输入增加的内存大小");
	int add;
	scanf("%d", &add);
	// 重新申请内存大小 , 传入申请的内存指针 , 申请内存总大小
	int* p2 = (int*)realloc(p, (len + add) * sizeof(int));
	// 给新申请的内存空间赋值
	int j = len;
	for (; j < len + add ; j++)
	{
		p2[j] = rand() % 200;
	
	}

	// 打印
	j = 0;
	for (; j < len + add; j++)
	{
		printf("array[%d] = %d , %#x\n", j, p2[j], &p2[j]);
	}
	
	// 回收申请的动态内存
	if (p2 != NULL)
	{
		free(p2);
		p2 = NULL;
	}
		
	system("pause");
}

使用mallocrealloc配合 , 就可以模拟出我们java中的集合类型,动态改变内存空间大小 。 使用malloc 第一次申请的内存首地址和第二次申请的内存首地址可能相同也可能不同 , 因为申请的内存是连续的 , 所有 , 但第一次申请的空间的后续空间不够用时 , 会重新开辟新的空间 , 并将数据copy到新的空间里面 。

内存分配的几个注意细节: 1.不能多次释放 2.释放完之后 , 给指针置NULL,标志释放完成 3.内存泄漏 (p重新赋值之后 , 再free , 并没有真正释放 , 要在赋值之前释放前一个内存空间)

Android程序员学C系列:

C语言基础及指针①

C语言基础及指针②之指针内存分析

C语言基础及指针③函数与二级指针

C语言基础及指针④函数指针

C语言基础及指针⑤动态内存分配

C语言基础及指针⑥字符操作

C语言基础及指针⑦结构体与指针

C语言基础及指针⑧文件IO

C语言基础及指针⑨联合体与枚举

C语言基础及指针⑩预编译及jni.h分析

© 著作权归作者所有

逝我
粉丝 4
博文 20
码字总数 31426
作品 0
长沙
程序员
私信 提问
链表的C语言实现(含动态内存分配)

链表的C语言实现(含动态内存分配) 上 链表的C语言实现之动态内存分配 一、为什么用动态内存分配 但我们未学习链表的时候,如果要存储数量比较多的同类型或同结构的数据的时候,总是使用一个数...

晨曦之光
2012/03/09
724
0
C语言内存管理讲解

谨记 人生有两条路,一天需要用心走,叫做梦想;一条需要用脚走,叫做现实。心走的太快,会迷路的;脚走的太快,会摔倒的;心走的太慢,现实会苍白;脚走的太慢,梦不会高飞。人生的精彩,是...

长风留言
2017/11/22
0
0
[从C到C++] 1.9 C++ new和delete操作符

在C语言中,动态分配和释放内存的函数是malloc、calloc和free,而在C++语言中,new、new[]、delete和delete[]操作符通常会被用来动态地分配内存和释放内存。 需要注意的是new、new[]、delet...

wu_being
2018/06/16
0
0
Cocos2d-x开发中C++内存管理

由于开始并没有介绍C++语言,C++的内存管理当然也没进行任何的说明,为了掌握Cocos2d-x中的内存管理机制,是有必要先了解一些C++内存管理的知识。 C++内存管理非常复杂,如果完全地系统地介绍...

智捷课堂
2014/11/02
82
0
C语言数组与指针一本道来

数组与指针.png 一本道来其他系列 C语言关键字 C语言注释符号一本道来 C语言编译预处理技术一本道来 指针的基础 注意本节内容可能在gcc下不能完成编译,请切换到Windows平台,使用或其他 指针...

PcDack
2017/12/04
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Spring使用ThreadPoolTaskExecutor自定义线程池及实现异步调用

多线程一直是工作或面试过程中的高频知识点,今天给大家分享一下使用 ThreadPoolTaskExecutor 来自定义线程池和实现异步调用多线程。 一、ThreadPoolTaskExecutor 本文采用 Executors 的工厂...

CREATE_17
今天
5
0
CSS盒子模型

CSS盒子模型 组成: content --> padding --> border --> margin 像现实生活中的快递: 物品 --> 填充物 --> 包装盒 --> 盒子与盒子之间的间距 content :width、height组成的 内容区域 padd......

studywin
今天
7
0
修复Win10下开始菜单、设置等系统软件无法打开的问题

因为各种各样的原因导致系统文件丢失、损坏、被修改,而造成win10的开始菜单、设置等系统软件无法打开的情况,可以尝试如下方法解决 此方法只在部分情况下有效,但值得一试 用Windows键+R打开...

locbytes
昨天
8
0
jquery 添加和删除节点

本文转载于:专业的前端网站➺jquery 添加和删除节点 // 增加一个三和一节点function addPanel() { // var newPanel = $('.my-panel').clone(true) var newPanel = $(".triple-panel-con......

前端老手
昨天
8
0
一、Django基础

一、web框架分类和wsgiref模块使用介绍 web框架的本质 socket服务端 与 浏览器的通信 socket服务端功能划分: 负责与浏览器收发消息(socket通信) --> wsgiref/uWsgi/gunicorn... 根据用户访问...

ZeroBit
昨天
10
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部