Ambiguity in declaring a 2d array in C

I defined the array in the following formats, but apparently the program only works fine in CASE B.

CASE A:

int **M1; M1 = (int **)malloc(m * sizeof(int *)); for (int i=0; i<m; i++){ M1[i] = (int *)malloc(d * sizeof(int)); } 

CASE B:

 int (*M1)[m] = malloc(sizeof(int[m][d])); 

I get a segmentation error in CASE A. What could be the reason?

+6
source share
3 answers

The following code compiles without error or warning in the gcc compiler,

  int **M1,i; M1 = (int **)malloc(5 * sizeof(int *)); for (i=0;i<5;i++){ M1[i] = (int *)malloc(2 * sizeof(int)); } M1[0][0]=111; M1[0][1]=222; printf("\n%d %d",M1[0][0],M1[0][1]); 

Gives 111 222 as a conclusion.

The problem may be elsewhere in your code.

+3
source

CASE A;

M1 is a pointer to a pointer. You allocate memory for a 2D array of type int, and you can store the m*d values ​​in the array.

M1[0][0] to M[m-1][d-1] are valid accesses for this array to get a value of type int , and something else besides this will lead to undefined behavior.

Case B:

M1 is a pointer to an array of type int that has m elements.

In case A, the segmentation error most likely looks because the array is not associated with access.

+1
source

A pointer and an array are two different things. The type pointer contains the address at which the variable of the declared type is allocated.

A type array is a memory space in which variables of the declared type are stored in the cathedral .

Now you are a declaration. There is no ambiguity (even if it is not so obvious) in the declaration C. In case A, you stated:

 int **M1; 

This is not a 2d array, not even one-dimensional. You declare a variable, M! as a pointer to another pointer to an int. The flat word M1 will store the address of another variable, which, in turn, contains the address where an integer is stored in memory. Now execution:

 M1 = (int **)malloc(m * sizeof(int *)); 

You assign M1 address of a memory area that can store up to m adjacent integer pointers , the memory access indicated by the M1 symbol, and subsequent locations act as array access (but this is not the case). This is more or less equivalent to a static declaration:

 int *[m]; //an array of pointers to int 

Then assigning to each element of this pseudo-memory array for d adjacent integers:

 for (int i=0; i<m; i++) { M1[i] = (int *)malloc(d * sizeof(int)); } 

now you have a place to store d consecutive integers that start with the addresses stored in M1[i] for i = 0-> d-1.

What happens when you try to access a value using indices: M1[a][b] ? The compiler extracts the address indicated by M1 and, using the first index ( a ), extracts the contents indicated by the address at atht position of the pointer array. This points to the first integer subspace we allocated to store d consecutive ints. This is really an int monomeric array. Applying the second index to it, the compiler finally extracts the required integer. Cose for a two-dimensional addressing array, but not a banana! This is not a two-dimensional int array. :-)

In case B, you declare a pointer to the monomeric array int , to which you assign enough space to store your two-dimensional array. Since in C there is no concept of a multidimensional array, but the basic principle of an array is array ..., etc. (Ad-libitum) ad:

 int (*M1)[m] = malloc(sizeof(int[m][d])); 

as a pointer to a modem array with the space allocated for the array of elements [m][d] , did the trick.

But, of course, both decisions are wrong!

You use side effects to get what you want, but using surrogates for what you have been told you need: a two-dimensional array of int.

The correct solution is to define a pointer to a two-dimensional array of integers where only the first index is required:

 int (*M1)[][m]; //declare a pointer to a real array M1 = malloc(m * d * sizeof(int)); //Allocate room for bidimensional array for (int i=0; i<m; i++) for (int j=0; j<d; j++) { (*M1)[i][j] = (i*100)+j; //Fill elements with something using bidimensional subscripting } for (int i=0; i<m; i++) for (int j=0; j<d; j++) { printf("[%d][%d]=%d\n", i, j, (*M1)[i][j]); //Check back data... } 

Now let's see what happens if you get out of bounds in 3 cases. In case A , if you go beyond the boundaries with the first index , you will collect an incorrect pointer that will immediately cause a memory error ; in case B , you will have a memory error only if you exit the process address memory, the same is for the correct solution. This should answer your question .

Finally, because we are talking about misunderstanding about arrays and pointers, do not be mistaken in the standard ISO 9899: 2011 §6.7.6.3 / 7, which states:

The declaration of a parameter as a '' type array must be adjusted to a '' Qualified pointer to a type, where type qualifiers (if any) are those specified in the [and] output of the array type. If the static keyword also appears inside [and] the type of the output array, then for each function call the value of the corresponding actual argument should provide access to the first element of the array with at least as many elements as specified in size.

It simply claims that arrays are passed only by reference (automatically configured by the compiler), and not by value (which is legal for structures, i.e.) . You are not prompted to specify any qualified pointer instead of an array in a function call or a program crash ( Declaring an array of type as '' should be adjusted to “Qualified type pointer” means that it will be copied by the compiler, not by you ). Cases like char *[] and char ** work for the reason discussed above, and not because it is legal to exchange them!

+1
source

All Articles