简体   繁体   English

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

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

I've always programmed in Java, which is probably why I'm so confused about this: 我总是用Java编程,这可能就是为什么我对此很困惑:

In Java I declare a pointer: 在Java中我声明了一个指针:

int[] array

and initialize it or assign it some memory: 并初始化它或为其分配一些内存:

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

Now, in C, it's all so confusing. 现在,在C中,这一切都让人感到困惑。 At first I thought it was as easy as declaring it: 起初我以为它就像宣布它一样容易:

int array[]

and initializing it or assigning it some memory: 并初始化它或为其分配一些内存:

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

Unless I'm wrong, all of the above is equivalent Java-C, right? 除非我错了,以上所有内容都等同于Java-C,对吗?

Then, today I met a code in which I found the following: 然后,今天我遇到了一个代码,其中我发现了以下内容:

pthread_t tid[MAX_OPS];

and some lines below, without any kind of initialization... 以及下面的一些行,没有任何初始化......

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

Surprisingly (at least to me), the code works! 令人惊讶的是(至少对我而言)代码有效! At least in Java, that would return a nice "NullPointerException"! 至少在Java中,会返回一个很好的“NullPointerException”!

So, in order: 所以,按顺序:

  1. Am I correct with all of the Java-C "translations"? 我是否正确使用所有Java-C“翻译”?

  2. Why does that code work? 为什么该代码有效?

  3. Is there any difference between using malloc(n*sizeof(int)) and calloc(n,sizeof(int)) ? 使用malloc(n*sizeof(int))calloc(n,sizeof(int))之间有什么区别吗?

Thanks in advance 提前致谢

You can't assign memory to an array. 您无法将内存分配给阵列。 An array has a fixed size, for the whole of its lifespan. 数组在整个生命周期内都有固定的大小。 An array can never be null. 数组永远不能为空。 An array is not a pointer. 数组不是指针。

malloc returns the address to a memory block that is reserved for the program. malloc将地址返回给为程序保留的内存块。 You can't "assign" that (being the memory block) to an array, but you can store the address of this memory block in a pointer: luckily, array subscription is defined through pointers - so you can "use pointers like arrays", eg 你不能将(作为内存块)“分配”给一个数组,但你可以将这个内存块的地址存储在一个指针中:幸运的是,数组预订是通过指针定义的 - 所以你可以“使用像数组一样的指针” ,例如

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

When you declare an array without a size (ie array[] ), it simply means the size of the array is determined from the initializer list. 当声明一个没有大小的数组(即array[] )时,它只是意味着数组的大小是从初始化列表中确定的。 That is 那是

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

Trying to declare an array without a size and without an initializer is an error. 尝试声明没有大小而没有初始化程序的数组是一个错误。


The code pthread_t tid[MAX_OPS]; 代码pthread_t tid[MAX_OPS]; declares an array named tid of type pthread_t and of size MAX_OPS . 声明一个名为tid的数组,类型为pthread_t ,大小为MAX_OPS

If the array has automatic storage (ie declaration is inside a function and not static, not global), then each of the arrays elements has indeterminate value (and it would cause undefined behavior trying to read such value). 如果数组具有自动存储(即声明在函数内部而不是静态,而不是全局),则每个数组元素都具有不确定的值(并且它会导致尝试读取此类值的未定义行为)。 Luckily, all that the function call does is that it takes the address of the first element of the array as the first parameter, and probably initializes it (the element) inside the function. 幸运的是,函数调用所做的就是它将数组的第一个元素的地址作为第一个参数,并且可能在函数内初始化它(元素)。


The difference of calloc and malloc is that the memory block that calloc returns is initialized to zero. callocmalloc的区别在于calloc返回的内存块被初始化为零。 That is; 那是;

int *ptr = calloc(5, sizeof *ptr);
// is somewhat equal to
int *ptr = malloc(5 * sizeof *ptr);
memset(ptr, 0, 5 * sizeof *ptr);

The difference between 和...之间的不同

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

is that array has automatic storage, (is stored on stack), and is "released" after it goes out of scope. 是该array具有自动存储(存储在堆栈中),并在超出范围后“释放”。 ptr , however, (is stored on heap), is dynamically allocated and must be free d by the programmer. 然而, ptr (存储在堆上)是动态分配的,并且必须由程序员free d。

You are missing three very basic and tighten (and misleading!) C topics: 你缺少三个非常基本和紧缩(和误导!)C主题:

  • the difference between array and pointers 数组和指针之间的区别
  • the difference between static and dynamic allocation 静态和动态分配之间的区别
  • the difference from declaring variables on the stack or on the heap 与在堆栈或堆上声明变量的区别

If you write int array[] = malloc(3*sizeof(int)); 如果你写int array[] = malloc(3*sizeof(int)); you would get a compilation error (something like 'identifier' : array initialization needs curly braces ). 你会得到一个编译错误(类似'标识符':数组初始化需要花括号 )。

This means that declaring an array allows only static initialization: 这意味着声明一个数组只允许静态初始化:

  • int array[] = {1,2,3}; that reserves 3 contiguous integers on the stack; 在堆栈上保留3个连续的整数;
  • int array[3] = {1,2,3}; which is the same as the previous one; 与前一个相同;
  • int array[3]; that still reserves 3 contiguous integers on the stack, but does not initialize them (the content will be random garbage) 仍然在堆栈上保留3个连续的整数,但不初始化它们(内容将是随机垃圾)
  • int array[4] = {1,2,3}; when the initializer list doesn't initialize all the elements, the rest are set to 0 (C99 §6.7.8/19): in this case you'll get 1,2,3,0 当初始化列表没有初始化所有元素时,其余的被设置为0(C99§6.7.8/ 19):在这种情况下你将获得1,2,3,0

Note that in all these cases you are not allocating new memory, you are just using the memory already committed to the stack. 请注意,在所有这些情况下,您没有分配新内存,您只是使用已经提交到堆栈的内存。 You would run in a problem only if the stack is full (guess it, it would be a stack overflow ). 只有当堆栈已满时才会遇到问题(猜测它会是堆栈溢出 )。 For this reason declaring int array[]; 因此声明int array[]; would be wrong and meaningless. 会是错误的,毫无意义的。

To use malloc you have to declare a pointer: int* array . 要使用malloc您必须声明一个指针: int* array

When you write int* array = malloc(3*sizeof(int)); 当你写int* array = malloc(3*sizeof(int)); you are actually doing three operations: 你实际上做了三个操作:

  1. int* array tells the compiler to reserve a pointer on the stack (an integer variable that contains a memory address) int* array告诉编译器在栈上保留一个指针(一个包含内存地址的整数变量)
  2. malloc(3*sizeof(int)) allocates on the heap 3 contiguous integers and returns the address of the first one malloc(3*sizeof(int))在堆上分配3个连续的整数并返回第一个的地址
  3. = assigns copies that return value (the address of the first integer you have allocated) to your pointer variable =将返回值(已分配的第一个整数的地址)的副本分配给指针变量

So, to come back to your question: 那么,回到你的问题:

pthread_t tid[MAX_OPS];

is an array on the stack, so it doesn't need to be allocated (if MAX_OPS is, say, 16 then on the stack will be reserved the number of contiguous bytes needed to fit 16 pthread_t). 堆栈中是一个数组,因此不需要分配(如果MAX_OPS是16,那么堆栈上将保留适合16 pthread_t所需的连续字节数)。 The content of this memory will be garbage (stack variables are not initialized to zero), but pthread_create returns a value in its first parameter (a pointer to a pthread_t variable) and disregards any previous content, so the code is just fine. 这个内存的内容将是垃圾(堆栈变量未初始化为零),但pthread_create在其第一个参数(指向pthread_t变量的指针)中返回一个值,并忽略任何先前的内容,因此代码就可以了。

C offers static memory allocation as well as dynamic- you can allocate arrays off the stack or in executable memory (managed by the compiler). C提供静态内存分配以及动态 - 您可以从堆栈或可执行内存(由编译器管理)分配数组。 This is just the same as how in Java, you can allocate an int on the stack or an Integer on the heap. 这与Java中的方式相同,您可以在堆栈上分配int或在堆上分配Integer。 Arrays in C are just like any other stack variable- they go out of scope, etc. In C99 they can also have a variable size, although they cannot be resized. C中的数组就像任何其他堆栈变量一样 - 它们超出范围等。在C99中,它们也可以具有可变大小,尽管它们无法调整大小。

The main difference between {} and malloc/calloc is that {} arrays are statically allocated (don't need freeing) and automatically initialized for you, whereas malloc/calloc arrays must be freed explicitly and you have to initialize them explicitly. {}和malloc / calloc之间的主要区别在于{}数组是静态分配的(不需要释放)并自动为您初始化,而malloc / calloc数组必须显式释放,您必须显式初始化它们。 But of course, malloc/calloc arrays don't go out of scope and you can (sometimes) realloc() them. 但是,当然,malloc / calloc数组不会超出范围,你可以(有时)realloc()它们。

2 - This array declaration is static : 2 - 此数组声明是静态的:

pthread_t tid[MAX_OPS];

We don't need to allocate memory block, instead of dynamic allocation : 我们不需要分配内存块,而不是动态分配:

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

Don't forget to free the memory : 别忘了释放记忆:

free(tid);

3 - The difference between malloc and calloc is calloc allocate a block of memory for an array and initializes all its bits at 0. 3 - malloc和calloc之间的区别是calloc为数组分配一块内存,并将其所有位初始化为0。

I find it helpful when you are programming in C (as opposed to C++) to indicate *array explicitly, to remember that there is a pointer that can be moved around. 我发现当你用C语言编程(而不是C ++)来明确指示*数组时要记住有一个可以移动的指针。 So I would like to start by rephrasing your example as: 所以我想首先将你的例子改为:

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

The first makes it clear that there is something called array which is pointing to a block of memory that contains a 0, 1 and 2. array can't be moved elesewhere. 第一个清楚地表明有一个叫做数组的东西指向一个包含0,1和2的内存块。数组不能在其他地方移动。

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

Does in fact cause an array with sizeof(pthread_t) * MAX_OPS to be allocated. 实际上是否会导致分配sizeof(pthread_t)* MAX_OPS的数组。 But it does not allocate a pointer called *tid. 但它没有分配一个名为* tid的指针。 There is an address of the base of the array, but you can't move it elsewhere. 有一个数组基址的地址,但你不能把它移到别处。

The ptherad_t type is actually a cover for a pointer. ptherad_t类型实际上是指针的封面。 So tid above is actually an array of pointers. 所以上面的tid实际上是一个指针数组。 And they are all statically allocated but they are not initialized. 它们都是静态分配的,但它们没有初始化。

The pthread_create takes the location at the beginning of the array ( &tid[0] ), which is a pointer, and allocates a block of memory to hold the pthread data structure. pthread_create获取数组开头的位置( &tid[0] ),它是一个指针,并分配一块内存来保存pthread数据结构。 The pointer is set to point to the new data structure and the data structure is allocated. 指针设置为指向新数据结构并分配数据结构。

Your last question --- the difference between malloc(n*sizeof(int)) and calloc(n,sizeof(int)) is that the later initializes each byte to 0 , while the first does not. 你的最后一个问题--- malloc(n*sizeof(int))calloc(n,sizeof(int))之间的区别在于后者将每个字节初始化为0 ,而第一个不是。

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

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