我对C上的malloc()和calloc()非常困惑

blu*_*llu 27 c arrays malloc calloc

我总是用Java编程,这可能就是为什么我对此很困惑:

在Java中我声明了一个指针:

int[] array
Run Code Online (Sandbox Code Playgroud)

并初始化它或为其分配一些内存:

int[] array = {0,1,0}
int[] array = new int[3]
Run Code Online (Sandbox Code Playgroud)

现在,在C中,这一切都让人感到困惑.起初我以为它就像宣布它一样容易:

int array[]
Run Code Online (Sandbox Code Playgroud)

并初始化它或为其分配一些内存:

int array[] = {0,1,0}
int array[] = malloc(3*sizeof(int))
int array[] = calloc(3,sizeof(int))
Run Code Online (Sandbox Code Playgroud)

除非我错了,以上所有内容都等同于Java-C,对吗?

然后,今天我遇到了一个代码,其中我发现了以下内容:

pthread_t tid[MAX_OPS];
Run Code Online (Sandbox Code Playgroud)

以及下面的一些行,没有任何初始化......

pthread_create(&tid[0],NULL,mou_usuari,(void *) 0);
Run Code Online (Sandbox Code Playgroud)

令人惊讶的是(至少对我而言)代码有效!至少在Java中,会返回一个很好的"NullPointerException"!

所以,按顺序:

  1. 我是否正确使用所有Java-C"翻译"?

  2. 为什么该代码有效?

  3. 使用malloc(n*sizeof(int))和之间有什么区别calloc(n,sizeof(int))吗?

提前致谢

eq-*_*eq- 39

您无法将内存分配给阵列.数组在整个生命周期内都有固定的大小.数组永远不能为空.数组不是指针.

malloc将地址返回给为程序保留的内存块.你不能将(作为内存块)"分配"给一个数组,但你可以将这个内存块的地址存储在一个指针中:幸运的是,数组预订是通过指针定义的 - 所以你可以"使用像数组一样的指针" ,例如

int *ptr = malloc(5 * sizeof *ptr);
ptr[2] = 5; // access the third element "of ptr"
free(ptr); // always free at the end
Run Code Online (Sandbox Code Playgroud)

声明没有大小(即array[])的数组时,它只是意味着数组的大小是从初始化列表中确定的.那是

int array[] = {1, 2, 3, 4, 5}; // is equal to
int array[5] = {1, 2, 3, 4, 5};
Run Code Online (Sandbox Code Playgroud)

尝试声明没有大小而没有初始化程序的数组是一个错误.


该代码pthread_t tid[MAX_OPS];声明了一个名为tidtype pthread_t和size 的数组MAX_OPS.

如果数组具有自动存储(即声明在函数内部而不是静态,而不是全局),则每个数组元素都具有不确定的值(并且它会导致尝试读取此类值的未定义行为).幸运的是,函数调用所做的就是它将数组的第一个元素的地址作为第一个参数,并且可能在函数内部初始化它(元素).


的差callocmalloc是存储块calloc返回被初始化为零.那是;

int *ptr = calloc(5, sizeof *ptr);
// is somewhat equal to
int *ptr = malloc(5 * sizeof *ptr);
memset(ptr, 0, 5 * sizeof *ptr);
Run Code Online (Sandbox Code Playgroud)

和...之间的不同

int *ptr = malloc(5 * sizeof *ptr);
// and
int array[5];
Run Code Online (Sandbox Code Playgroud)

array自动存储,(存储在堆栈中),并在超出范围后"释放".ptr但是,(存储在堆上),是动态分配的,必须free由程序员进行.

  • 只是为了完成,并且为了完整性,Array是一个指针.事实上,C中的任何数组名称都恰好是指向数组中第一个对象的第一个字节的基础的指针,仅此而已.对于来自Java,.Net等的人来说,知道C保持对象/变量的类型与分配用于保存它们的存储完全分离是有帮助的.这就是为什么你可以将指针强制转换为int,创建UNION等等.非常非常灵活,但对于noobies来说很危险.分配int数组时,它只是存储在一个位置.你可以在存储中放入任何你喜欢的东西. (7认同)

lor*_*ova 5

你错过了三个非常基本的和紧缩(和误导!)C 主题:

  • 数组和指针的区别
  • 静态分配和动态分配的区别
  • 与在堆栈或堆上声明变量的区别

如果你写int array[] = malloc(3*sizeof(int));你会得到一个编译错误(类似于“标识符”:数组初始化需要花括号)。

这意味着声明一个数组只允许静态初始化:

  • int array[] = {1,2,3}; 在堆栈上保留 3 个连续的整数;
  • int array[3] = {1,2,3}; 与上一个相同;
  • int array[3]; 仍然在堆栈上保留 3 个连续整数,但不初始化它们(内容将是随机垃圾)
  • int array[4] = {1,2,3}; 当初始化列表未初始化所有元素时,其余元素设置为 0(C99 §6.7.8/19):在这种情况下,您将得到 1,2,3,0

请注意,在所有这些情况下,您并没有分配新内存,您只是在使用已经提交给堆栈的内存。只有当堆栈已满时,您才会遇到问题(猜猜看,这将是堆栈溢出)。因此,声明int array[];将是错误且毫无意义的。

要使用,malloc您必须声明一个指针:int* array.

当你写的时候,int* array = malloc(3*sizeof(int));你实际上在做三个操作:

  1. int* array 告诉编译器在堆栈上保留一个指针(一个包含内存地址的整数变量)
  2. malloc(3*sizeof(int)) 在堆上分配 3 个连续整数并返回第一个的地址
  3. = 将返回值(您分配的第一个整数的地址)的副本分配给您的指针变量

所以,回到你的问题:

pthread_t tid[MAX_OPS];
Run Code Online (Sandbox Code Playgroud)

是堆栈上的一个数组,因此不需要分配它(如果MAX_OPS是 16,那么堆栈上将保留适合 16 个 pthread_t 所需的连续字节数)。该内存的内容将是垃圾(堆栈变量未初始化为零),但pthread_create在其第一个参数(指向pthread_t变量的指针)中返回一个值并忽略任何先前的内容,因此代码很好。

  • 对于`int array[4]`,它们都被初始化了。当初始化列表未初始化所有元素时,其余元素设置为 0/NULL (C99 §6.7.8/19)。 (5认同)