动态内存申请

  • 一 动态内存申请
  • 二 静态分配内存和动态分配内存
    • 2.1 静态分配内存
    • 2.2 动态分配内存
  • 三 动态内存申请的相关函数
    • 3.1 分配内存空间函数 malloc
    • 3.2 free函数 (释放内存函数)
    • 3.3 案例一:从堆区申请一个int类型的空间
    • 3.4 案例二:从堆区申请一个数组,数组的大小由用户决定
    • 3.5 calloc函数
    • 3.5 realloc函数(重新申请内存空间)
  • 四 动态内存申请的注意事项
    • 4.1 指向堆区的指针变量不要随意更改指向,会导致calloc申请的内存空间泄漏
    • 4.2 不要操作已经释放的空间,因为该空间内容已经不能确定了
    • 4.3 不要对堆区空间重复释放
    • 4.4 如何防止对堆区空间重复释放?
  • 五 从堆区中给各个数据类型申请内存空间
    • 5.1 为int变量在堆区申请内存空间
    • 5.2 为char*变量在堆区申请内存空间
    • 5.3 为char数组变量在堆区申请内存空间
    • 5.4 为结构体变量在堆区申请内存空间
    • 5.5 为结构体变量数组在堆区申请内存空间

一 动态内存申请

  1. 数组的长度是预先定义好的,在整个程序中固定不变;
  2. 但在实际应用中,往往有这种情况,所需要的内存空间取决于实际输入的数据,而无法预先确定
  3. 为了解决上面的问题,C语言提供了一些内存管理函数,这些内存管理函数可以安装需要动态的分配内存空间,也可以把不再使用的内存空间回收再利用

二 静态分配内存和动态分配内存

2.1 静态分配内存

  1. 在程序编译或运行过程中,按事先规定好的大小分配内存空间的分配方式;
  2. 必须事先知道所需空间的大小;
  3. 空间是分配在栈区或全局变量区的;
  4. 按计划分配

2.2 动态分配内存

  1. 在程序运行过程中按需要自由分配所需空间;
  2. 按需分配;
  3. 空间是分配在堆区的,一般使用特点函数来分配

三 动态内存申请的相关函数

3.1 分配内存空间函数 malloc

函数功能: 在内存的动态存储器(堆区)中分配一块长度为size字节的连续内存空间,用来存放类型说明符指定的数据类型
函数原型: void *malloc(unsigned int num_bytes);形参num_bytes是需要申请内存空间的字节数
调用形式: (类型说明符*) malloc(size)
返回值:分配成功:分配的内存空间的起始地址分配失败:NULL
注意事项:1. 对malloc的返回值一定要强制类型转换;2. malloc申请的内存空间的内容不确定,一般需要使用memset进行清空;3. 调用malloc后,一定要判断一下,是否申请内存成功;4. 如果多次malloc申请的内存,第一次和第二次申请的内存不一定连续;

3.2 free函数 (释放内存函数)

函数说明:free函数释放ptr指向的内存
函数定义:void free(void *ptr)
注意事项:ptr指向的内存必须是malloc,calloc,relloc动态申请的内存

3.3 案例一:从堆区申请一个int类型的空间

[root@ansible9 ~]# cat  test.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int arg, char *argv[])
{int *p=NULL;p=(int *)malloc((int)sizeof(int));if(p==NULL){printf("malloc err\n");return 1;}printf("用malloc申请的内存空间中的内容是不确定的:%d\n",*p);memset(p,0,(int)sizeof(int));printf("用memset清0后的内存空间中的内容是:%d\n",*p);printf("请输入一个int数值:");scanf("%d",p);printf("%d\n",*p);free(p);
}
[root@ansible9 ~]# ./a.out
用malloc申请的内存空间中的内容是不确定的:0
用memset清0后的内存空间中的内容是:0
请输入一个int数值:111
111

3.4 案例二:从堆区申请一个数组,数组的大小由用户决定

步骤:

  1. 从键盘获取要申请的数组的大小;
  2. 根据大小,从内存堆区申请空间;
  3. 对空间读写操作;
  4. 释放该空间;
[root@ansible9 ~]# cat test.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int arg, char *argv[])
{printf("请输入数值元素的个数:");int n=0;scanf("%d",&n);printf("将要为元素个数为%d个的数组申请内存空间\n",n);int *p=NULL;p=(int *)malloc(n*(int)sizeof(int));if(p==NULL){perror("malloc error!");return 1;}memset(p,0,n*(int)sizeof(int));int i=0;printf("请输入%d个int数组",n);for(i=0;i<n;i++){scanf("%d",p+i);}for(i=0;i<n;i++){printf("%d\n",p[i]);}free(p);
}
[root@ansible9 ~]# ./a.out
请输入数值元素的个数:5
将要为元素个数为5个的数组申请内存空间
请输入5个int数组10 20 30 40 50 60 70 80
10
20
30
40
50

3.5 calloc函数

函数原型:void * calloc(size_t nmemb, size_t size);参数: size_t是无符号整形,是在头文件中用typeof定义出来的返回值:申请失败:返回NULL;申请成功:返回申请的内存的首地址
函数功能:在内存的堆区,申请nmemb块,每块大小为size字节的连续内存空间
注意事项:1. calloc函数申请的内存空间已经自动被清0了,不用再用memset清0;2. calloc函数申请的内存空间字节数为nmemb和size的乘积;
[root@ansible9 ~]# cat test.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int arg, char *argv[])
{printf("请输入数值元素的个数:");int n=0;scanf("%d",&n);printf("将要为元素个数为%d个的数组申请内存空间\n",n);int *p=NULL;p=(int *)calloc(n, (int)sizeof(int));if(p==NULL){perror("calloc error!");return 1;}int i=0;printf("请输入%d个int数组",n);for(i=0;i<n;i++){scanf("%d",p+i);}for(i=0;i<n;i++){printf("%d\n",p[i]);}free(p);
}
[root@ansible9 ~]# ./a.out
请输入数值元素的个数:5
将要为元素个数为5个的数组申请内存空间
请输入5个int数组10 20 30 40 50 60 70
10
20
30
40
50

3.5 realloc函数(重新申请内存空间)

函数原型:void* realloc(void* s, unsigned int newsize);
形参:s原先开辟内存的地址           newsize:新申请内存的大小
返回值:新申请内存的首地址
函数功能:在原先s执行的内存基础上重新申请内存,新的内存大小为newsize字节,如果原先内存后面有足够大的空间就追加;如果没有则realloc函数会在内存堆区找一个newsize字节大小的空间来申请,将原先内存中的数据拷贝过来,然后释放原先的内存,最后返回新内存的地址
[root@ansible9 ~]# cat test.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int arg, char *argv[])
{printf("请输入数值元素的个数:");int n=0;scanf("%d",&n);printf("将要为元素个数为%d个的数组申请内存空间\n",n);int *p=NULL;p=(int *)calloc(n, (int)sizeof(int));if(p==NULL){perror("calloc error!");return 1;}int i=0;printf("请输入%d个int数组元素",n);for(i=0;i<n;i++){scanf("%d",p+i);}for(i=0;i<n;i++){printf("%d\n",p[i]);}printf("想要为数组增加几个元素:");int m=0;scanf("%d",&m);printf("您想要增加%d个元素\n",m);p=(int *)realloc(p,(n+m)*(int)sizeof(int));if(p==NULL){perror("calloc error!");return 1;}printf("请输入%d个新int数组元素",m);for(i=n;i<(m+n);i++){scanf("%d",p+i);}for(i=0;i<(n+m);i++){printf("%d\n",p[i]);}printf("数组现有%d个元素\n",(n+m));int h=0;printf ("想减少几个元素:");scanf("%d",&h);printf("您想减少%d个元素\n",h);p=(int *)realloc(p,(n+m-h)*(int)sizeof(int));if(p==NULL){perror("calloc error!");return 1;}for(i=0;i<(n+m-h);i++){printf("%d\n",p[i]);}free(p);
}
[root@ansible9 ~]# ./a.out
请输入数值元素的个数:3
将要为元素个数为3个的数组申请内存空间
请输入3个int数组元素10 20 30
10
20
30
想要为数组增加几个元素:2
您想要增加2个元素
请输入2个新int数组元素40 50
10
20
30
40
50
数组现有5个元素
想减少几个元素:4
您想减少4个元素
10

四 动态内存申请的注意事项

4.1 指向堆区的指针变量不要随意更改指向,会导致calloc申请的内存空间泄漏

[root@ansible9 ~]# cat test.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int arg, char *argv[])
{int *p = (int *)malloc(4*(int)sizeof(int));int num=10;p=&num;
}

4.2 不要操作已经释放的空间,因为该空间内容已经不能确定了

[root@ansible9 ~]# cat test.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int arg, char *argv[])
{int *p = (int *)malloc((int)sizeof(int));memset(p,0,(int)sizeof(int));*p=100;free(p);printf("%d\n",*p);
}

4.3 不要对堆区空间重复释放

[root@ansible9 ~]# cat test.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int arg, char *argv[])
{int *p = (int *)malloc((int)sizeof(int));memset(p,0,(int)sizeof(int));*p=100;free(p);free(p);
}
[root@ansible9 ~]# gcc -Wall test.c
[root@ansible9 ~]# ./a.out
free(): double free detected in tcache 2
Aborted (core dumped)

4.4 如何防止对堆区空间重复释放?

五 从堆区中给各个数据类型申请内存空间

5.1 为int变量在堆区申请内存空间

int main(int arg, char *argv[])
{int *p = (int*)calloc(1,(int)sizeof(int));*p=100;printf("%d\n",*p);if(NULL!=p){free(p);p=NULL;}
}

5.2 为char*变量在堆区申请内存空间

int main(int arg, char *argv[])
{char **p = (char**)calloc(1,(int)sizeof(char*));*p = (char*)calloc(1,(int)sizeof(char));printf("%p\n",p);printf("%p\n",*p);**p='A';printf("%c\n",**p);
}

5.3 为char数组变量在堆区申请内存空间

int main(int arg, char *argv[])
{char*p = (char*)calloc(5,(int)sizeof(char));int n=0;for(n=0;n<5;n++){printf("请输入第%d个字符:",n+1);scanf("%c%*c",p+n);}printf("%s\n",p);free(p);
}

5.4 为结构体变量在堆区申请内存空间

struct stu
{int num;char name[32];int age;
};int main(int arg, char *argv[])
{struct stu* p = (struct stu*)calloc(1,(int)sizeof(struct stu));p->num=100;strcpy(p->name,"andy");p->age=18;printf("num=%d\n",p->num);printf("name=%s\n",p->name);printf("age=%d\n",p->age);
}
struct stu
{int num;char name[32];int age;
};void my_set_stu(struct stu* p)
{printf("请输入学生的信息 num name age\n");scanf("%d %s %d",&p->num,p->name,&(*p).age);
}
void my_print_stu(const struct stu* p)
{printf("num=%d\n",p->num);printf("name=%s\n",p->name);printf("age=%d\n",p->age);
}
int main(int arg, char *argv[])
{struct stu* p = (struct stu*)calloc(1,(int)sizeof(struct stu));my_set_stu(p);my_print_stu(p);free(p);
}

5.5 为结构体变量数组在堆区申请内存空间

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct stu
{int num;char name[32];int age;
};void my_set_stu(struct stu* p, int n)
{int i=0;for(i=0;i<n;i++){printf("请输入第%d个学生的信息 num name age\n", i+1);scanf("%d %s %d",&(p+i)->num,(p+i)->name,&(*(p+i)).age);}
}
void my_print_stu(const struct stu* p, int n)
{int i=0;for(i=0;i<n;i++){printf("第%d个学生的信息: ",i+1);printf("num=%d ",(p+i)->num);printf("name=%s ",(p+i)->name);printf("age=%d\n",(p+i)->age);}
}
int main(int arg, char *argv[])
{int n=0;printf("请输入学生个数:");scanf("%d",&n);struct stu* p = (struct stu*)calloc(n,(int)sizeof(struct stu));my_set_stu(p,n);my_print_stu(p,n);free(p);
}

c语言十七:动态内存申请相关推荐

  1. C语言中动态内存分配的本质是什么?

    摘要:C语言中比较重要的就是指针,它可以用来链表操作,谈到链表,很多时候为此分配内存采用动态分配而不是静态分配. 本文分享自华为云社区<[云驻共创]C语言中动态内存分配的本质>,作者: G ...

  2. C++---之动态内存申请new

    一.为什么需要动态内存分配? 在C++程序中,所有内存需求都是在程序执行之前通过定义所需的变量来确定的. 但是可能存在程序的内存需求只能在运行时确定的情况. 例如,当需要的内存取决于用户输入. 在这些 ...

  3. C/C++动态内存申请与释放

    20.1 理解指针的两种"改变" 普通变量(非指针,简单类 型变量)只能改变值:   1) int a = 100; 2) ... 3) a = 200;   第 1 行代码,声明 ...

  4. 【C语言】动态内存分配

    [C语言]动态内存分配 文章目录 [C语言]动态内存分配 一.malloc 与free函数 二.calloc 三.realloc 四.常见的动态内存的错误 本期,我们将讲解malloc.calloc. ...

  5. 动态内存申请(Linux)

    我们在C语言中学习过关于动态内存申请的相关操作,例如malloc 那么在Linux中也是相同的操作:我们以32位操作相同为例 我们知道,申请动态内存实质上就是从堆区(.heap)中申请,而在4G内存分 ...

  6. C语言知识点 -- 动态内存管理、文件操作

    C语言知识点 – 动态内存管理.文件操作 文章目录 C语言知识点 -- 动态内存管理.文件操作 一.动态内存管理 1.malloc 2.free 3.calloc 4.realloc 二.文件操作 1 ...

  7. 二维数组的动态内存申请,采用子函数的方式 为二级指针申请内存,和释放内存

    原理:二级指针,行指针+列指针 照着葫芦画瓢就行. 方法一:用c语言malloc实现 #include<cstdio> #include<iostream> #include& ...

  8. c语言malloc引用类型作参数,c语言中动态内存分配malloc只在堆中分配一片内存.doc...

    c语言中动态内存分配malloc只在堆中分配一片内存 .C语言中动态内存分配(malloc)只在堆中分配一片内存,返回一个void指针(分配失败则返回0),并没有创建一个对象.使用时需要强制转换成恰当 ...

  9. 动态内存申请(malloc, calloc, new)之分配虚拟内存空间和物理内存空间

    动态内存申请(malloc, calloc, new)之分配虚拟内存空间和物理内存空间 1. 动态内存申请的底层系统调用 动态内存申请函数根据申请的内存大小选择不同的系统调用,小于128K选择brk系 ...

最新文章

  1. 这回导师们颤抖了,这个网站能匿名评价其“人品”,已有大量“不良”导师被爆...
  2. win10右键闪退到桌面_【雷粉百科】windows10鼠标点击右键出现卡顿或者转圈
  3. Windows XP权限
  4. Visual Studio 2013 添加一般应用程序(.ashx)文件到SharePoint项目
  5. YbtOJ-毒瘤染色【LCT】
  6. Android studio如何写滚动视图
  7. URL不能过长,否则summit方法提交失败
  8. Build the initrd image
  9. UNIX 时间戳 C#
  10. 手动实现 NSTabViewController 的 Rect Transition 及 Propagate Title-b
  11. MySQL大表关联如何优化_MySQL 对于大表(千万级),要怎么优化呢?
  12. map mybatis 的字段返回0_mybatis返回map类型数据空值字段不显示(三种解决方法)
  13. HPU 图书馆占座 python
  14. 在win10系统上使用HiTool工具网口烧写Hi3516DV300开发板【踩坑总结:网络环境有限制】
  15. 关于 Chrome Console 查看DOM详情细节的奇思淫巧
  16. 嵌入式 Linux C 代码规范和风格
  17. diamond java_Diamond语法何时在Java 8中不起作用?
  18. 男孩取名分享:光彩夺目、聪明机灵的男孩名
  19. Neo.4j 使用总结
  20. [LeetCode] 589. N-ary Tree Preorder Traversal

热门文章

  1. 网络管理人员应该掌握的技术
  2. 强化学习(Reinforcement Learning)入门学习--01
  3. oracle 登录失败次数,Oracle用户连续登录失败次数限制如何取消
  4. docker:error pulling image configuration
  5. 计算机无法屏幕亮度,win7电脑屏幕亮度无法调节怎么办?调节屏幕亮度的方法...
  6. 计算机微课ppt,全国“xx杯”计算机类说课大赛课件一等奖作品:制作“旅游专线”PPT微课课件.pptx...
  7. 工作室SWS自动化脚本
  8. git 相关文件指令随笔
  9. ExcelVBA批量添加PDF文件
  10. 面试的一般流程及其常见的问题