Home > database >  how to access c 2d array with 1 index
how to access c 2d array with 1 index

Time:12-09

I have the following:

#include <stdio.h>

int main() {

    int a[2][2] = { 0,1,2,3};
    printf("\n%d %d \n%d %d\n",a[0][0],a[0][1],a[1][0],a[1][1]);
    printf("%d %d %d %d\n",*a[0],*a[1],*a[2],*a[3]);

    return 0;
}

which returns:

0 1 
2 3
0 2 0 1491303602

Is there a way to access the 2d array with 1 index? Since the array is held in contiguous memory, shouldn't we be able to do this?

also:

printf("\n%d %d \n%d %d\n",&a[0][0],&a[0][1],&a[1][0],&a[1][1]);
printf("%d %d %d %d\n",a[0],a[1],a[2],a[3]);

produces the following:

1137924528 1137924532 
1137924536 1137924540
1137924528 1137924536 1137924544 1137924552

so why are the memory addresses of the first two elements &a[0][0] = a[0] and &a[0][1] = a[1] but the last two don't match?

CodePudding user response:

In your code snippet

#include <stdio.h>

int main() {

    int a[2][2] = { 0,1,2,3};
    printf("\n%d %d \n%d %d\n",a[0][0],a[0][1],a[1][0],a[1][1]);
    printf("%d %d %d %d\n",*a[0],*a[1],*a[2],*a[3]);

    return 0;
}

the line

printf("%d %d %d %d\n",*a[0],*a[1],*a[2],*a[3]);

is equivalent to:

printf("%d %d %d %d\n",a[0][0],a[1][0],a[2][0],a[3][0]);

This means that you are accessing the object a out of bounds, which invokes undefined behavior.

What you probably want to do is the following:

#include <stdio.h>

int main() {

    int a[2][2] = { {0,1}, {2,3} };
    int *p = &a[0][0];
    printf("%d %d \n%d %d\n",a[0][0], a[0][1], a[1][0],a[1][1]);
    printf("%d %d %d %d\n", p[0],p[1], p[2], p[3] );

    return 0;
}

Another way of writing this is like this:

#include <stdio.h>

int main() {

    int a[2][2] = { {0,1}, {2,3} };
    printf( "%d %d \n%d %d\n", a[0][0], a[0][1], a[1][0], a[1][1] );
    printf( "%d %d %d %d\n", a[0][0], a[0][1],a[0][2], a[0][3] );

    return 0;
}

These programs have the following output on my compiler:

0 1 
2 3
0 1 2 3

Although this will probably work on all compilers, it is worth noting that doing this may invoke undefined behavior, depending on how strictly you interpret the standard. This is because you are accessing the first sub-array a[0] out of bounds, but not the object a as a whole. See the following question for further information:

One-dimensional access to a multidimensional array: is it well-defined behaviour?

The compilers gcc and clang actually both provide a run-time warning for the second program, if I compile with -fsanitize=undefined. The compiler clang additionally provides a compile-time warning, if I enable all warnings.

For these reasons, it would probably be better to declare a 1D array instead of a 2D array, and to perform the index calculatings into the 1D array yourself, if you want to use the 1D array as a 2D array. That way, you can be sure that what you are doing is allowed by the ISO C standard. Here is an example:

#include <stdio.h>

#define ROWS 2
#define COLUMNS_PER_ROW 2

int calculate_1D_offset( int row, int column )
{
    return row * COLUMNS_PER_ROW   column;
}

int main( void )
{
    int a[ROWS*COLUMNS_PER_ROW] = { 0, 1, 2, 3 };

    //find the value of a[1][0], as if "a" were a 2D array
    printf( "%d\n", a[calculate_1D_offset(1,0)] );
}

This program has the following output:

2

so why are the memory addresses of the first two elements &a[0][0] = a[0] and &a[0][1] = a[1] but the last two don't match?

The array a consists of 2 sub-arrays, each consisting of 2 int elements. So the total number of int elements is 4.

In your question, the addresses are the following:

1137924528 is the address of the element a[0][0].
1137924532 is the address of the element a[0][1].
1137924536 is the address of the element a[1][0].
1137924540 is the address of the element a[1][1].

In your question, the line

printf("%d %d %d %d\n",a[0],a[1],a[2],a[3]);

has the following output:

1137924528 1137924536 1137924544 1137924552

The last two addresses are out of bounds, because the sub-arrays a[2] and a[3] do not exist. Only a[0] and a[1] exist.

If a[2] did exist, its address would be 1137924544, which would be the the address of the 5th int element of the 2D array, i.e. a[0][4] (because indexes in C are 0-based).

However, I doubt that these addresses are actually correct, because you are using the wrong printf format specifier for printing an address. In order to print an address, you should use %p instead of %d, as %d is intended for an int, not a pointer. On platforms on which pointers are 64-bit and an int is 32-bit, the 32 most significant bits may be stripped off the value, or worse.

CodePudding user response:

#include <stdio.h>

int main(void) {

    int a[2][2] = { 0,1,2,3};
    printf("\n%d %d %d %d\n",a[0][0],a[0][1],a[1][0],a[1][1]);
    printf("%d %d %d %d\n",*a[0],*(a[0]   1), *a[1], *(a[1]   1));
}

https://godbolt.org/z/3avvnssn5

Result:

0 1 2 3
0 1 2 3

CodePudding user response:

Lets "draw" your array:

 --------- --------- --------- --------- 
| a[0][0] | a[0][1] | a[1][0] | a[1][1] |
 --------- --------- --------- --------- 

From this it's easy to see a pattern emerging, telling us that we can use a single array to represent all two "dimensions":

 --------- --------- --------- --------- 
| a[0]    | a[1]    | a[2]    | a[3]    |
 --------- --------- --------- --------- 

Now all we have to do is come up with a formula to calculate the one-array index from the matrix x,y pair.

In the first "row" we get the index by simply using the column index. For the second "row" we need to add the number of "columns".

So the generic calculation is current_row * total_columns current_column.

I code it would look something like this:

const int total_rows = 2;
const int total_columns = 2;

char a[total_rows * total_columns] = { 1, 2, 3, 4 };

for (unsigned current_row = 0; current_row < total_rows;    total_rows)
{
    for (unsigned current_column = 0; current_column < total_columns;    total_columns)
    {
        printf("matrix[%d][%d] = %d\n", current_row, current_column,
               a[current_row * total_columns   current_column);
    }
}
  • Related