动态内存管理 前篇
C语言中的数据结构通常是固定大小的。例如,一旦程序完成编译,数组元素的数量就是固定的。
说到这里,有人就要说:变长数组呢?在C99中,变长数组的长度在运行时确定,但在数组的生命周期内仍然是固定的,因为在编写程序时强制选择了大小,所以固定大小的数据结构可能会有问题。也就是说,在不修改程序并且再次编译程序的情况下无法改变数据结构的大小对于空间的需求,有时候我们需要的空间大小在程序运行的时候才能知道,那数组的编译时开辟空间的方式就不能满足了。
这时候就只能试试动态存开辟了。
在调用内存分配函数时,总存在这样的可能性:找不到我们需要的足够大的内存块。那这样的话,函数就会返回空指针(NULL)
注意:
1. 程序员的任务是测试任意内存分配函数的返回值,并且要在返回值为空指针时采取适当措施
2. 通过空指针访问内存的行为是未定义的,程序可能会出现崩溃
在介绍具体的内存分配函数之前,先了解一下他们的功能:
- malloc:分配内存块,但是不对内存块进行初始化
- calloc:分配内存块,并且对内存块进行清零
- realloc:调整先前分配的内存块大小
- free :释放内存块
- 所有函数的头文件都是<stdlib.h>
void* malloc (size_t size);
这个函数向内存申请一块连续可用的空间,并返回指向这块空间的指针
🌰
#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
int main()
{
//申请10个整形类型
int* p = (int*)malloc(10 * sizeof(int));
//int* p=(int*)malloc(40);
//判断是否申请空间成功
if (p == NULL)
{
printf("%s\n", strerror(errno));
return 1;
}
//使用 存放1-10
for (int i = 0; i < 10; i++)
{
*(p + i) = i + 1;
}
//打印
for (int i = 0; i < 10; i++)
{
printf("%d ", *(p + i));
}
//释放申请的空间
free(p);
p = NULL;
return 0;
}
在这里解释一下:
🐉🐉🐉🐉🐉
当然了,有人还有疑问:为什么一定要释放申请的内存空间?释放了空间之后,为什么要置为空指针?
在这里,我来单独解释:
void* calloc (size_t num, size_t size);
🌰
#include<stdio.h>
#include<stdlib.h>
int main()
{
int* p = calloc(10, sizeof(int));
if (p == NULL)
{
perror(p);
return 1;
}
for (int i = 0; i < 10; i++)
{
printf("%d ", p[i]);
}
free(p);
p = NULL;
return 0;
}
//运行结果:
******
0 0 0 0 0 0 0 0 0 0
*****
malloc 和 calloc
有时会我们发现过去申请的空间太小了,有时候我们又会觉得申请的空间过大了,那为了合理的时候内存,我们一定会对内存的大小做灵活的调整。那 realloc 函数就可以做到对动态开辟内存大小的调整
void* realloc (void*ptr, size_t size)
#include<stdio.h>
#include<stdlib.h>
int main()
{
int* p = malloc(10 * sizeof(int));
//判断malloc函数是否开辟成功
if (p == NULL)
{
perror(p);
return 1;
}
int* ptr = realloc(p, 5 * sizeof(int));
//判断realloc函数是否开辟成功
if (ptr != NULL)
{
p = ptr;
}
for (int i = 0; i < 5; i++)
{
printf("%d ", p[i]);
}
free(p);
p = NULL;
return 0;
}
//运行结果:
*****
5个随机数
*****
🐉🐉🐉🐉🐉
看到这里,有人就有疑问了:realloc函数如果开辟失败,原有内存中的数据会怎么变化?为什么不是直接让p来接收realloc的结果?
解释:
🐉🐉🐉🐉🐉
此外,realloc函数还需要注意:
void free (void* ptr);
#include<stdio.h>
#include<stdlib.h>
int main()
{
int* p = (int*)malloc(INT_MAX );
*p = 20;//如果p的值是NULL,就会有问题
free(p);
return 0;
}
补充一下:
INT_MAX:2147483647
void test()
{
int i = 0;
int* p = (int*)malloc(10 * sizeof(int));
if (NULL == p)
{
exit(EXIT_FAILURE);
}
for (i = 0; i <= 10; i++)
{
*(p + i) = i;//当i是10的时候越界访问
}
free(p);
}
申请空间的单位一般都是字节
void test()
{
int a = 10;
int* p = &a;
free(p);//ok?
}
free函数是专门来释放动态开辟的内存空间的
void test()
{
int* p = (int*)malloc(100);
p++;
free(p);//p不再指向动态内存的起始位置
}
free函数的参数是要释放动态内存空间的起始地址
void test()
{
int *p = (int *)malloc(100);
free(p);
free(p);//重复释放
}
对同一个空间释放两次了 - 因为p一直保留着起始位置的地址
void test()
{
int *p = (int *)malloc(100);
free(p);
p=NULL;
free(p);//重复释放
}
这种不是对同一个空间释放空间两次 - 因为p已经置为空了,对空指针进行free操作是没有意义的
void test()
{
int* p = (int*)malloc(100);
p++;
free(p);//p不再指向动态内存的起始位置
}
void test()
{
int* p = (int*)malloc(100);
if (NULL != p)
{
*p = 20;
}
}
int main()
{
test();
while (1);
}
动态开辟的空间一定要释放,并且要正确释放,否则会造成内存泄漏
码文不易,各位看官一键三连哦 💕💕💕
各位的鼓励与支持是我前进最大的动力
作为我的Rails应用程序的一部分,我编写了一个小导入程序,它从我们的LDAP系统中吸取数据并将其塞入一个用户表中。不幸的是,与LDAP相关的代码在遍历我们的32K用户时泄漏了大量内存,我一直无法弄清楚如何解决这个问题。这个问题似乎在某种程度上与LDAP库有关,因为当我删除对LDAP内容的调用时,内存使用情况会很好地稳定下来。此外,不断增加的对象是Net::BER::BerIdentifiedString和Net::BER::BerIdentifiedArray,它们都是LDAP库的一部分。当我运行导入时,内存使用量最终达到超过1GB的峰值。如果问题存在,我需要找到一些方法来更正我的代
我正在使用i18n从头开始构建一个多语言网络应用程序,虽然我自己可以处理一大堆yml文件,但我说的语言(非常)有限,最终我想寻求外部帮助帮助。我想知道这里是否有人在使用UI插件/gem(与django上的django-rosetta不同)来处理多个翻译器,其中一些翻译器不愿意或无法处理存储库中的100多个文件,处理语言数据。谢谢&问候,安德拉斯(如果您已经在rubyonrails-talk上遇到了这个问题,我们深表歉意) 最佳答案 有一个rails3branchofthetolkgem在github上。您可以通过在Gemfi
我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚
ruby如何管理内存。例如:如果我们在执行过程中采用C程序,则以下是内存模型。类似于这个ruby如何处理内存。C:__________________|||stack|||------------------||||------------------|||||Heap|||||__________________|||data|__________________|text|__________________Ruby:? 最佳答案 Ruby中没有“内存”这样的东西。Class#allocate分配一个对象并返回该对象。这就是程序
几个月前,我读了一篇关于rubygem的博客文章,它可以通过阅读代码本身来确定编程语言。对于我的生活,我不记得博客或gem的名称。谷歌搜索“ruby编程语言猜测”及其变体也无济于事。有人碰巧知道相关gem的名称吗? 最佳答案 是这个吗:http://github.com/chrislo/sourceclassifier/tree/master 关于ruby-寻找通过阅读代码确定编程语言的rubygem?,我们在StackOverflow上找到一个类似的问题:
我安装了ruby版本管理器,并将RVM安装的ruby实现设置为默认值,这样'哪个ruby'显示'~/.rvm/ruby-1.8.6-p383/bin/ruby'但是当我在emacs中打开inf-ruby缓冲区时,它使用安装在/usr/bin中的ruby。有没有办法让emacs像shell一样尊重ruby的路径?谢谢! 最佳答案 我创建了一个emacs扩展来将rvm集成到emacs中。如果您有兴趣,可以在这里获取:http://github.com/senny/rvm.el
是否有简单的方法来更改默认ISO格式(yyyy-mm-dd)的ActiveAdmin日期过滤器显示格式? 最佳答案 您可以像这样为日期选择器提供额外的选项,而不是覆盖js:=f.input:my_date,as::datepicker,datepicker_options:{dateFormat:"mm/dd/yy"} 关于ruby-on-rails-事件管理员日期过滤器日期格式自定义,我们在StackOverflow上找到一个类似的问题: https://s
?博客主页:https://xiaoy.blog.csdn.net?本文由呆呆敲代码的小Y原创,首发于CSDN??学习专栏推荐:Unity系统学习专栏?游戏制作专栏推荐:游戏制作?Unity实战100例专栏推荐:Unity实战100例教程?欢迎点赞?收藏⭐留言?如有错误敬请指正!?未来很长,值得我们全力奔赴更美好的生活✨------------------❤️分割线❤️-------------------------
嗨~大家好,这里是可莉!今天给大家带来的是7个C语言的经典基础代码~那一起往下看下去把【程序一】打印100到200之间的素数#includeintmain(){ inti; for(i=100;i 【程序二】输出乘法口诀表#includeintmain(){inti;for(i=1;i 【程序三】判断1000年---2000年之间的闰年#includeintmain(){intyear;for(year=1000;year 【程序四】给定两个整形变量的值,将两个值的内容进行交换。这里提供两种方法来进行交换,第一种为创建临时变量来进行交换,第二种是不创建临时变量而直接进行交换。1.创建临时变量来
我想用这两种语言中的任何一种(最好是ruby)制作一个窗口管理器。老实说,除了我需要加载某种X模块外,我不知道从哪里开始。因此,如果有人有线索,如果您能指出正确的方向,那就太好了。谢谢 最佳答案 XCB,X的下一代API使用XML格式定义X协议(protocol),并使用脚本生成特定语言绑定(bind)。它在概念上与SWIG类似,只是它描述的不是CAPI,而是X协议(protocol)。目前,C和Python存在绑定(bind)。理论上,Ruby端口只是编写一个从XML协议(protocol)定义语言到Ruby的翻译器的问题。生