一个C内存分配问题

今天一个 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 所指向的空间之中并实现了他的内存扩展. 其 实在使用中可能远没有如此简单,但是我们可以通过中间变量实现. 根据实际问题进行实际的考虑吧.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值