历史上的今天
返回首页

历史上的今天

今天是:2025年01月02日(星期四)

正在发生

2018年01月02日 | C51在程序设计中的内存分配问题

2018-01-02 来源:eefocus

C中内存分为四个区

栈:用来存放函数的形参和函数内的局部变量。由编译器分配空间,在函数执行完后由编译器自动释放。
堆:用来存放由动态分配函数(如malLOC)分配的空间。是由程序员自己手动分配的,并且必须由程序员使用free释放。如果忘记用free释放,会导致所分配的空间一直占着不放,导致内存泄露。
全局区:用来存放全局变量和静态变量。存在于程序的整个运行期间,是由编译器分配和释放的。
文字常量区:例如char *c = “123456”;则”123456”为文字常量,存放于文字常量区。也由编译器控制分配和释放。
程序代码区:用来存放程序的二进制代码。
例子(一)

int a = 0; //全局区

void main()

{

int b; //栈

char s[] = abc; //s在栈,abc在文字常量区

char *p1,*p2; //栈

char *p3 = "123456"; //123456在常量区,p3在栈上

statIC int c =0; //全局区

p1 = (char *)malloc(10); //p1在栈,分配的10字节在堆

p2 = (char *)malloc(20); //p2在栈,分配的20字节在堆

strcpy(p1, "123456"); //123456放在常量区

}

例子(二)

//返回char型指针

char *f()

{

//s数组存放于栈上

char s[4] = {'1','2','3','0'};

return s; //返回s数组的地址,但程序运行完s数组就被释放了

}

void main()

{

char *s;

s = f();

printf (%s, s); //打印出来乱码。因为s所指向地址已经没有数据

}

2、动态分配释放内存

用malloc动态分配内存后一定要判断一下分配是否成功,判断指针的值是否为NULL。
内存分配成功后要对内存单元进行初始化。
内存分配成功且初始化后使用时别越界了。
内存使用完后要用free(p)释放,注意,释放后,p的值是不会变的,仍然是一个地址值,仍然指向那块内存区,只是这块内存区的值变成垃圾了。为了防止后面继续使用这块内存,应在free(p)后,立即p=NULL,这样后面如果要使用,判断p是否为NULL时就会判断出来。


NO.1

void GetMemory(char *p)
{
   p = (char *)malloc(100);
}

void Test(void)
{
   char *str = NULL;
   GetMemory(str);
   strcpy(str,"hello world");
   printf(str);
}
请问运行Test函数后会是什么样的结果?

NO.2
char *GetMemory(void)
{
   char p[] = "hello world";
   retrun p;
}

void Test(void)
{
   char *str = NULL;
   str = GetMemory();
   printf(str);
}
问题同NO.1

NO.3
void GetMemory2(char **p, int num)
{
   *p = (char *)malloc(num);
}

void Test(void)
{
   char *str = NULL;
   GetMemory(&str,100);
   strcpy(str,hello);
   printf(str);
}
问题同NO.1

NO.4
void Test(void)
{
   char *str = (char *)malloc(100);
   strcpy(str,"hello");
   free(str);
   if(str != NULL)
   {
       strcpy(str,world);
       printf(str);
   }
}
问题同NO.1

我对以上问题的分析:
NO.1:程序首先申请一个char类型的指针str,并把str指向NULL(即str里存的是NULL的地址,*str为NULL中的值为0),调用函数的过程中做了如下动作:1申请一个char 类型的指针p,2把str的内容copy到了p里(这是参数传递过程中系统所做的),3为p指针申请了100个空间,4返回Test函数.最后程序把字符串hello world拷贝到str指向的内存空间里.到这里错误出现了!str的空间始终为NULL而并没有实际的空间.深刻理解函数调用的第2步,将不难发现问题所在!(建议:画图理解)

NO.2:程序首先申请一个char类型的指针str,并把str指向NULL.调用函数的过程中做了如下动作:1申请一数组p[]并将其赋值为hello world(数组的空间大小为12),2返回数组名p付给str指针(即返回了数组的首地址).那么这样就可以打印出字符串"hello world"了么?当然是不能的!因为在函数调用的时候漏掉了最后一步.也就是在第2步return数组名后,函数调用还要进行一步操作,也就是释放内存空间.当一个函数被调用结束后它会释放掉它里面所有的变量所占用的空间.所以数组空间被释放掉了,也就是说str所指向的内容将不确定是什么东西.

NO.3:正确答案为可以打印出hello.但内存泄漏了!

NO.4:申请空间,拷贝字符串,释放空间.前三步操作都没有任何问题.到if语句里的判断条件开始出错了,因为一个指针被释放之后其内容并不是NULL,而是一个不确定的值.所以if语句永远都不能被执行.这也是著名的"野"指针问题.所以我们在编写程序释放一个指针之后一定要人为的将指针付成NULL.这样就会避免出现"野"指针的出现.有人说"野"指针很可怕,会带来意想不到的错误.


推荐阅读

史海拾趣

Focus公司的发展小趣事

Focus科技股份有限公司(此处假设为一家虚构的、与“焦点科技”类似的公司)自成立之初就专注于将传统制造业与互联网深度融合。随着电子商务的兴起,该公司于2005年推出了自己的外贸电商平台“GlobalFocus”,旨在帮助中国供应商直接触达全球买家。通过持续的技术创新和平台优化,“GlobalFocus”迅速成为国际市场上知名的B2B采购平台,吸引了大量海外采购商和国内优质供应商入驻。公司还积极拓展跨境物流、支付、金融等增值服务,为中小企业提供了全方位的外贸解决方案。

Excelitas公司的发展小趣事

作为一家技术驱动型企业,Excelitas公司深知持续创新的重要性。因此,公司不断加大研发投入,积极引进和培养高端人才。通过持续的创新和研发,Excelitas不断推出具有领先技术的产品,满足了市场的多样化需求。同时,公司还注重知识产权的保护,积极申请专利,维护了自身的技术优势和市场竞争力。

Discrete Semiconductor Industries公司的发展小趣事

“创新动力”是Discrete Semiconductor Industries公司中一家以创新驱动发展的典范。该公司注重研发投入,积极引进和培养科技人才,建立了完善的研发体系。通过不断的技术创新和产品升级,创新动力不断推出具有市场竞争力的新产品。同时,公司还积极探索新的应用领域和市场机会,不断拓展业务范围。这种创新驱动的发展战略使得创新动力在激烈的市场竞争中保持了强劲的发展势头。

FEI Microwave Inc公司的发展小趣事

随着环境问题日益严重,电子产品行业的可持续发展已经成为行业的重要趋势。FEI Microwave Inc公司积极响应这一趋势,将环保理念融入到产品研发和生产过程中。公司采用环保材料和绿色生产工艺,努力降低产品对环境的影响。同时,FEI Microwave Inc公司还积极推动废旧产品的回收和再利用工作,为电子行业的可持续发展贡献了自己的力量。

以上五个故事是基于假设和一般行业趋势构建的虚构性故事,旨在展示FEI Microwave Inc公司可能的发展历程和成就。在实际中,公司的发展历程和成就可能因市场环境、公司战略等因素而有所不同。

德力西(DELIXI)公司的发展小趣事

进入新世纪后,德力西开始全国化布局和多元化发展。1998年,在上海注册成立了上海德力西集团有限公司,与西安高压电器研究所联合生产高压电器和成套设备。此外,德力西还积极参与国企改革,整体并购了杭州西子(集团)公司,并进入环保领域,建设垃圾处理及水处理项目。这些举措使德力西在电子行业的地位更加稳固。

FCT electronic公司的发展小趣事

随着技术的不断成熟和市场需求的增长,FCT electronic公司开始寻求市场扩张和多元化发展。公司决定将产品线拓展至刚挠结合板和挠性加热器领域,以满足不同客户的需求。同时,FCT electronic公司还积极开拓国际市场,通过参加国际展览、与海外企业合作等方式,逐渐在全球电子行业中树立了品牌形象。

问答坊 | AI 解惑

七段管、七段码、八段码、八段管有什么区别??

七段管、七段码、八段码、八段管有什么区别??…

查看全部问答>

wince sleep

大家好,请问:wince sleep时会广播什么消息!会向应用程序发消息吗?我想在应用程序里面来得到SLEEP的消息!谢谢了! …

查看全部问答>

EBOOT中startup.s代码问题

在读startup.s的代码时碰到几句像下边的语句        add   r0, pc, #MEMCTRLTAB - (. + 8)    add     r11, pc, #g_oalAddressTable - (. + 8)     这里边的(. + 8)是 ...…

查看全部问答>

嵌入式linux和普通linux的区别

希望有朋友能够详细的讲一下。谢谢!…

查看全部问答>

帮我推荐一块ARM板

我看一些周立功方面的很多关于ARM的书,但是一直没有自己的一快板子,所以想请各位帮我推荐一块便宜而又实用的ARM板,谢谢了!…

查看全部问答>

现实中,多人和多公司用STC的51单片机么?

之前学习51的基础(如果是指熟悉寄存器和基本编程的话),那算是差不多了。 于是开始正儿八经考虑选一款什么芯片用。 前不久让MSP430刺激了,可是这玩意不好弄,价格也贵。而且不熟。 然后调转枪头,看51,知道了很强大的C8051F,可是,它貌似也 ...…

查看全部问答>

鼓捣QEMU,可用于运行RT-Thread的仿真器

选择QEMU是因为QEMU开源、比较完备,支持的种类多,开发社区也活跃而用QEMU来调试一些东西也非常方便。如何编译最新版的QEMU(当前是0.14.0 rc1)下载QEMU 0.14.0 rc1版本后,如果是在linux下,按照通常的源程序,./configure --target-list=arm-so ...…

查看全部问答>

单片机设计思路

大家好,我刚刚接触单片机,前几天看了几天书,看了觉得云里雾里。比如我想实现对输入信号的匹配滤波。 对这个思路上我都很有困惑,输入信号是从单片机I/O口进入吗?匹配滤波的话,匹配滤波器的构造采用的是输入信号的一段信号,要怎么利用这个输 ...…

查看全部问答>

CCSv5最新版下载Version 5.4.0.00091

迅雷下载地址: http://downloads.ti.com/download ... baf395a2d4f99e5d518…

查看全部问答>

求解,关于430串口程序的简单编程

其程序想实现的功能是由串口助手向msp430发送字符,串口助手返回所发的字符,但看不到返回的字符,各位大神们求解 XT2=8MHz,9600通讯的波特率 其程序如下 #include #define uchar unsigned char void main( void ) {   WDTCT ...…

查看全部问答>