5

I created two 2D arrays (matrix) in C in two different ways.
I don't understand the difference between the way they're represented in the memory, and the reason why I can't refer to them in the same way:

scanf("%d", &intMatrix1[i][j]); //can't refer as  &intMatrix1[(i * lines)+j])

scanf("%d", &intMatrix2[(i * lines)+j]); //can't refer as &intMatrix2[i][j])

What is the difference between the ways these two arrays are implemented and why do I have to refer to them differently?

How do I refer to an element in each of the arrays in the same way (?????? in my printMatrix function)?

int main()
{
   int **intMatrix1;
   int *intMatrix2;

   int i, j, lines, columns;

   lines = 3;
   columns = 2;

   /************************* intMatrix1 ****************************/

   intMatrix1 = (int **)malloc(lines * sizeof(int *));

   for (i = 0; i < lines; ++i)
      intMatrix1[i] = (int *)malloc(columns * sizeof(int));

   for (i = 0; i < lines; ++i)
   {
       for (j = 0; j < columns; ++j)
       {
       printf("Type a number for intMatrix1[%d][%d]\t", i, j);
       scanf("%d", &intMatrix1[i][j]); 
       }
   }

   /************************* intMatrix2 ****************************/ 

   intMatrix2 = (int *)malloc(lines * columns * sizeof(int));

   for (i = 0; i < lines; ++i)
   {
       for (j = 0; j < columns; ++j)
       {
       printf("Type a number for intMatrix2[%d][%d]\t", i, j);
       scanf("%d", &intMatrix2[(i * lines)+j]);
       }
   }

   /************** printing intMatrix1 & intMatrix2 ****************/

   printf("intMatrix1:\n\n");
   printMatrix(*intMatrix1, lines, columns);

   printf("intMatrix2:\n\n");
   printMatrix(intMatrix2, lines, columns);
}


/************************* printMatrix ****************************/

void printMatrix(int *ptArray, int h, int w)
{
    int i, j;

    printf("Printing matrix...\n\n\n");

    for (i = 0; i < h; ++i)
        for (j = 0; j < w; ++j)
        printf("array[%d][%d] ==============> %d\n, i, j, ??????);
}
tempy
  • 897
  • 3
  • 14
  • 22
  • 2
    But in reality there is no such things as two-dimensional array - AFAIK, both of them are just a line of bytes in the memory. – tempy Oct 08 '12 at 15:18
  • [This question](http://stackoverflow.com/questions/890961/in-c-which-is-the-way-to-access-a-2d-array-sequentially-memory-block-wise) looks similar. – Anirudh Ramanathan Oct 08 '12 at 15:19
  • http://stackoverflow.com/questions/16004668/c-allocating-a-matrix-in-a-function/27366086#27366086 I have made a solution program for gcc C11/C99 with apropriate allocation funtions. Maybe it will be useful 4u... – 42n4 Dec 08 '14 at 20:40

4 Answers4

5

You are dereferencing the Matrix1 two times..

Matrix1[i][j] ;

It means that it is a 2D array or a double pointer declared like this.

int **Matrix1 ;

A double pointer could be thought of as array of pointers. Its each element is a pointer itself, so it is dereferenced once to reach at the pointer element, and dereferenced twice to access the data member of that member pointer or array. This statement as you you wrote is equivalent to this one..

Matrix1[i][j] ;   //is ~ to

*( *(Matrix1 + i) + j) ;

For a single pointer like this.

int *Matrix2 ;

You can derefernce it only once, like this.

Matrix2[i] ;  //is ~ to
*(Matrix2 + i) ;

This statement which you wrote..

Matrix2[(i * lines)+j] ;
         |-----------|

This portion evaluates to a single number, so it derefenced one time.

(i * lines) + j ;

As for your printmatrix() function, the ptArray passed to it is a single pointer. So you cannot dereference it twice.

Perhaps you can get better understanding of static and dynamic 2D arrays from my answer here.

2D-array as argument to function

Community
  • 1
  • 1
Coding Mash
  • 3,338
  • 5
  • 24
  • 45
3

Both matrices are sequences of bytes in memory. However, the difference between them is how you're defining the memory interface to represent a matrix. In one case you're just defining a memory segment with a number of elements equal to the elements in the matrix, and in the other case you're specifically allocating memory to represent each specific line.

The following case is more expensive computationally, because you're invoking malloc() a greater number of times:

intMatrix1 = (int **)malloc(lines * sizeof(int *));
for (i = 0; i < lines; ++i)
  intMatrix1[i] = (int *)malloc(columns * sizeof(int));

However, it brings the advantage that you get to refer to matrix elements in a clearer fashion:

intMatrix1[i][j];

If you just allocate one sequence of elements equal to the number of elements in the matrix, you have to take in account line/column index calculations to refer to the right matrix elements in memory.

To attempt to increase the degree of uniformity in the code, may I suggest a function that receives the matrix line reference and matrix column-count and prints a line?

void PrintLine(int *ptrLine, int lineLen) {
   unsigned int i;
   for(i = 0; i < lineLen; i++)
      printf("%d ", ptrLine[i]);
   printf("\n");
}

And then, for each matrix type, you would just do:

// Case 1
for(i = 0; i < lines; i++)
   PrintLine(intMatrix1[i], columns);
// Case 2
for(i = 0; i < lines; i++) {
   PrintLine(intMatrix2 + i*columns, columns);
}
Blitzkoder
  • 1,768
  • 3
  • 15
  • 30
2

The difference is that the first array:

intMatrix1 = (int **)malloc(lines * sizeof(int *));

Creates an array of pointers intMatrix1. Each of those pointers points to an int array (which you malloc here).

for (i = 0; i < lines; ++i)
   intMatrix1[i] = (int *)malloc(columns * sizeof(int));

That's why you need the 2 stars (dereference to the pointer array, then to the int array) in the declaration and the double brackets to access single elements:

int **intMatrix1;

int i = intMatrix[row][column];
int i = *(*(intmatrix + row) + column);

For the second matrix, you create just an int array of size column * rows.

int *intMatrix2 = (int *)malloc(lines * columns * sizeof(int));

int i = intMatrix[row + column];
int i = *(intMatrix + row + column);

To print the 2 arrays you will have to use different print functions, because the internal structure of the 2 matrix is different, but you already know the different methods to access both arrays.

Minion91
  • 1,911
  • 12
  • 19
2

In C, the array access operator [] is really just a cleaner way of performing pointer arithmetic. For a one-dimensional array of elements of type type_s, arr[i] is equivalent to *(arr + (i * sizeof(type_s))). To dissect that expression:

  • arr will be the base address, the lowest memory address where this array is stored
  • i is the zero-indexed position of the element in the array
  • sizeof returns the number of chars (which is generally the same as the number of bytes, but it's not mandated by the C spec) that an element in arr takes up in memory. The compiler will determine the size of the element and take care of performing this math for you.

As a side note, this syntax has the side effect of arr[i] being equivalent to i[arr], although it's universally accepted to put the index in brackets.

So with all of that said, let's look at the differences between your two declarations:

intMatrix1[i][j] is equivalent to *(*(intMatrix1 + i * sizeof(int)) + j * sizeof(int)). So, there are two dereference operators in that expression, meaning that intMatrix is an array of arrays (it contains pointers to pointers).

On the other hand, intMatrix2[(i * lines)+j] is equivalent to *(intMatrix2 + ((i * lines) + j) * sizeof(int)), which contains only one dereference operator. What you're doing here is defining a one-dimensional array that contains the same number of elements as the original two-dimensional array. If your data can be best represented by a matrix, then I recommend you use the first version: intMatrix1[i][j].

Zach Rattner
  • 20,745
  • 9
  • 59
  • 82