C语言动态内存开辟详解(malloc,calloc,realloc,free,柔型数组)
目录
- 一、概述
- 二、相关库函数的使用
- 1.malloc
- 2.calloc
- malloc vs. calloc 异同
- 3.free的使用
- 4.realloc
- 三、易错点
- 四、C\C++程序的内存开辟规则
- 五、柔性数组
一、概述
Q:为什么需要动态内存分配?
A:使用这两种方式开辟内存的大小是固定的:
int val = 20; //在栈上开辟4个字节的空间
char arr[10] = {0}; //在栈上开辟10个字节的连续空间
另外,数组在申明的时候,必须指定数组的长度,它所需要的内存在编译时分配。
但是,当所需空间的大小在程序运行时才能知道,也就无法事先开辟一块空间了,这时候就需要动态内存开辟。
二、相关库函数的使用
注:以下均需包含<stdlib.h>
1.malloc
void* malloc (size_t size);
使用:
#include <stdio.h>
#include <stdlib.h>
int main()
{int* ptr = (int*)malloc(40);if (ptr == NULL) //务必判断是否开辟成功,否则退出并报错{perror("malloc"); //或printf("%s",strerror(errno)); //strerror头文件是<string.h> errno头文件是<errno.h?//直接打印用perror,如果只需要获得错误码不需要打印就使用strerror(errno)return 1;}int i = 0;for (i = 0; i < 10; i++){printf("%d ", *(ptr + i));}//必不可少的使用后free 和 NULL置空free(ptr);ptr = NULL;return 0;
}
易错:1.忘记判断NULL 2.忘记free和指针置空
free只是释放(返还)空间,但不会将其置为空指针,为了防止它是野指针、防止内存泄漏,需要手动置为空指针
注:free不释放等程序结束也能自动回收内存空间
2.calloc
void* calloc (size_t num, size_t size);
使用:
#include <string.h>
#include <errno.h>
int main()
{int* ptr = calloc(10, 4);if (ptr == NULL){printf("%s", strerror(errno));return 1;}int i = 0;for (i = 0; i < 10; i++){printf("%d ", *(ptr + i));}free(ptr);ptr = NULL;return 0;
}
malloc vs. calloc 异同
1.相同之处:
1.无符号整形(size_t)是要开辟内存的大小,以字节为单位
2.返回值void*表示适用于所有类型的指针来接收,并且需要强制类型转换来适应所要接受的类型指针
3.如果开辟成功,则返回一个指向开辟好空间的指针。如果开辟失败,则返回一个NULL指针,因此对malloc、calloc以及realloc的返回值一定要做检查(例如设置一个指针来存放返回的地址,判断是否为NULL,是NULL返回错误信息如果不为NULL,再使用要使用的指针来存放,这样可以避免本身要使用的指针值改变)。
4.如果参数 size 为0,标准是未定义的,取决于编译器。
2.不同点
1.malloc开辟的空间是未初始化的,calloc会默认初始化为0,单位为字节
2.calloc中num参数表示要开辟num个size大小的字节,
比如calloc(3,4); 表示开辟3个大小为4个字节的内存,可以使用在数组中
3.相比于malloc,calloc的初始化更精确可控一些,建议使用calloc
3.free的使用
void free (void* ptr);
使用malloc等动态内存开辟相关库函数时一定配合free使用,先free()后把指针置空,避免内存泄漏和野指针。
4.realloc
void* realloc (void* ptr, size_t size);
1.ptr 是要调整的内存地址
2.size 调整之后新大小
3.返回值为调整之后的内存起始位置。
使用:
#include <stdio.h>
#include <stdlib.h>
int main()
{int* p = (int*)calloc(10, sizeof(int));if (p == NULL){perror("calloc");return 1;}//realloc从新分配大小为20个字节int* ptr = (int*)realloc(p, 20 * sizeof(int));if (ptr != NULL){p = ptr;}//free释放free(p);p = NULL;return 0;
}
总结:realloc开辟空间,后面空间足够时还是用原首地址,扩容(直接追加);若空间不足,则会开辟一块新的空间,(一块连续的空间),把原来的内容拷贝到新的地址内,此时地址改变。如果找不到合适的空间来调整大小,则返回空指针。所以一般不用原来的指针变量来接收值,防止值被改变。
三、易错点
四、C\C++程序的内存开辟规则
C/C++程序内存分配的几个区域
- 栈区(stack):在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。 栈区主要存放运行函数而分配的局部变量、函数参数、返回数据、返回地址等。
- 堆区(heap):一般由程序员分配释放, 若程序员不释放,程序结束时可能由系统自动回收 。
- 数据段(静态区)(static)存放全局变量、静态数据。程序结束后由系统释放。
- 代码段:存放函数体(类成员函数和全局函数)的二进制代码。
实际上,普通的局部变量是在栈区分配空间的,栈区的特点是在上面创建的变量出了作用域就销毁。
但被static修饰的变量则存放在数据段(静态区),数据段的特点是在上面创建的变量,直到程序结束才销毁,所以生命周期变长了。
五、柔性数组
1.定义:在C99 中,结构中的最后一个元素允许是未知大小的数组,这就叫做『柔性数组』成员。
typedef struct st_type
{int i;int a[0];//柔性数组成员 (若无法编译,可改为int a[];)
}type_a;
2.特点:
- 结构中的柔性数组成员前面必须有至少一个其他成员。
- sizeof 返回的这种结构大小不包括柔性数组的内存。
- 包含柔性数组成员的结构用malloc ()函数进行内存的动态分配,并且分配的内存应该大于结构的大小,以适应柔性数组的预期大小。
3.使用:
//代码1
int i = 0;
type_a *p = (type_a*)malloc(sizeof(type_a)+100*sizeof(int));
//业务处理
p->i = 100;
for(i=0; i<100; i++)
{p->a[i] = i;
}
free(p);
注意:对有柔型数组的结构体动态开辟时,要用sizeof() + —(100 * sizeof(int))的形式来分配大小
4.优点
使用柔型数组的好处是方便内存释放,一次性分配内存,例如用指针动态开辟时可能忘记释放两次,而用柔型数组做一次free就可以把所有的内存释放掉。
其次,有利于提高访问速度,因为是内存的开辟是连续的,也有益于减少内存碎片(没有被使用的一些内存)。
※推荐阅读※
C语言结构体里的成员数组和指针
C语言动态内存开辟详解(malloc,calloc,realloc,free,柔型数组)相关推荐
- C语言动态内存分配详解
文章目录 前言 一.为什么存在动态内存分配 1.已掌握的内存开辟方式 2.上述开辟空间方式的特点 3.为什么存在动态内存分配 二.动态内存函数的介绍 1.malloc 2.free 3.calloc ...
- C/C++动态内存开辟详解(含常见错误以及经典面试题)
动态内存开辟 1.四个重要的内存函数 1.1 malloc和free 1.2 calloc 1.3 realloc 2.常见错误 2.1 对NULL指针进行解引用操作 2.2 对动态开辟内存的越界访问 ...
- 【C语言】动态内存分配详解
目录 一.为什么有动态内存分配 二.动态内存分配函数 (1)malloc()函数 (2)calloc()函数 (3)realloc()函数 三.常见的动态内存错误 1.越界访问 2.内存泄漏 3.对N ...
- 内存分配详解 malloc, new, HeapAlloc, VirtualAlloc,GlobalAlloc
很多地方都会使用内存,内存使用过程中操作不当就容易崩溃,无法运行程序,上网Google学习一下,了解整理下他们之间的区别以及使用 ,获益匪浅 0x01 各自的定义和理解 (1)先看GlobalAllo ...
- 【C++】动态内存分配详解(new/new[]和delete/delete[])
原文链接:https://blog.csdn.net/qq_40416052/article/details/82493916 代码还是原文看着方便,在此不调整格式了 一.为什么需要动态内存分配? 在 ...
- 易语言读写内存操作详解
1.函数原型: BOOL ReadProcessMemory( HANDLE hProcess, PVOID pvAddressRemote, PVOID pvBufferLocal, DWORD d ...
- java文档注释定界符_c语言的注释定界符详解
c语言的注释定界符详解 c语言的注释定界符是什么 1.最早期的C语言注释是:/* */ 2.后来又增加的行注释:// 其中/**/是多行注释,//是单行注释. 需要注意的是:C 语言的注释并不是可以出 ...
- 内存分布malloc/calloc/realloc/free/new/delete、内存泄露、String模板、浅拷贝与深拷贝以及模拟string类的实现
内存分布 一.C语言中的动态内存管理方式:malloc/calloc/realloc和free 1.malloc: 从堆上获得指定字节的内存空间,函数声明:void *malloc (int n); ...
- 【C语言进阶】详解C语言动态内存管理
前言: 今天这篇博客将为大家讲解如何通过开辟动态内存,从而写出更加优秀的的程序.同时今天的内容对于以后想要继续学习c++的同学来说也尤为重要.那就让我们进入正题吧. 一.动态内存概述: 什么是动态内存 ...
最新文章
- python list去重_Python中实用却不常见的小技巧
- matlab while 跳出,请帮忙看下这个程序为什么跳不出WHILE循环??
- PL/SQL Developer连接本地Oracle 11g 64位数据库和快捷键设置
- 《Android进阶之光》--View体系与自定义View
- kernel移植——从三星官方内核开始移植
- ( vscode中文版 ) 怎么快速打开vscode settings.json文件
- 阮一峰ES6入门读书笔记(十一):Promise
- sdr 软件_将永远改变我们业余无线电爱好的SDR软件定义无线电技术
- 浏览器全球的书签都在这里了,看看有没有你的!
- js逆向教程第二发-猿人学第一题
- mysql 综合练习
- 【原创】QT5-卸载精灵v1.0-卸载windows软件-简易版
- UTC时间和CST时间
- [BIM]BIM中IFD介绍
- JAVA动态桌面制作_自己动手制作安卓动态壁纸教
- java安装教程win7_Tomcat服务器安装配置教程(win7)
- 计算机专业证书难度,计算机专业应该考这些证书!
- 淘宝新店如何推广效果比较好?有哪些渠道?
- 时隔多年,我胡汉三又回来了(大学毕业篇-迷茫)
- 数据库练习(学生、课程、选课关系)