vivek upadhyay
vivek upadhyay

Reputation: 44

Printing a multidimensional array in C

I am trying to print a 2-D array in C by using pointers but I am not getting the expected output.

Program:-

#include <stdio.h>
int main()
{
    int arr[2][3] = {{1,2,3},{4,5,6}};
    int* p;
    for ( p = arr; p <= arr+6; p++)
    {
        printf("%d ", *p);
    }
    return 0;
}

Output:-

1 2 3 4 5 6 -1116112128 1587637938 0 0 1893963109 32521 -1453950296 32766 -1453805568 1 800797033 21984 -1453949463

Could you tell me where I am wrong as the output should only be:

1 2 3 4 5 6

Upvotes: 0

Views: 946

Answers (5)

Luis Colorado
Luis Colorado

Reputation: 12668

In

    for ( p = arr; p <= arr+6; p++)

the expression arr, as an rvalue, is a pointer to the first element of the array (which is of type int [3], so each time you increment that pointer, it moves three int positions forward ---a whole row---, and so, arr + 6 points just after the sixth row of the array (if the array should ever had six rows) You can do it (with the proper explicit pointer conversions, as you are mixing pointers to int with pointers to int [3]) with the expression arr + 2 which is the addres of the first array element after the second row (and the number of rows of the array).

You can do it also declaring

    int (*aux)[2][3] = &arr;  /* aux is a pointer to the whole 3x2 array,
                        * so aux + 1 will be the position of the second
                        * 2D array after this one */

and then

    int *end = (int *)(aux + 1);

or simply

    int *end = (int *)(&arr + 1); /* see below */

(Beware that arr and &arr are both pointers and point to the same place, but they are not the same type (arr is of type int (*)[3] and &arr is of type int(*)[2][3])

So let's rewrite your code as

    for (p = (int *)arr; p < end; p++)

or

    for (p = (int *)arr; p < (int *)&arr + 1; p++)

would work, which seems more natural to do the calculus in complete array units than in rows or single cells (and you can change freely the dimensions of the array)

Your code would be:

#include <stdio.h>
int main()
{
    int arr[2][3] = { { 1, 2, 3 }, { 4, 5, 6 } };
    int *end = (int *)(&arr + 1); /* try to avoid evaluating this expression in the loop 
                                   * despite that it can be optimized to comparing
                                   * with a constant value */
    char *sep = "";
    for (int *p = (int *)arr; p < end; p++)
    {
        printf("%s%d", sep, *p);
        sep = ", ";
    }
    putchar('\n');
    return 0;
}

(Beware that you have to use < operator and not <= as you don't want to print the value pointed by end, because it lies one place outside of the array)

Finally a note: this will work with true arrays, but not with function parameters declared as arrays, because they decay to pointers and then &arr is not a pointer to data the size of the array, but it is the address of the parameter itself, which points to the array somewhere else.

Upvotes: 0

Vlad from Moscow
Vlad from Moscow

Reputation: 310980

Array designators used in expressions with rare exceptions are implicitly converted to pointers to their first elements.

The type of the array elements of this array

int arr[2][3];

is int [3]. So a pointer to the first element of the array has the type int ( * )[3].

This assignment

p = arr;

where p has the type int * is incorrect because the operands of the assignment have incompatible pointer types.

At least you need to cast the right expression to the type int * like

p = ( int * )arr;

The same casting you need to use in the condition in the for loop. That is instead of

p <= arr+6

you have to write

p < ( int * )arr+6

Below there is a demonstration program that shows how to output a two-dimensional array as a two-dimensional array using pointers.

#include <stdio.h>

int main( void )
{
    int arr[2][3] = {{1,2,3},{4,5,6}};

    for ( int ( *p )[3] = arr; p != arr + 2; p++ )
    {
        for ( int *q = *p; q != *p + 3; ++q )
        {
            printf( "%d ", *q );
        }
        putchar( '\n' );
    }

    return 0;
}

If you want to output the two-dimensional array as a one-dimensional array then you can write

#include <stdio.h>

int main( void )
{
    int arr[2][3] = {{1,2,3},{4,5,6}};

    for ( int *p = ( int * )arr; p != ( int * )arr + 6; p++ )
    {
        printf( "%d ", *p );
    }
    putchar( '\n' );

    return 0;
}

Upvotes: 0

Syed M Sohaib
Syed M Sohaib

Reputation: 412

You are trying to access the value in the wrong way, The two-dimensional array is saved as a continuous block in the memory. So, if we increment the value of ptr by 1 we will move to the next block in the allocated memory.

int arr[2][3] = {{1,2,3},{4,5,6}};
int *ptr = arr;

int i,j;
for (i = 0; i < 6; i++) {
    printf("%d ", *(ptr + i));
}
return 0;

Upvotes: 0

Adrian Mole
Adrian Mole

Reputation: 51835

First, when looping through arrays of size n wth an index i, the condition for continuation should be i < n rather than i <= n, because array indexes in C run from 0 through n-1.

However, your code has a more serious error: 1-dimensional arrays can be 'decayed' into pointers to the elements' type; however, 2-dimensional arrays decay into pointers to 1-dimensional arrays. So, in your case, the type of the pointer used in the arr + 6 expression is a pointer to an array of three integers; further, when the 6 is added, that operation is performed in terms of the size of the pointed-to object, which is sizeof(int) * 3 – so, even when changing the <= to <, you will be running far beyond the actual bounds of the array.

To make the pointer arithmetic work in the correct 'units' (i.e. sizeof(int)), cast the arr to an int* before the addition (and also change the <= to <):

#include <stdio.h>
int main()
{
    int arr[2][3] = { {1,2,3},{4,5,6} };
    int* p;
    for (p = (int*)arr; p < (int*)arr + 6; p++) {
        printf("%d ", *p);
    }
    return 0;
}

Upvotes: 0

Caleb
Caleb

Reputation: 125007

Could you tell me where I am wrong

The elements of arr are not integers, but arrays of 3 integers. So arr+6 is surely a different address than what you expect, since pointer arithmetic works in multiples of the size of the type in the array.

You'll always be better off using nested loops to iterate over a multidimensional array; treating it as one single-dimensional array of int leads to exactly the kinds of confusion you see here. The code is harder to understand and verify, it won't be any slower.

Upvotes: 1

Related Questions