惧留孙网

juliusun.com

在线教程 > C语言教程 > 堆操作

堆操作

第 41/50 节 冥河C语言教程


计算机内存中有一块区域称为堆。堆可以由程序控制申请释放等操作。

堆也经常被称为动态内存。堆申请也被称为动态内存分配。堆就可以做到动态内存分配。希望其它资料上讲解动态内存分配不要陌生。

堆操作没有新的语法知识,仅仅是学习几个关于堆的函数。

堆操作函数一般封装在malloc.h中。需要引用头文件#include<malloc.h>。部分编译器是封装在stdio.h或stdlib.h中,必要时注意引用。

本节要介绍的函数有如下:

  malloc : 堆空间分配函数
    free : 堆空间释放
    calloc : 堆空间分配、初始数据清零函数。相比malloc,此函数会把申请的内存每个字节全部设置为0,少用,不重点介绍
    realloc : 修改指定堆空间大小函数

函数原型及解释如下:

void * malloc(unsigned int size)

参数size指定要申请的堆空间大小,单位为字节。返回值根据成功与否确定。分配失败返回NULL;分配成功返回被分配的堆空间指针。malloc返回void类型指针,使用时可以强制转换成自己需要的指针类型。

void free(void * p)

参数p指定要释放的堆空间地址。参数p要为堆分配函数如malloc、calloc、realloc等返回的地址。地址传递错误,运行时可能出错。函数无返回值。

void * calloc(unsigned int n,unsigned int size)

分配n块空间,每块大小是size字节。申请后的空间是连续的,总大小为n*size字节。申请成功,将这些空间每个字节都设置成0然后返回地址。申请失败返回NULL。calloc有点类似malloc(n*size),但是多一个把申请成功的空间清0的操作。此函数使用较少,本节不再详细介绍。

void * realloc(void *p,unsigned int size)

重新分配已成功申请的堆空间地址。参数p(一般为堆分配函数malloc、calloc返回的结果)为将要重新分配的堆空间地址,size为修改之后的空间大小。修改成功,返回新的堆空间地址,失败返回NULL。

注意:重新分配,realloc返回的地址可能与p相同或不同。当重新分配的空间大小大于以前时,realloc尽量在原地址扩展,扩展成功,就直接返回原地址p。扩展失败,会重新申请堆空间,并将p指向的堆空间数据复制到新空间中,释放掉原堆空间,然后返回新空间地址。重新分配失败,返回NULL。重新分配的空间小于原空间大小时,一般返回就是原空间地址。仅仅释放部分堆空间。

重新分配空间时,realloc会保留原有的数据。堆空间缩小时,保留新字节数的数据。

堆空间分配成功,不需要时请调用free函数释放系统资源,降低对系统资源的浪费。如果一直不释放申请的堆空间,程序直到退出系统才会自动收回。

举例说明,先让用户输入数字n,然后再输入n个整数。计算n个整数的值并输出算式。

分析,由于是用户动态输入n,所以用数组不合适,数组定义时必须是常量。数组元素定义少了,可能不无承受用户输入的数字个数,分配太多,会造成浪费。用堆合适,用户输入多少,分配相应的空间大小即可。例:


  1. #include<stdio.h>
  2. #include<malloc.h> //一般堆操作函数在此头文件中有定义
  3. int main( )
  4. {
  5. unsigned int n; //无符号整型来记录数字多少
  6. int *p,sum=0; //p用来记录堆空间地址,sum记录数字之和
  7. printf("您需要计算多少数字?\n");
  8. scanf("%d",&n);
  9. p = (int *)malloc(n * sizeof(int)); //int类型占用空间大小乘以n,才是要申请的字节数。malloc返回值void*要强制转换成int *
  10. printf("请输入运算数:\n");
  11. if(p == NULL) return 1; //如果分配失败,就退出
  12. for(unsigned int j = 0;j < n;++j)
  13. {
  14. scanf("%d",&p[j]);
  15. }
  16. for(unsigned int i = 0;i < n;++i)
  17. {
  18. if(i != 0)printf("+"); //当i不为0时,说明已经有数字输出,此时要输出一个加号
  19. printf("%d",p[i]); //以数组的方式引用指针。因为释放堆时还需要p,所以p不能自增自减,要保持原样
  20. sum += p[i];
  21. }
  22. free(p);//释放空间
  23. printf("=%d\n",sum);
  24. getchar( ) ;getchar( ) ; //使程序暂停一下
  25. return 0;
  26. }

根据输入情况,效果图不同:

Pic

修改下上面的题目,再拿realloc举个例子。假设用户不必提前输入数字,而是以输入0算作结尾。

例子解题思路是申请堆,输入数字放入堆。数字为0停止输入;数字不为,重新分配堆空间大小,新大小是原有基础上加一个int类型的大小。输入结束,输出算式时,同样遇到0算运算结束。例:


  1. #include<stdio.h>
  2. #include<malloc.h> //一般堆操作函数在此头文件中有定义
  3. int main( )
  4. {
  5. unsigned int n = 0; //记录用户输入多少int数字
  6. int *p,sum=0; //p用来记录堆空间地址,sum记录数字之和
  7. p = (int *)malloc(sizeof(int) ); //先申请一个int类型空间大小
  8. if(p == NULL) return 1; //如果分配失败,就退出
  9. puts("请输入数字,以0结束");
  10. do //至少输入一次,先输入后判断,用do-while比较合适
  11. {
  12. scanf("%d",&p[n]);
  13. if(p[n] != 0)
  14. {
  15. int * src = p; //保留原堆空间指针,重新分配失败时可以以此为参数释放
  16. p = (int *)realloc(src,(n + 2)*sizeof(int) ); //n是下标,原有大小是n+1个元素。新大小再加一个元素大小,即n+2
  17. if(p == NULL)
  18. {
  19. free(src); //重新分配失败释放原空间,停止继续执行
  20. return 1;
  21. }
  22. }
  23. }while(0 != p[n++]); //输入0停止输入,跳出循环。判断后n自增
  24. n = 0; //n清0,在以后的代码码记录数组下标
  25. while(p[n] != 0) //遇到计算结束
  26. {
  27. if(n != 0)printf("+"); //当i不为0时,说明已经有数字输出,此时要输出一个加号
  28. printf("%d",p[n]); //以数组的方式引用指针。因为释放堆时还需要p,所以p不能自增自减,要保持原样
  29. sum += p[n++]; //一轮计算完毕,n自增
  30. }
  31. free(p);//释放空间
  32. printf("=%d\n",sum);
  33. getchar( ) ;getchar( ) ; //使程序暂停一下
  34. return 0;
  35. }

根据输入情况,效果图不同:

Pic

效果图仅供参考。

作者:冥河 QQ:3304576112
交流QQ群:554701039 C语言讲课群
本教程内容由本站保留版权,请勿复制传播
抖音
©2015-2024 惧留孙网 juliusun.com

京ICP备15039193号-1

首页 教程 下载 文章 聊天 我的