tempy
tempy

Reputation: 907

Differences between matrix implementation in C

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, ??????);
}

Upvotes: 5

Views: 2192

Answers (4)

Blitzkoder
Blitzkoder

Reputation: 1838

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);
}

Upvotes: 3

Coding Mash
Coding Mash

Reputation: 3346

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

Upvotes: 5

Minion91
Minion91

Reputation: 1929

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.

Upvotes: 2

Zach Rattner
Zach Rattner

Reputation: 21333

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].

Upvotes: 2

Related Questions