高手进,一个关于内存越界的问题,100分
问题我也说不清楚,给个程序,大家给解释一下结果吧
编译环境:xp&sp2+vc6.0&sp6
程序一
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void foo(void *rep)
{
char data[31] = "123456789012345678901234567890 ";
memcpy(rep, data, 31);
}
int main()
{
//char *p = (char*)malloc(10*sizeof(char)); //a
//char *p = (char*)malloc(20*sizeof(char)); //b
//char p[20]; //c
char *p1 = "098765432109876543210987654321 ";
//printf( "hello\n "); //e
memcpy(p, p1, 31);
printf( "p: %s\n ", p);
foo((void*)p);
printf( "p: %s\n ", p);
//free(p); //d
return 0;
}
麻烦大家运行一下几种排列,其中f(a)表示去掉a处的注释,f(b)等同:
debug方式:
1, f(a)
2, f(b)
3, f(a)&&f(d)
4, f(b)&&f(d)
5, f(c)
6, f(c)&&f(d)
release方式:
1, f(a)
2, f(b)
3, f(a)&&f(d)
4, f(b)&&f(d)
3, f(a)&&f(d)&&f(e)
4, f(b)&&f(d)&&f(e)
5, f(c)
6, f(c)&&f(d)
如果有unix的机器,麻烦用cc或gcc再运行一遍
本来打算把结果说一下,但情况太多了,也说不清楚,麻烦大家运行一下,帮忙解释一下结果,谢谢
[解决办法]
当printf( "%s ")输出的时候,当遇过字符串中的‘\0’时停止读取,因为你的字符串越界了,
所以当它读的时候就不一定读到什么了,因为它的停止是不可控的,这个问题不须想了,没有意义。
[解决办法]
我在wince底下跑了你的程序,证实了了你的程序数组的越界是因为malloc分配空间不够,你的字符串进入首地址后,后面多出的未分配空间的字符串强占了别人的空间造成冲突。改成如下就不会越界了,正如楼上几位说的。
char *p = (char*)malloc(31*sizeof(char));你可以分配超过31的任何大小
其他地方没有什么问题。不过在你malloc时最好memset一下因为p里面的数值刚分配的是乱七八糟的数据。最好清下零防止意想不到的错误。
还有malloc和free本来就该配对用没什么好说的不然会造成内存泄露后果很严重。:)
[解决办法]
如果是在栈上,比如malloc出来的,可以通过 _msize 得到大小
如:
#include "iostream "
using namespace std;
int main()
{
char *p = (char*)malloc(31*sizeof(char));
int size = _msize(p);
cout < <size < <endl;
return 0;
}
[解决办法]
用malloc分配出的内存,实际上分配的大小比你需要的多几个字节。那几个字节就用来保存诸如分配的大小,下一个可用此类的数据,这个与具体的malloc实现有关。所以只要你在free()中给出了正确的分配首地址,它自会知道从哪一段到哪一段需要释放。也是同样的道理,如果你误写了分配区域之前或是之后的地址,那一个可能是你会擦掉记录那些关键信息的字段,另一个可能是影响到另一个malloc分配出的正在被别人使用的内存块。两者的后果都是不可预知的。
[解决办法]
恩正如
bigbee(阿风)
所说,一个 malloc 出来的空间比实际的要多,多出来的这个部分
一个在malloc返回的地址前偏移一段空间,比如 32 字节,在这个
32字节里,保存在堆大小等信息,这个跟不同平台的malloc的实现
有关,没必要再深究了
[解决办法]
跟踪了一下,在vs.net2005下,malloc初次分配一块内存的时候,将一堆信息存在_CrtMemBlockHeader里面,并且链接到已分配内存的链表的头上。每分配一块内存,额外的开销是32字节(sizeof(_CrtMemBlockHeader))+内存大小+4字节(尾部的gap)。在debug模式下,free实际调用的是_free_dbg,该函数在_ASSERTE(_CrtIsValidHeapPointer(pUserData))处失败。
f(a)和f(b)实际上破坏了跟在该块内存后面的内存块的_CrtMemBlockHeader,stdarg.c所分配的内存。
Release下的代码无法跟踪,而且进行了许多优化,如此只能读汇编指令,这样问题就比较复杂了。
------解决方案--------------------
内存分配在堆和栈的情况不一样的。
一般调用malloc,分配出来的内存会比你需要的稍微大一些。因为malloc是从当前空闲内存表中找出一块和你需要大小最接近但是大于你要的块分给你。
在堆中的内存越界,一般会引起段错误,造成进程中止。
在栈中的数据,因为每个进程启动时,系统会给他分配一块内存作为栈。VC下的默认栈大小为1M。在链接的时候可以设置栈的大小。栈中越界不会造成段错误,如果是写越界,会破快其他数据,造成不可预知的错误。读取越界,只是读取的数据不可预知,随之可能产生其他的意外错误,也可能不会。如果只是用来printf,只是后面的结果不可预知。
有一种情况,你在栈中写越界了,但是你越界写的是一块未用的栈空间,随后又读取了这些数据,表面上来看,程序运行结果是正确的,掩盖了内存越界的错误。
[解决办法]
问题解决了给分啊 ,怎么都是这样啊