目录

  • 一、概述
  • 二、相关库函数的使用
    • 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++程序内存分配的几个区域

  1. 栈区(stack):在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。 栈区主要存放运行函数而分配的局部变量、函数参数、返回数据、返回地址等。
  2. 堆区(heap):一般由程序员分配释放, 若程序员不释放,程序结束时可能由系统自动回收 。
  3. 数据段(静态区)(static)存放全局变量、静态数据。程序结束后由系统释放。
  4. 代码段:存放函数体(类成员函数和全局函数)的二进制代码。

实际上,普通的局部变量是在栈区分配空间的,栈区的特点是在上面创建的变量出了作用域就销毁。
但被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,柔型数组)相关推荐

  1. C语言动态内存分配详解

    文章目录 前言 一.为什么存在动态内存分配 1.已掌握的内存开辟方式 2.上述开辟空间方式的特点 3.为什么存在动态内存分配 二.动态内存函数的介绍 1.malloc 2.free 3.calloc ...

  2. C/C++动态内存开辟详解(含常见错误以及经典面试题)

    动态内存开辟 1.四个重要的内存函数 1.1 malloc和free 1.2 calloc 1.3 realloc 2.常见错误 2.1 对NULL指针进行解引用操作 2.2 对动态开辟内存的越界访问 ...

  3. 【C语言】动态内存分配详解

    目录 一.为什么有动态内存分配 二.动态内存分配函数 (1)malloc()函数 (2)calloc()函数 (3)realloc()函数 三.常见的动态内存错误 1.越界访问 2.内存泄漏 3.对N ...

  4. 内存分配详解 malloc, new, HeapAlloc, VirtualAlloc,GlobalAlloc

    很多地方都会使用内存,内存使用过程中操作不当就容易崩溃,无法运行程序,上网Google学习一下,了解整理下他们之间的区别以及使用 ,获益匪浅 0x01 各自的定义和理解 (1)先看GlobalAllo ...

  5. 【C++】动态内存分配详解(new/new[]和delete/delete[])

    原文链接:https://blog.csdn.net/qq_40416052/article/details/82493916 代码还是原文看着方便,在此不调整格式了 一.为什么需要动态内存分配? 在 ...

  6. 易语言读写内存操作详解

    1.函数原型: BOOL ReadProcessMemory( HANDLE hProcess, PVOID pvAddressRemote, PVOID pvBufferLocal, DWORD d ...

  7. java文档注释定界符_c语言的注释定界符详解

    c语言的注释定界符详解 c语言的注释定界符是什么 1.最早期的C语言注释是:/* */ 2.后来又增加的行注释:// 其中/**/是多行注释,//是单行注释. 需要注意的是:C 语言的注释并不是可以出 ...

  8. 内存分布malloc/calloc/realloc/free/new/delete、内存泄露、String模板、浅拷贝与深拷贝以及模拟string类的实现

    内存分布 一.C语言中的动态内存管理方式:malloc/calloc/realloc和free 1.malloc: 从堆上获得指定字节的内存空间,函数声明:void *malloc (int n); ...

  9. 【C语言进阶】详解C语言动态内存管理

    前言: 今天这篇博客将为大家讲解如何通过开辟动态内存,从而写出更加优秀的的程序.同时今天的内容对于以后想要继续学习c++的同学来说也尤为重要.那就让我们进入正题吧. 一.动态内存概述: 什么是动态内存 ...

最新文章

  1. python list去重_Python中实用却不常见的小技巧
  2. matlab while 跳出,请帮忙看下这个程序为什么跳不出WHILE循环??
  3. PL/SQL Developer连接本地Oracle 11g 64位数据库和快捷键设置
  4. 《Android进阶之光》--View体系与自定义View
  5. kernel移植——从三星官方内核开始移植
  6. ( vscode中文版 ) 怎么快速打开vscode settings.json文件
  7. 阮一峰ES6入门读书笔记(十一):Promise
  8. sdr 软件_将永远改变我们业余无线电爱好的SDR软件定义无线电技术
  9. 浏览器全球的书签都在这里了,看看有没有你的!
  10. js逆向教程第二发-猿人学第一题
  11. mysql 综合练习
  12. 【原创】QT5-卸载精灵v1.0-卸载windows软件-简易版
  13. UTC时间和CST时间
  14. [BIM]BIM中IFD介绍
  15. JAVA动态桌面制作_自己动手制作安卓动态壁纸教
  16. java安装教程win7_Tomcat服务器安装配置教程(win7)
  17. 计算机专业证书难度,计算机专业应该考这些证书!
  18. 淘宝新店如何推广效果比较好?有哪些渠道?
  19. 时隔多年,我胡汉三又回来了(大学毕业篇-迷茫)
  20. 数据库练习(学生、课程、选课关系)

热门文章

  1. 图像运动模糊及其去除
  2. 随机生成10位数QQ号.c
  3. 006 以太坊Mist安装部署
  4. [UVALive - 4329] Ping pong 树状数组入门
  5. 用SDK包开发K66FX18学习笔记(3)
  6. 搜索插件像百度那样的智能感知效果
  7. Elasticsearch _reindex Alias使用
  8. Android组件化架构实践,成功拿下大厂offer
  9. VSCode取消注释斜体
  10. narwal机器人_省时省心才见真章!Narwal云鲸J1智能扫拖机器人国内上市