繁体   English   中英

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

[英]I'm very confused about malloc() and calloc() on C

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

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

int[] array

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

int[] array = {0,1,0}
int[] array = new int[3]

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

int array[]

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

int array[] = {0,1,0}
int array[] = malloc(3*sizeof(int))
int array[] = calloc(3,sizeof(int))

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

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

pthread_t tid[MAX_OPS];

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

pthread_create(&tid[0],NULL,mou_usuari,(void *) 0);

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

所以,按顺序:

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

  2. 为什么该代码有效?

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

提前致谢

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

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

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

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

int array[] = {1, 2, 3, 4, 5}; // is equal to
int array[5] = {1, 2, 3, 4, 5};

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


代码pthread_t tid[MAX_OPS]; 声明一个名为tid的数组,类型为pthread_t ,大小为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);

和...之间的不同

int *ptr = malloc(5 * sizeof *ptr);
// and
int array[5];

是该array具有自动存储(存储在堆栈中),并在超出范围后“释放”。 然而, ptr (存储在堆上)是动态分配的,并且必须由程序员free d。

你缺少三个非常基本和紧缩(和误导!)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];

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

C提供静态内存分配以及动态 - 您可以从堆栈或可执行内存(由编译器管理)分配数组。 这与Java中的方式相同,您可以在堆栈上分配int或在堆上分配Integer。 C中的数组就像任何其他堆栈变量一样 - 它们超出范围等。在C99中,它们也可以具有可变大小,尽管它们无法调整大小。

{}和malloc / calloc之间的主要区别在于{}数组是静态分配的(不需要释放)并自动为您初始化,而malloc / calloc数组必须显式释放,您必须显式初始化它们。 但是,当然,malloc / calloc数组不会超出范围,你可以(有时)realloc()它们。

2 - 此数组声明是静态的:

pthread_t tid[MAX_OPS];

我们不需要分配内存块,而不是动态分配:

pthread_t *tid = (pthread_t *)malloc( MAX_OPS * sizeof(pthread_t) );

别忘了释放记忆:

free(tid);

3 - malloc和calloc之间的区别是calloc为数组分配一块内存,并将其所有位初始化为0。

我发现当你用C语言编程(而不是C ++)来明确指示*数组时要记住有一个可以移动的指针。 所以我想首先将你的例子改为:

int array[] = {0,1,2};
int *array = malloc(3*sizeof(int));
int *array = calloc(3,sizeof(int));

第一个清楚地表明有一个叫做数组的东西指向一个包含0,1和2的内存块。数组不能在其他地方移动。

你的下一个代码:pthread_t tid [MAX_OPS];

实际上是否会导致分配sizeof(pthread_t)* MAX_OPS的数组。 但它没有分配一个名为* tid的指针。 有一个数组基址的地址,但你不能把它移到别处。

ptherad_t类型实际上是指针的封面。 所以上面的tid实际上是一个指针数组。 它们都是静态分配的,但它们没有初始化。

pthread_create获取数组开头的位置( &tid[0] ),它是一个指针,并分配一块内存来保存pthread数据结构。 指针设置为指向新数据结构并分配数据结构。

你的最后一个问题--- malloc(n*sizeof(int))calloc(n,sizeof(int))之间的区别在于后者将每个字节初始化为0 ,而第一个不是。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM