外部函数中申请内存
来源:互联网 发布:学网店美工要多久 编辑:程序博客网 时间:2024/05/17 04:35
在我们使用指针传递内存的时候,必须谨慎小心,否则常常会对非法内存(空地址、错误地址)进行操作。下面我们通过一个程序来说明一些需要注意的问题。
#include <stdio.h>
#include <stdlib.h>
voidtest1(char* p, intnum)
{
p = (char *)malloc(sizeof(char) * num);
}
voidtest2(char** pp, intnum)
{
*pp = (char *)malloc(sizeof(char) * num);
}
voidmain()
{
char* p = NULL;
char** pp = NULL;
test1(p, 10);
printf("No1.After test1(p, 10), the value of p is: %x/n", p);
test2(&p, 10);
printf("After test2(&p, 10), the value of p is: 0x%x/n", p);
/*
test2(pp, 10);
printf("After test2(pp, 10), the value of pp is: 0x%x/n", pp);
*/
pp = (char **)malloc(10*sizeof(char *));
test2(pp, 10);
printf("After test2(pp, 10), the value of pp is: 0x%x/n", pp);
}
在上面的程序中,我们实现了两个函数,test1中我们使用传入的参数char* p申请了一段内存,该段内存用于存储char型的数据。test2中我们使用传入的参数char** pp申请了一段内存,该段内存也是存储char型数据的。但是两个申请过程有所不同。需要注意的是p是char*, *pp也是char*。
阐明上面的程序之前我想先说一个老例子,函数
voidplus1(intn)
{
n = n+1;
}
不用废话大家都知道plus1是不会修改n的值的,因为在n传入函数之后会拷贝一份,修改的只是这份拷贝,而传入的这个n值是不会变的。
voidplus2(int* n)
{
*n = *n+1;
}
plus2因为使用指针,也就是传入了n的地址值,那么对*n的操作实际上就是对n的操作。所以*n增1,也就是n增1。这个例子虽然简单,但是真的是经典,指针的好处和坏处都显示出来了。好处就是可以通过传递指针来实际操作数值,坏处就是传递指针有可能对内存进行非法操作。
再回到上面的程序,我们可以看到输出结果为:
No1.After test1(p, 10), the value of p is: 0
No2.After test2(&p, 10), the value of p is: 0x3407e0
No4.After test2(pp, 10), the value of pp is: 0x340818
明显的使用test1(p, 10)申请内存失败了,如果大家真正明白了上面plus1和plus2的例子,就也应该明白了test1(p, 10)申请失败的原因。事实上是“如果我们希望在函数外部获得函数参数在函数内部被修改的结果,那么我们需要使用该参数的‘上一层’指针”。需要注意的是这句话中的上一层指针的概念,这是我自己发明的一个词语,例如char* 就是char的上一层指针,char** 就是char*的上一层指针,依此类推。
那么好,让我们来看一下test1(p, 10)失败的原因。当我们传入char* p的时候,实际上此时p==NULL,那么我们的原因是希望在test1调用完成之后让p指向一个内存地址,也就是希望在外部获取p在函数内部的修改结果。此时如果我们传入p,那么进入函数test1后,会拷贝一份p,我们称之为_p,那么后续语句中对p的操作实际上就是对_p的操作,紧接着我们调用了malloc申请内存,返回值放入了_p中,也就是修改了_p。函数结束后,p并没有受到这份改变的影响,依旧是NULL。所以输出为0。
看到这里如果大家明白的话,就应该立刻反映出我们应该使用char** p来获得申请的内存。答案是yes,但是也没有那么简单,还是存在一个陷阱。
再看函数test2,函数test2和test1的目的一样,只是参数改为了char** p。那么我们可以使用两种方式调用该函数第一种是test2(&p, 10),其中p还是char*,这个函数会调用成功,char* p会保存申请后的地址。或者我们直接调用test2(pp, 10),其中pp是char**类型,我们会发现程序异常结束,因为程序会试图在非法内存中写入数据。为什么会这样呢?因为char** pp==NULL,也就是说pp指向的内存空间并不存在,我们可以先设pp指向的内存为x,而我们在test2中的目的是让x中保存某个内存块的地址。在x不存在的情况下,这么做自然是向非法地址写入数据了。那么怎么办呢?呵呵,只需要先申请这个x就可以了,也就是
pp = (char **)malloc(10*sizeof(char *));
test2(pp, 10);
printf("After test2(pp, 10), the value of pp is: 0x%x/n", pp);
这段程序的来由,现在大家明白我为什么注释掉No.3那段程序了吧,因为它根本不能运行。
而在test2(&p, 10)中x实际一进存在了,就是p啊,所以不需要提前申请。
通过这个例子,大家可以看到了通过函数申请内存是一件麻烦、危险的事情。所以我们在处理类似程序的时候,一定要小心。
- 外部函数中申请内存
- 如何在函数体内给外部指针申请内存
- 关于在dll中申请内存,外部释放的问题
- 关于在dll中申请内存,外部释放的问题
- 关于在dll中申请内存,外部释放的问题
- 关于在dll中申请内存,外部释放的问题
- 关于lwip中pbuf_alloc()内存申请函数
- lwip中pbuf_alloc()内存申请函数
- 申请内存的函数
- C内存申请函数
- 内存申请函数
- 函数动态申请内存
- C申请内存函数
- C中用户空间申请内存的函数!!!!!
- C语言中常用的几个内存申请函数
- [简记]内核中申请内存和用户空间中申请内存的函数(kmalloc/vmalloc/malloc)对比
- request_mem_region 申请内存函数讲解
- inux内核申请内存函数
- vim 的一些使用方法,如设置行号,开启自动缩进等
- Spring 2 和 JPA 简介
- 2006年10月18日随笔
- 2006年10月24日一周综述
- 再读《中国惠普前总裁孙振耀谈工作与生活》之一:健康第一
- 外部函数中申请内存
- 2006年10月25日数据库试验
- 七种VC延时方式
- 微软的SLP软件加密保护服务
- Ibatis学习随笔
- 2006年10月26日数据库
- 再读《中国惠普前总裁孙振耀谈工作与生活》之二:做自己想做的事情
- 世界500强企业名称中英对照(续)
- (电脑类)内存参数识别----购买内存需知