一个C内存分配问题

来源:互联网 发布:淘宝第三方免费活动 编辑:程序博客网 时间:2024/04/29 21:28

今天一个C/C++群里的几个朋友在谈论一个C的内存分配问题,这个问题是先由一个朋友提出的,它写了如下一段代码:

char *p = (char *)malloc(10);

p = "akdfa";

char *q = (char *)realloc(p, 25);

结果在运行时出错了.

然后大家展开了讨论,结果无果而终。由于在群上不太容易表达自己的想法,下面我把自己和一个朋友的理解写一下.也欢迎大家对此问题进行讨论.

 

首先分析一下这个朋友的这三句代码(这是有必要的):

char *p = (char *)malloc(10);

编译器会在堆内存区申请一个10个字节的内存空间,然后令p指向它.

p = "akdfa";

这句代码我想已经脱离了那个朋友的原意,那个朋友肯定是想把"akdfa"放入刚才申请的那10个字节的内存空间中去.但是其实编译器并没有这样做.因为"akdfa"是一个常量字符串,编译器会自动把它放到常量内存区,然后把该字符串的首地址赋给p.其实这里我们已经改变了p的值。而刚才申请的那10个字节的内存空间其实我们已经丢失了,因为我们已无指针指向这段内存空间,我们已经无法对其进行操作了。这就产生了一个隐含的内存泄露问题.但是这两句话并不会引起运行时错误.其实错误是由第三句引起的.

char *q = (char *)realloc(p, 25);

这句代码的本意是不改变p的值,扩充其内存空间.的确如此.可是为什么这里会引发了一个运行时异常呢.关键就是p,在第二句的时候已经对其进行了解释,它不再指向堆内存区的一段内存.而是指向了常量内存区的一段内存.要想具体了解,只能看realloc的实现了.看了一下realloc的源码,虽然没有全部看懂,但可以看出来realloc是不容许对指向常量内存区的指针进行操作的,甚至数组也不可以.只允许对指向堆内存区的指针进行操作.我想要想对此进行解释,非常有必要贴一下realloc的源码了.

 

realloc的源码中,我们可以看到这样一个结构体struct header.从代码中我们可以看出它里面有一个size的成员用来指示当前分配空间的大小.由于没有找到这个结构体的具体实现和更多相关的资料。我只能猜测对于堆以外的其他内存区空间的指针没有这个结构体.因为他们都是有编译器自动进行分配的,无需我们进行操作。而realloc的源码中明明用到了这个结构体,可想而知它把其他内存区的指针给排除在外了,只允许指向栈空间的指针了.由于具体的我无法查证,只能做这个猜测了。若有了解内情的高手,请不吝指点.

为了对上面我所说的做一个证明,我们可以稍微修改一下那个朋友的三句代码:

char *p = (char *)malloc(10);

char *t = (char*)malloc(15);

p = "akdfa";

strcpy(t,p);

t = (char *)realloc(t,100);

ok,这样就不会出错了.因为我们使用了一个指向堆区的t指针代替了指向常量区的指针p.

上面我们也解释了,其实这样的写法存在隐式的内存泄露问题.也就是说上面的代码等价于:

char *t = (char*)malloc(15);

char *p = "akdfa";

strcpy(t,p);

t = (char *)realloc(t,100);

好的,我们如我们把p换成数组,即:

char *t = (char*)malloc(15);

char p[20] = "akdfa";

//strcpy(t,p);

t = (char *)realloc(p,100);

同样会产生运行时异常,这也说明了,realloc函数也无法对栈内存区指针进行操作.

后来那个朋友又问了这样一个问题,“如何对指针堆内存区的指针赋值呢?”

char *t = (char*)malloc(15);

我们该如何将一个常量字符串放到t所指向的控件之中呢?显然这样 t = "hello";是无法实现了,它改变了t的指向。对此我认为我说了这样一句话:

若是我们仅仅将一个常量字符串赋给一个指针的话,那么我们也没有必要为他申请空间了,(因为编译器会自动为我们申请,那也意味着我们只有只读的权利).如果我们要向把一个字符串放到一个堆内存区内,并还想扩展它的控件,我们可以借助strcpy函数实现.:

char *t = (char*)malloc(15);

strcpy(t,"hello");

t = (char *)realloc(t,100);

OK,我们将”hello”放到了t所指向的空间之中并实现了他的内存扩展.其实在使用中可能远没有如此简单,但是我们可以通过中间变量实现.根据实际问题进行实际的考虑吧.

 

原贴是在csdn学生大本营,王富涛笔记中http://student.csdn.net/space.php?uid=43658&do=blog&id=16735

原创粉丝点击