Store simple value in a matrix in C

I have a simple program that scanf a value at a time then store it in a row (p) then store it in a matrix (pg).

//
// Created by herveDarritchon on 15/01/2022.
//

#include <stdio.h>

int main() {
    int dim = 0;
    printf("dim ?\n");
    scanf("%d", &dim);
    short tab[dim];
    short *p;
    short **pg;
    p = &tab[0];
    short tab_double[dim][dim];
    pg = (short **) &tab_double[0];

    for (int j = 0; j < dim; j++) {
        for (int i = 0; i < dim; i++) {
            printf("value: ");
            scanf("%d", &p[i]);
            printf("value stored : %d\n", p[i]);
        }

        printf("value in tab: ");

        for (int l = 0; l < dim; l++) {
            printf("%d|", tab[l]);
        }

        printf("\n");
        pg[j] = tab;
        printf("value ub pg[%d]: ", j);

        for (int l = 0; l < dim; l++) {
            printf("%d|", pg[j][l]);
        }

        printf("\n");
    }

    for (int k = 0; k < dim; k++) {
        printf("value ub pg[%d]: ", k);

        for (int l = 0; l < dim; l++) {
            printf("%d|", pg[k][l]);
        }

        printf("\n");
    }
}

Result is

dim ?
2
value: 1
value stored : 1
value: 2        
value stored : 2    
value in tab: 1|2|  
value ub pg[0]: 1|2|
value: 3
value stored : 3
value: 4
value stored : 4
value in tab: 3|4|
value ub pg[1]: 3|4|
value ub pg[0]: 3|4|
value ub pg[1]: 3|4|

But at the end, the matrix (pg) only stores the last row in all its index :(

I think I did something wrong with pointers ... but I can't figure out why the matrix has only the last row.


Solution 1:

The line

pg = &tab_double[0];

was giving you a compiler warning. You seem to have suppressed this warning by adding a type cast:

pg = (short **) &tab_double[0];

However, it was not a good idea to suppress the compiler warning like that. The compiler was pointing out that something was wrong.

With the line

short tab_double[dim][dim];

you are declaring a two-dimensional (2D) array.

A 2D array is nothing more than an array of arrays. The inner arrays are of type short[dim] (array of dim elements, where each element is of type short) and the outer array is of type short[dim][dim] (array of dim elements, where each element is of type short[dim]).

If you want pg to point to the first element of the outer array, then you should make its type reflect this. You want it to point to an element of type short[dim]. Therefore, the type of the pointer should be short (*)[dim] (the parentheses are necessary, because otherwise the type would be an array of pointers to objects of type short). So you should declare the pointer like this:

short (*pg)[dim];

However, you are instead declaring the pointer like this:

short **pg;

This tells the compiler that pg will be pointing to a pointer to a short. However, this information is incorrect. As mentioned above, you want it to point to an object of type short[dim] (i.e. to an array of dim elements of type short).

An array is not a pointer (although arrays often decay to pointers in certain situations).

After fixing this, your compiler will now give you an error in the following line:

pg[j] = tab;

This is because you cannot directly assign a value to an array. However, you can

  • copy one element at a time from one array to another array in a loop, until the entire array is copied, or
  • copy the memory contents of one array to another array, using memcpy.

Solution 2:

You are confusing arrays with pointers and seem to assume they are somehow the same. That is not true.

Look at the memory layout:

short arr[dim][dim];

In memory this looks like this (assume dim==3):

 +---------+---------+---------+---------+---------+---------+---------+---------+---------+
 |    +0   |    +2   |    +4   |    +6   |    +8   |    +A   |    +C   |    +E   |   +10   |
 +---------+---------+---------+---------+---------+---------+---------+---------+---------+
 |arr[0][0]|arr[0][1]|arr[0][2]|arr[1][0]|arr[1][1]|arr[1][2]|arr[2][0]|arr[2][1]|arr[2][2]|
 +---------+---------+---------+---------+---------+---------+---------+---------+---------+
  

This is similar to your short tab_double[dim][dim];

On the other side look at this:

short **pg;

In memory this looks like this (assume 32 bit addresses):

 +----------+----------+----------+
 |    +0    |    +4    |    +8    |
 +----------+----------+----------+
 |   pg[0]  |   pg[1]  |   pg[2]  |
 +----------+----------+----------+

and furthermore it depends on the content of p[x] where p[x][0] is located.

As you can see, the memory layout of short **pg is very different from short tab_double[dim][dim]

With that assignment pg = (short **) &tab_double[0]; you tell your compiler to treat the memory that holds the first few elements of your array as an array of pointers. That causes memory corruption.