使用未分配的 space calloc

using non allocated space calloc

我只是想知道当我使用未分配的 space 时编译器不会抛出异常,这里是一个代码示例:

#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 数组上工作。

你有些可怕 undefined behavior (UB). Read Lattner's blog about What every C programmer should know about undefined behavior

注意 UB,非常 bad things could happen, or nothing serious. And the observed behavior might not even be reproducible from one run to the next one (read about ASLR)。

为了解释您的系统上发生了什么,您需要深入研究实现细节,这比 C 或 C++ 代码要低得多。例如,您可以请求生成的汇编程序(例如,使用 gcc -Wall -O -fverbose-asm -S 编译您的代码并查看生成的 *.s 汇编程序文件)。或者您可以使用(在 Linux 上)类似 strace(1) to understand the involved system calls 的东西。 我想象在 Linux 上,对 calloc 的调用将向内核询问至少一页堆数据(即 calloc 将使用 mmap(2) or sbrk(2) ....) and since a page is 4Kbytes of data, the bytes you are accessing are in fact in your virtual address space.

顺便说一句,我邀请你安装和使用一些Linux distribution. Since it is mostly made of free software,你可以研究相关的源代码(包括你的代码、标准C库和Linux内核,甚至可能是编译器)。这可能需要您 许多 年,但原则上您将能够理解所有实施细节。

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

is there a way to know the size ? (of some heap-allocated data)

不,不是在可移植的 C 中。您应该自己管理大小(即有某种方式知道它)。一个有用的技巧可能是将它保持在数组数据附近,例如在 struct 中包含大小,并以 flexible array member 结尾。但是您仍然需要一些 约定 来获得大小。

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

访问越界数组是否会抛出 "exception" 取决于数组的位置/MMU 边界。总之,不靠谱!

要获得 "real" 异常,切换到 C++,删除 calloc,使用 vector::at

越界访问数据会产生未定义的行为,这意味着任何事情都可能发生。

如果您越界,由于访问未映射或受保护的内存页面,预计会出现分段错误。但是,这假设您的代码到机器代码的映射有些直接。

事实是,编译器只会给您一种错觉,即您的代码直接映射到机器代码。当你通过导致未定义的行为来打破规则时,幻觉可能会以一些非常奇怪的方式打破,这就是未定义的行为的全部意义所在。