使用未分配的空间calloc

时间:2016-10-22 17:22:30

标签: c calloc

我只是想知道编译器在使用非分配空间时不会抛出异常,例如这里是代码:

#include <stdio.h>
#include <stdlib.h>

int main()
{
   int i, n;
   int *a;

   printf("Number of elements to be entered:");
   scanf("%d",&n);

   a = (int*)calloc(n, sizeof(int));
   printf("Enter %d numbers:\n",n);
   for( i=0 ; i < n ; i++ ) 
   {
      scanf("%d",&a[i]);
   }

   printf("The numbers entered are: ");
   for( i=0 ; i < n ; i++ ) 
   {
      printf("%d ",a[i]);
   }
   free( a );

   return(0);
}

例如,如果n = 3,我静静地说:

a[10]=3;

它会起作用并且不会抛出异常而我可以打印它,那么使用一个元素超出界限有什么影响?有没有办法知道大小?因为(sizeof)不会对calloc数组起作用。

3 个答案:

答案 0 :(得分:3)

超出范围访问数据会给您带来未定义的行为,这意味着任何事情都可能发生。

如果远离界限,由于访问未映射或受保护的内存页面,可能会出现分段错误。但是,这假设您的代码与机器代码的映射有点直接。

事实是,编译器只会让您觉得您的代码直接映射到机器代码。当你通过造成未定义的行为来打破规则的那一刻,幻觉可能会以一些非常奇怪的方式打破,而这就是未定义的行为的全部内容。

答案 1 :(得分:2)

你有一些可怕的undefined behavior(UB)。阅读Lattner关于What every C programmer should know about undefined behavior的博客。

请注意,对于UB,可能会发生非常bad的事情,或者没有任何严重的事情。并且观察到的行为甚至可能无法从一次运行再到下一次运行(阅读ASLR)。

要解释系统上发生的情况,您需要深入了解实施细节,远低于C或C ++代码。例如,您可以请求生成的汇编程序(例如,使用gcc -Wall -O -fverbose-asm -S编译代码并查看生成的*.s汇编程序文件)。或者您可以使用(在Linux上)类似strace(1)的内容来理解所涉及的system calls。 我想象在Linux上,对calloc的调用会要求内核至少有一页堆数据(即calloc会使用mmap(2)sbrk(2)。 ..)由于页面是4K字节的数据,因此您访问的字节实际上位于virtual address space

顺便说一句,我邀请您安装并使用一些Linux distribution。由于它主要由free software组成,因此您可以研究所涉及的源代码(包括您的代码,标准C库和Linux内核,甚至是编译器)。这可能需要许多年,但您原则上可以理解所有实现细节。

另请阅读Joel的law of leaky abstractions ...

  

有没有办法知道尺寸? (一些堆分配的数据)

不,不是在便携式C.你应该自己管理大小(即有一些方法来了解它)。一个有用的技巧可能是将其保持在阵列数据附近,例如:在struct中包含大小,以flexible array member结尾。但是你仍然需要一些约定来获得大小。

答案 2 :(得分:1)

抱歉,您无法知道已分配数组的大小(请参阅:determine size of dynamically allocated memory in c

访问越界数组是否会抛出“异常”取决于数组/ MMU边界的位置。无论如何,这是不可靠的!

要获得“真实”例外,请切换到C ++,放弃calloc,使用vector::at