Is "Malloc (sizeof (struct a *))" and "malloc (sizeof (struct a))" the same?

This question is a continuation of the Malloc call failure, but works elsewhere

I tried the following program, and I found it workable (i.e. not crashing - and this was mentioned in the above link as well). I may be lucky that it works, but I am looking for a reasonable explanation from SO experts about why this works?

Here are some basic concepts about memory allocation using malloc() wrt structures and pointers

  • malloc(sizeof(struct a) * n) allocates n number of elements of type struct a . And this memory can be saved and retrieved using pointer-to-type-"struct a" . Basically a struct a * .
  • malloc(sizeof(struct a *) * n) allocates n number of elements of type struct a * . Then each element can point to elements of type struct a . Basically malloc(sizeof(struct a *) * n) allocates array(n-elements)-of-pointers-to-type-"struct a" . And the allocated memory can be saved and accessible with pointer-to-(pointer-to-"struct a") . Basically a struct a ** .

So, when we create array(n-elements)-of-pointers-to-type-"struct a" , this

  • is it permissible to assign this struct a * instead of struct a ** ?
  • valid for accessing / unlinking a highlighted array(n-elements)-of-pointers-to-type-"struct a" using pointer-to-"struct a" ?

 data * array = NULL; if ((array = (data *)malloc(sizeof(data *) * n)) == NULL) { printf("unable to allocate memory \n"); return -1; } 

The following is a snippet of code:

 #include <stdio.h> #include <stdlib.h> int main(void) { typedef struct { int value1; int value2; }data; int n = 1000; int i; int val=0; data * array = NULL; if ((array = (data *)malloc(sizeof(data *) * n)) == NULL) { printf("unable to allocate memory \n"); return -1; } printf("allocation successful\n"); for (i=0 ; i<n ; i++) { array[i].value1 = val++; array[i].value2 = val++; } for (i=0 ; i<n ; i++) { printf("%3d %3d %3d\n", i, array[i].value1, array[i].value2); } free(array); printf("freeing successful\n"); return 0; } 

EDIT: Well, if I do the following in error

 data * array = NULL; if ((array = (data *)malloc(sizeof(data *) * n)) == NULL) { 

Is there a capture method (during compilation using any GCC flags) of this kind of unintended programming that can work from time to time and can be blown away at any time! I compiled this with -Wall and did not find any warnings!

+4
source share
4 answers

There seems to be a fundamental misunderstanding.

malloc (sizeof (struct a) * n) allocates n elements of type struct a.

No, this is what is commonly used, as after such a call. malloc(size) allocates a memory area of size bytes. What you do with this region is entirely up to you. The only thing that matters is that you do not cross the boundaries of the allocated memory. Assuming 4 bytes of float and int and 8 bytes of double , after successful malloc(100*sizeof(float)); you can use the first 120 of 400 bytes as an array of 15 double s, and the next 120 as an array of 30 float s, then put an array of 20 char right behind it and fill in the remaining 140 bytes of 35 int if you want. This is a completely harmless defined behavior.

malloc returns a void* , which can be implicitly passed to a pointer of any type, therefore

 some_type **array = malloc(100 * sizeof(data *)); // intentionally unrelated types 

excellent, it may just not be the amount of memory you wanted. In this case, this is very likely because the pointers are the same size no matter what they point to.

Most likely you will get the wrong amount of memory

 data *array = malloc(n * sizeof(data*)); 

how did you do it. If you use the allocated memory as an array of n elements of type data , there are three possibilities

  • sizeof(data) < sizeof(data*) . Then your only problem is that you are losing space.
  • sizeof(data) == sizeof(data*) . Everything is fine, with no spaces, as if you had no typo.
  • sizeof(data) > sizeof(data*) . You will then gain access to memory, which you should not access when you touch the later elements of the array, which is undefined. Depending on different things that could work sequentially as if your code was correct, immediately crash with segfault or something in between (technically, it could behave in such a way that it could not be meaningfully placed between the two, but that would be unusual).

If you intentionally do this, knowing point 1. or 2., it applies. Bad practice, but not a mistake. If you do this unintentionally, it is a mistake, no matter which item is applied, harmless but hard to find, and 1. or 2. applied, harmful, but usually easier to detect in case 3.

In your examples. data was 4 respectively. 8 bytes (possibly) that on a 64-bit system put them in 1, respectively. 2. with a high probability, on a 32-bit system by 2, respectively. 3.

The recommended way to avoid such errors is to

 type *pointer = malloc(num_elems * sizeof(*pointer)); 
+4
source

No.

sizeof(struct a*) - pointer size.
sizeof(struct a) - the size of the entire structure.

+7
source

This array = (data *)malloc(sizeof(data *) * n) allocates sizeof(data*) ( pointer ) for struct data , if you want to do this you need array be data** array .

In your case, you want your pointer to point to a sizeof(data) structure in memory, and not to another pointer. For this, data** (pointer to pointer) is required.

+1
source

Is it permissible to assign struct a * instead of struct a **?

Well, technically speaking, it’s fair to assign such a thing, but it’s wrong (UB) to dereference such a pointer. You do not want to do this.

valid for accessing / deleting references to the selected array (n-elements) -of-pointers-to-type- "struct a" using the pointer-to-struct a "?

No, undefined.

+1
source

Source: https://habr.com/ru/post/1389697/


All Articles