如果我尝试取消引用一个指针,我只是测试输出是什么,指针指向超出动态创建的内存范围使用calloc()
并期待内存错误或一些垃圾值。它给出0作为输出,这是calloc()
的基本特征,它用' 0'初始化分配的内存,或者它只是由于未定义的行为?
#include <stdio.h>
#include <stdlib.h>
int main()
{
int *p = NULL;
p = (int *)calloc(10, 8);
if(p != NULL)
{
printf("\n successfully allocated memory ");
}
else
EXIT_FAILURE;
printf("\n Thirty first element of memory is %d \n",p[30]);
}
结果:
successfully allocated memory
Thirty first element of memory is 0
答案 0 :(得分:1)
从语言的角度来看,访问越界内存是未定义的行为,这意味着任何事情都可能发生。
对于该特定行为的一种可能解释是,大多数操作系统在将任何内存提供给您的进程之前将其清零,与您在内部使用的功能无关(这是一种安全措施,所以你不能读取其他进程使用的数据。
要获取垃圾数据,通常必须在程序内部使用和释放相同的内存(在这种情况下,它会保留旧值)。或者,当然,如果您的索引距离太远以至于您正在索引到相邻的数据结构中。
你的程序没有崩溃的原因是malloc(和类似的函数)通常从os请求更多的内存,而不是你需要的内存,并在下次调用malloc时使用剩余内存。因此,从操作系统的角度来看,您正在访问有效的内存,并且没有理由终止您的程序。
答案 1 :(得分:1)
您仅在p + 30 * sizeof(int)
分配p + 120
时尝试访问8 * 10 = 80 bytes
,因此您可以访问的最大地址为p[19]
答案 2 :(得分:0)
访问超出范围内存的是Undefined Behaviour。因此,您获得的价值可以是0
或1
或Batman
关键是,你不能对未定义的事情提出任何解释或理由。在这种情况下,任何事情都可能发生。
此外,如果您尝试访问不允许您的程序访问的内存位置,您将获得seg fault
。当您访问越界内存时,情况可能并非如此。它可以很好地位于程序的用户存储区域内。
答案 3 :(得分:0)
我认为Windows在释放分配之前会将一个已释放的页面归零。享受下面的代码吧。
#include<stdio.h>
#include<stdlib.h>
#include <windows.h>
#include <signal.h>
int g = 0;
unsigned long long* p=NULL;
void signal_handler(int ssc)
{
printf("Error %d \n", ssc);
printf("segfault after %llu bytes",g*8);
printf("should i go backwards? press enter");
getch();
g=0;
do
{
printf("Virtual Adress:%llu is %llu\n",p+g,*(p+g) );
Sleep(1);
g--;
}
while(1);
}
int main ()
{
if(SIG_ERR == signal(SIGSEGV, signal_handler) ) {printf("error seting signal handler %d\n",SIGSEGV);}
p = (unsigned long long*)calloc(10,8);
if( p!= NULL)
{
printf("successfully allocated memory\n");
}
else
{
EXIT_FAILURE;
}
do
{
printf("Virtual Adress:%llu is %llu\n",p+g,*(p+g) );
Sleep(2);
g++;
}
while(1);
return 0;
}