关于realloc的问题

fatpenguin 2005-04-14 04:24:31
每次使用realloc多申请一个sizeof(int)的空间。
=========================================
void
main()
{
int i;
int dataList[5] = {1, 2, 3, 4, 0};
int* numList = (int*)malloc(sizeof(int));
int* tempNumList = numList;

for(i = 0; i < 5; i++){
*tempNumList++ = dataList[i];
numList = (int*)realloc(numList, sizeof(int)); //xxx
}

printf("\n");
while(*numList != 0){
printf("%d ", *numList++);
}
}
=============================================
结果很奇怪:1, -33686019, 3, 4。
除了第二个数字以外其他都正常。
如果考虑realloc的第二个参数是‘增加到’的大小,那么xxx处改为sizeof(int)*(i+2)运行到第二个循环以后numList就会换位置。
请教各位,多谢!
...全文
397 14 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
14 条回复
切换为时间正序
请发表友善的回复…
发表回复
fatpenguin 2005-04-16
  • 打赏
  • 举报
回复
多些各位,尤其是pcboyxhy(-273.15℃)。
fatpenguin 2005-04-15
  • 打赏
  • 举报
回复
嗬嗬,您可能没有明白我的意思,我是说“这样一个可以改变却又马上恢复的空间是什么样的空间”,比如它是系统或者应用程序使用的?当然地址我是知道的。
呵呵,是有点胡搅蛮缠了。再等您一句话我就结了,不好意思。
pcboyxhy 2005-04-15
  • 打赏
  • 举报
回复

for(i = 0; i < 5; i++){
*tempNumList++ = dataList[i];
printf("%x\n", numList); //加一句这个看看就知道了
numList = (int*)realloc(numList, sizeof(int)); //xxx
}
fatpenguin 2005-04-15
  • 打赏
  • 举报
回复
谢谢各位,不过我还有个疑惑,就是用 numList = (int*)realloc(numList, sizeof(int)); 反复分配一个空间时为什么会只有第二个数不是我所希望的,虽然在 *tempNumList++ = dataList[1]; 可以改变为2,但往下走一步马上就恢复到-33686019了,而其他几个空间还都可以改变。但是编译和运行都没有任何提示,请问这样一个可以改变却又马上恢复的空间是什么样的空间呢?
pcboyxhy 2005-04-15
  • 打赏
  • 举报
回复
第二句里tempNumList我觉得应该是一个指向指针的指针吧!

不是指向指针的指针
pcboyxhy 2005-04-15
  • 打赏
  • 举报
回复
realloc( )返回的值未必是原来的那个地址的值
但是他会把原来的那个地址上的存的值复制到新的空间去
这个空间就是堆的一部分

不同的编译器对于 realloc 的实现在遵守标准的前提下还有细微差异的区别。
像你这段代码在MinGW Studio2.05所带的GCC下编译后运行就会崩溃。
因为你使用的方法没有遵守标准。


xioxu 2005-04-15
  • 打赏
  • 举报
回复
我再请教下 int* numList = (int*)malloc(sizeof(int));
int* tempNumList = numList;
第二句里tempNumList我觉得应该是一个指向指针的指针吧!
rocklabzhang 2005-04-15
  • 打赏
  • 举报
回复
学习
dongpy 2005-04-14
  • 打赏
  • 举报
回复
那么xxx处改为sizeof(int)*(i+2)运行到第二个循环以后numList就会换位置。
=========================================================================
是因为紧接着的连续自由空间不够分配,所以需要重新分配空间了,分配以后再把原空间的内容拷贝过来,然后释放原空间。
chunhai12 2005-04-14
  • 打赏
  • 举报
回复
学习
pcboyxhy 2005-04-14
  • 打赏
  • 举报
回复
http://dev.csdn.net/develop/article/27/27950.shtm
作者Blog:http://blog.csdn.net/eliner/





首先看一下下面的C程序片断:



#include <malloc.h>

char *p;

p = (char * ) malloc (10);

p = (char * ) realloc (p,20);

…………………………



这段程序的意思很简单,只有稍有点C基础的人都可以看懂。函数首先定义了一个字符型的指针p,然后为指针p分配了一个10个字节大小的内存空间,接着将这个内存块的大小增加到20个字节。



这里有什么问题吗?上机运行一下,好像没有问题!



是的,这样上机运行是没有问题的,但是这里存在着也许我们不太注意的隐患!隐患在那里?这就是我在本文中要详细说明的realloc()函数了。



再看一下下面一段来自MSDN的话:

realloc returns a void pointer to the reallocated (and possibly moved) memory block. The return value is NULL if the size is zero and the buffer argument is not NULL, or if there is not enough available memory to expand the block to the given size. In the first case, the original block is freed. In the second, the original block is unchanged. The return value points to a storage space that is guaranteed to be suitably aligned for storage of any type of object. To get a pointer to a type other than void, use a type cast on the return value.

这段E文还不算是晦涩难懂,所以我就不翻译了,大致的意思是说关于realloc返回值的。但是这里对他的返回值分了几种情况:

1、 返回void * 指针,调用成功。

2、 返回NULL,当需要扩展的大小(第二个参数)为0并且第一个参数不为NULL,此时原内存变成了“freed(游离)”的了。

3、 返回NULL,当没有足够的空间可供扩展的时候,此时,原内存空间的大小维持不变。



第一种情况告诉了我们在得到需要的内存空间后需要做类型转换的工作;

第二种情况可能只有傻瓜才会去使用吧!

第三种情况,内存空间不够的时候就会维持未来的大小不变。



MSDN上面说内存空间不够的时候就不会扩展原来的内存空间的大小,这话固然没有错,但是有点含糊,似乎遗漏了一种情况!我们知道,realloc是从堆上分配内存的,当扩大一块内存空间时, realloc()试图直接从堆上现存的数据后面的那些字节中获得附加的字节,如果能够满足,自然天下太平;可如果数据后面的字节不够的话,问题就出来了,那么就使用堆上第一个有足够大小的自由块,现存的数据然后就被拷贝至新的位置,而老块则放回到堆上。这句话传递的一个重要的信息就是数据可能被移动!看到这里,也许我们已经发现一开始我给出的程序的问题了。为了更清楚地说明问题,可以将上面的程序改成下面的形式:



#include <malloc.h>

char *p,*q;

p = (char * ) malloc (10);

q=p;

p = (char * ) realloc (p,20);

…………………………



这段程序也许在编译器中没有办法通过,因为编译器可能会为我们消除一些隐患!在这里我们只是增加了一个记录原来内存地址的指针q,然后记录了原来的内存地址p,如果不幸的话,数据发生了移动,那么所记录的原来的内存地址q所指向的内存空间实际上已经放回到堆上了!这样一来,我们应该终于意识到问题的所在和可怕了吧!



这个问题似乎有点牛角尖的味道,因为我们也许从来不曾遇上过,但是我们应该明白这样的事情的始终存在,只有这样,在万一我们碰上的时候才会去有意识的去避免这种隐患,否则,一旦这样的隐患一旦发作,程序崩溃不说,恐怕查错也不是一件容易的事!



候俊杰在《深入浅出MFC》中引用林语堂的《朱门》中的一句话,我很有感触,虽然不可能有他的感触深,但是抱着向前辈学习的心态,所以也拿来作为本为的结束:



“只用一样东西,不明白他的道理,实在不高明”。

pcboyxhy 2005-04-14
  • 打赏
  • 举报
回复
for(i = 0; i < 5; i++)
{
*tempNumList++ = dataList[i];
numList = (int*)realloc(numList, sizeof(int)); //xxx
}

问题的根本原因在于
numList = (int*)realloc( ); // 这里的numList可能会改变
当原来的numList后面的内存不够扩展时,就会分配堆里第一快足够大小的可用内存
所以numList的值已经改变

*tempNumList++ = dataList[i]; //而 tempNumList的操作还是针对原来的连续内存的
junmayang 2005-04-14
  • 打赏
  • 举报
回复
numList = (int*)realloc(numList, sizeof(int)); //xxx
第二个参数肯定不对啊,每次都只有一个大小,该改成
numList = (int*)realloc(numList, (i + 2) * sizeof(int)); //xxx

最好是把循环改成这样更简单,可以不用tempNumList:
for(i = 0; i < 5; i++){
numList = (int*)realloc(numList, (i + 1) * sizeof(int)); //xxx
*(numList + i) = dataList[i];
}
dongpy 2005-04-14
  • 打赏
  • 举报
回复
for(i = 0; i < 5; i++){
*tempNumList++ = dataList[i];
numList = (int*)realloc(numList, sizeof(int)); //xxx
}
=====================================
numList始终指向同一块内存,大小4字节。

*tempNumList++ = dataList[i];这里从i==1开始就访问越界了,访问了未分配的堆内存。

70,023

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧