Malloc'ing arrays and then free'ing them?

I am currently messing around with c. I have a few hiccups in using pointers and syntax.

Below I try to create an array of pointers for whole arrays, and then direct each pointer to an array created through malloc ().

After creating the arrays, I then loop through each cell, assigning a value.

Now it all works, but when it comes to using free () to recover memory, the program crashes.

I noticed that if I malloc () the memory of the array, and then immediately calls free () on them, the program runs without problems. When, however, I malloc () assign the values ​​and THEN free (), a crash occurs. (Segmentation error).

Below is the code that works, malloc (), and then immediately free () ing

int (*ptrArr[5])[5]; for(int i=0; i<5; i++) ptrArr[i] = malloc(sizeof(int) * 5); for(int i=0; i<5; i++) printf("ptrArr[%d][%x]->[%x]\n", i, &ptrArr[i], &*ptrArr[i]); printf("\n"); for(int i=0; i<5; i++){ for(int j=0; j<5; j++){ printf("[%x](%2d) | ", &*ptrArr[i][j], *ptrArr[i][j]); } printf("\n"); } for(int i=4; i>=0; i--) free(ptrArr[i]); 

the above runs as I expected, but when I assign values ​​to the cells and then try and call later, segmentation fails:

 int (*ptrArr[5])[5]; for(int i=0; i<5; i++) ptrArr[i] = malloc(sizeof(int) * 5); for(int i=0; i<5; i++) printf("ptrArr[%d][%x]->[%x]\n", i, &ptrArr[i], &*ptrArr[i]); printf("\n"); for(int i=0; i<5; i++){ for(int j=0; j<5; j++){ printf("[%x](%2d) | ", &*ptrArr[i][j], *ptrArr[i][j]); } printf("\n"); } int loop = 5; for(int i=0; i<5; i++){ for(int j=0; j<5; j++){ *ptrArr[i][j] = (loop + (i*j)); ++loop; } } printf("\n"); for(int i=0; i<5; i++){ for(int j=0; j<5; j++){ printf("[%x](%2d) | ", &*ptrArr[i][j], *ptrArr[i][j]); } printf("\n"); } for(int i=4; i>=0; i--) { printf("Freeing ptrArr[%x]\n", i); free(ptrArr[i]); } 

I think I either misunderstand

 int (*ptrArr[5])[5]; 

which I intended was an array of 5 pointers, each of which pointed to an integer array, or im incorrectly assigning values ​​to the cells correctly, instead distorting the memory, due to which the free () function fails.

Any help would be appreciated, I hope the question is clear and concise.

Thanks.

+5
source share
4 answers

As I approach this problem, I need to print sizeof various suspects, for example

 int (*test[5])[5]; printf( "%zu ", sizeof(test) ); printf( "%zu ", sizeof(test[0]) ); printf( "%zu\n", sizeof(test[0][0]) ); 

Result 40 8 20 . (Note that on my machine, int is 4 bytes, and a pointer is 8 bytes.)
So this tells me that test is an array of 5 pointers. Logically, test[0] is the only pointer. But interestingly, test[0][0] is an array of 5 integers.

If I add the following line of code

 printf( "%zu\n", sizeof(test[0][0][0]) ); 

the output is 4, i.e. test[0][0][0] is a single int . From this we conclude that the declaration int (*test[5])[5] declares a three-dimensional array, which is not what you intended.


So try a simpler ad like this

 int (*test)[5]; printf( "%zu ", sizeof(test) ); printf( "%zu ", sizeof(test[0]) ); printf( "%zu\n", sizeof(test[0][0]) ); 

The output is 8 20 4 , which means that test is the only pointer, test[0] is an array of 5 integers, and test[0][0] is the only int . We conclude that int (*test)[5] declares a two-dimensional array.


The next question is how to allocate memory for an array. If we do it

 test = malloc( 5 * sizeof(int) ); 

then we have an array that has 1 row and 5 columns, basically a one-dimensional array.

To get a two-dimensional array with N rows, we need

 test = malloc( N * 5 * sizeof(int) ); 

Then we can fill, print and free an array like this

 int N = 5; for ( int row = 0; row < N; row++ ) for ( int col = 0; col < 5; col++ ) test[row][col] = (row+5)*10 + col; for ( int row = 0; row < N; row++ ) { for ( int col = 0; col < 5; col++ ) printf( "%2d ", test[row][col] ); printf( "\n" ); } free( test ); 
+2
source

Well, that was a headache for decoding, but like a good critical crossword, there is a solution. I cleaned things up a bit. The main problem was dereferencing.

See: The order of operations for dereferencing and parentheses-ref in C

I noted a line in some working code below. I added brackets around (* ptrArr [i]) to get an array that can then be properly indexed as (* ptrArr [i]) [j].

I also suggested an alternative way to declare an array first. This is easier to check!

 #include <stdlib.h> #include <stdio.h> #define SIZE 5 int main() { // This makes things clearer :- typedef int ArrayType[SIZE]; typedef ArrayType * ArrayPtr; ArrayPtr ptrArr[SIZE]; for (int i = 0; i < SIZE; i++) ptrArr[i] = malloc (sizeof (int) * SIZE); int loop = SIZE; for (int i = 0; i < SIZE; i++) { for (int j = 0; j < SIZE; j++) { // THIS NEXT LINE HAD THE WRONG BRACKETS IN // *(ptrArr[i])[j] = (loop + (i * j)); (*ptrArr[i])[j] = (loop + (i * j)); printf("array has base address: %lx\n", ptrArr[i]); printf("writing to: %lx\n", &(*ptrArr[i])[j]); ++loop; } } for (int i = SIZE-1; i >= 0; i--) { printf ("Freeing ptrArr[%x] with address %lx\n", i, ptrArr[i]); free (ptrArr[i]); } } 
0
source
 for(int i=0; i<5; i++) ptrArr[i] = malloc(sizeof(int) * 5); 

This suggests that ptrArr[i] is a pointer to some integers.

  *ptrArr[i][j] = (loop + (i*j)); 

This suggests that ptrArr[i][j] is a pointer to an integer.

What is it? These two pieces of code differ in the number of layers of indirection.

0
source

Your first example is incorrect because you are printing invalid array indices.

The nested loop causes this:

 printf("[%x](%2d) | ", &*ptrArr[i][j], *ptrArr[i][j]); 

The third parameter is identical to ptrArr[i][j][0] .

But this is not true. It should be ptrArr[i][0][j] , because you allocated only one internal size of your 2d array using the malloc call: ptrArr[i] = malloc(sizeof(int) * 5); .

You see that int (*ptrArr[5])[5]; really represents an array of pointers to an array of 5 integers. And ptrArr[i] is a pointer to an array of 5 integers.

It also means that the second parameter &*ptrArr[i][j] , which is identical to ptrArr[i][j] , really needs to be ptrArr[i][0] , because again we only have one size.

...

We are almost done. Replace the malloc calloc call first, so we won’t print garbage values. Then replace% x printf with qualifiers with% p and pass their corresponding parameters (void *).

Using these corrections, the first example outputs the correct addresses and the correct values ​​and has no undefined behavior (you can also remove redundant &* pairs)

(It was just a fix for your first example! I didn’t even turn to the second. But the solution is basically the same.)

0
source

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


All Articles