【问题标题】:How many members calloc allocates in C [duplicate]在C中分配了多少个成员calloc [重复]
【发布时间】:2020-01-15 18:21:07
【问题描述】:

我期望下面的 sn-p 使用 calloc 为五个成员分配内存。

$ cat calloc.c
// C program to demonstrate the use of calloc() 
// and malloc() 
#include <stdio.h> 
#include <stdlib.h> 

int main() 
{ 
  int *arr; 
  arr = (int *)calloc(5, sizeof(int)); 
  printf("%x\n", *arr);
  printf("%x\n", *(arr+1));
  printf("%x\n", *(arr+2));
  printf("%x\n", *(arr+3));
  printf("%x\n", *(arr+4));
  printf("%x\n", *(arr+5));
  printf("%x\n", *(arr+6));
  // Deallocates memory previously allocated by calloc() function 
  free(arr); 

  return(0); 
} 

但是好像分配的不止五个;它分配了六个成员,为什么?

./a.out 
0
0
0
0
0
0
411

【问题讨论】:

标签: c linux


【解决方案1】:

分配内存不像购买棒棒糖。分配内存更像是买地。

如果你买了五个棒棒糖,然后你想吃第六个,这显然是行不通的——甚至谈论“尝试吃第六个”都是非常荒谬的。

但是,如果您购买了一块 10 英尺乘 50 英尺的土地,并开始建造 10x10 英尺的建筑物,并且在建造了其中五座(完全占据了您的土地)之后,您又建造了第六座,侵占了您邻居的土地,您的邻居可能不会立即注意到,因此您可能会侥幸逃脱。 (反正一会儿,总归是有麻烦的。)

同样,如果您分配一个大小为 5 的数组,然后尝试访问不存在的第 6 个元素,则没有自然法则可以阻止它,就像您尝试吃不存在的第 6 个棒棒糖时那样。在 C 中,您通常不会收到有关越界数组访问的错误消息,因此您可能会得到 似乎 可以工作的代码,即使它正在做一些完全不可接受的事情,例如侵犯邻居的土地。

【讨论】:

  • 我真的很喜欢你的土地类比。这甚至可以扩展为说,当您越界建造时,可能是您正在破坏碰巧站在那里的邻居车库,直到他尝试使用他的汽车才发现(沉默数据损坏),或者您自己的工作出现严重错误,因为您的土地位于岸边,而您尝试建造的“土地”实际上是开阔的海洋(不存在内存,段错误)。我绝对必须记住这个类比!
【解决方案2】:

首先,让我们明确一点:就所有目的而言,*(a+x)a[x] 相同。

C 具有空闲内存访问权限。如果您执行 arr[1000],您仍然会打印一个值,否则程序将因分段错误而崩溃。这是未定义行为的经典案例。编译器无法知道您编写的代码是否错误,因此无法抛出错误。相反,C 标准说这是未定义的行为。这意味着您正在访问不应该访问的内存。

作为程序员,您有责任检查您是否超出了数组和没有编译器的范围。另外,calloc 用 0 初始化所有元素。为什么你认为你得到了 411?再次尝试运行它,您可能会得到不同的值。您在a[5] 访问的内存未分配给数组。相反,您将超出数组的范围。该内存很可能被分配给其他东西。如果它被分配给另一个程序,则在运行该程序时会出现分段错误。

【讨论】:

  • 对我来说,整个混淆点是当 a[5] 给我 0 时,如果它给我一些垃圾(如 a[6] 的情况),我会很满意,这仍然是一样的每次我运行它。
  • 重启电脑再试一次,这次可能内存地址变了。 a[5]恰好是0,纯属巧合,不是calloc这样设置的
  • @Milan 这是未定义行为更令人困惑的方面之一。我们说它会做一些随机的事情,我们说它可以做任何事情,但通常,就像这里一样,它会做一些完全可预测且看起来几乎合理的事情。这会让你寻找原因,它可能会让你怀疑你是否被错误地告知原始代码是非法的或不工作。但是,有时,对于看似可预测的行为,除了“未定义的行为意味着 任何事情 都可能发生,包括做一些看起来合理的事情。”之外,没有合适的解释。
  • @Milan 未定义的行为意味着它不能保证工作。但这并不意味着保证不会起作用。
  • @Steve Summit 如果您想遵守任何类型的标准,您的代码中不得有未定义的行为。这主要是因为其他人可能会尝试使用不同的编译器甚至同一编译器的不同版本来编译您的代码并得到不同的结果。虽然有时您可以侥幸逃脱,但最好不要这样做,除非您专门寻找那种乐趣。
【解决方案3】:

它分配的内存不超过5。它分配了5 成员并用0 初始化它们。当您访问分配的内存之外时,它可能会被写入任何内容,并且不一定是非零值。

【讨论】:

    【解决方案4】:

    每次调用 malloc、calloc 或 realloc 时,内存分配都是从堆区完成的。

    运行时/动态分配 -> 堆

    静态/编译时间->堆栈

    // C program to demonstrate the use of calloc() 
    // and malloc() 
    #include <stdio.h> 
    #include <stdlib.h> 
    
    int main() 
    { 
     int *arr; 
     arr = (int *)calloc(5, sizeof(int)); // dynamically allocate memory for 5 element each of size of integer variables and intializes all with 0.
      printf("%x\n", *arr);//array name is a constant pointer(points to base address of the array
     printf("%x\n", *(arr+1));
     printf("%x\n", *(arr+2));
     printf("%x\n", *(arr+3));
     printf("%x\n", *(arr+4));
     printf("%x\n", *(arr+5));
     printf("%x\n", *(arr+6));// you are accessing memory which is not the part of your pointer variable. There are chances that this is the part of the some other program or variable.
     // Deallocates memory previously allocated by calloc() function 
     free(arr); 
     arr=NULL;//always assign pointer to null to avoid any dangling pointer situation
    
     return(0); 
    } 
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-08-21
      • 2012-10-08
      • 2012-09-05
      • 1970-01-01
      • 1970-01-01
      • 2012-09-13
      • 1970-01-01
      相关资源
      最近更新 更多