0

I am trying to get value from "second row" in multidimensional array. But I have some problems with that. I thought that numbers are stored sequentialy in memory so tab[2][2] is stored same as tab[4]. But it seems that I was wrong.

This is what I tried:

int b[2][2] = {{111,222},{333,444}};
int i = 0;
for(;i < 100; i++)
    printf("%d \n", **(b+i));

The problem is that I get only 111 and 333 as the result. There is no 222 or 444 in other 98 results. Why?

1
  • 1
    Yep, the double * was the issue. Would've been fine with *(b+i). Commented Apr 23, 2014 at 4:32

3 Answers 3

4

The problem is that **(b+i) doesn't do what you think it does. It evaluates to:

b[i][0]

As Matt McNabb noted,

**(b+i)

is equivalent to:

*(*(b+i)+0)

and since *(b+i) is equivalent to b[i], the expression as a whole can be seen as:

*(b[i]+0)

and hence:

b[i][0]

Since your array has only 2 rows, only the values of i for 0 and 1 are in bounds of the array (that's the 111 and 333). The rest was wildly out of bounds.

What you could do is:

#include <stdio.h>

int main(void)
{
    int b[2][2] = { { 111, 222 }, { 333, 444 } };
    int *base = &b[0][0];

    for (int i = 0; i < 4; i++)
        printf("%d: %d\n", i, base[i]);
    return 0;
}

Output:

0: 111
1: 222
2: 333
3: 444
Sign up to request clarification or add additional context in comments.

1 Comment

Explaining a bit more, *(a+b) is identical to a[b], and *a is equivalent to *(a+0) in the context of retrieving the stored value.
1

You can think of a two-dimensional array as a special form of a one-dimensional array. Your array holds 2 elements (!). (Each element happens to be an array of two elements, but let's ignore that for a sec.) Let's make the dimensions different so that we can distinguish them:

int arr2d[2][3] holds 2 elements (each being an array of 3 elements). The "primary index" is written first, that is if you have a one-dimensional array of 3 like int arr1d[3]and want to have an array of those with three elements like arr2d, you have to write arr2d[2][3]. You could arrange that with a typedef which makes it clear that all arrays in C are essentially 1-dimensional:

typedef int arr3IntT[3];
arr3IntT arr2d[2] = { {0,1,2}, {3,4,5} };

Now what does arr2d+i mean? arr2d, like any array, decays to a pointer to its first element (which is an array of 3 ints). arr2d+1 adds the offset of 1 of those elements to the address, so that like always the expression yields the address of the second element (which is the second array of 3 ints). Dereferencing it once like *(arr2d+1) yields that element, i.e. the one-dimensional sub-array of 3 ints. It decays to a pointer to its first element, i.e. a pointer to the first int in that second sub-array. Dereferencing that in the expression **(arr2d+1) yields that int, like always. To summarize: In your original code you iterate from sub-array to sub-array, always referencing the first of their elements, incidentally going out of bounds for i>1.

But principally you are right, elements of n-dimensional arrays in C are lying contiguously in memory, so you can access them one by one if you like to. You just have to index a pointer to int, not one to int[3]. Here is how: The expression arr2d decays to a pointer to its first element which is an array of 3 ints. Dereferencing that gives that first element, a one-dimensional array of 3 ints. Like all arrays, it decays to a pointer to its first element, an int, which is the very first element in the data:

#include<stdio.h>
int main()
{
    int arr2d[2][3] = { {0,1,2}, {3,4,5} };
    int *p_el1 = *arr2d;
    int i, j;


    // Sanity check by indexing 2-dimensionally
    for(i=0; i<2; i++) for(j=0; j<3; j++) printf("%d\n", arr2d[i][j]);

    // iterate the elements 1 by 1
    for(i=0; i<3*2; i++) printf("%d\n", p_el1[i]);
}

Comments

1

A multidimensional array is not a fundamentally new type. It's an array type where the elements are themselves arrays. To quote the C99 standard §6.2.5 ¶20 (Types)

An array type describes a contiguously allocated nonempty set of objects with a particular member object type, called the element type. Array types are characterized by their element type and by the number of elements in the array.

int b[2][2] = {{111, 222}, {333, 444}};

The above statement defines b to be an array of 2 elements where each element is the type int[2] - an array of 2 integers. It also initializes the array with the array initializer list. An array is implicitly converted to a pointer to its first element in some cases.

In the printf call, b decays to a pointer to its first element. Therefore, it's equivalent to &b[0] and has type int (*)[2] - a pointer to an array of 2 integers. Please note that it's undefined behaviour to access elements out of the bound of an array. Therefore, the for loop condition i < 100 is wrong. It should be i < 2. Now, let's try to demystify the expression **(b+i).

b -------------> pointer to a[0]
b + i ---------> pointer to a[i]
*(b + i)  -----> a[i]
*(*(b + i)) ---> *(a[i]) ----> *(&(a[i])[0]) ----> a[i][0]

As noted, the elements of the array are themselves arrays. Therefore, a[i] is an array. Again, the array decays to a pointer to its first element, i.e., to &(a[i])[0]. Applying indirection operator * on this pointer gets us the value at that address which is a[i][0].

You can access the elements of the array through a pointer but the pointer type must be a pointer to element type of the array.

#include <stdio.h>

int main(void) {
    int b[2][2] = {{111, 222}, {333, 444}};
    int (*p)[2] = b;

    // (sizeof b / sizeof b[0]) evaluates to 
    // the size of the array b
    for(int i = 0; i < (sizeof b / sizeof b[0]); i++)
        // (sizeof *p / sizeof (*p)[0]) evaluates to
        // the size of element of the array which is
        // itself an array.
        for(int j = 0; j < (sizeof *p / sizeof (*p)[0]); j++)
            printf("%d\n", *(*(p + i) + j));

    return 0;
}

Here, the expression *(*(p + i) + j) can be decoded as

p  ---------------> pointer to the first element of b, i.e., &b[0]
(p + i) ----------> pointer to b[i], i.e., &b[i]
*(p + i) ---------> the array element b[i] ---> decays to &(b[i])[0]
*(p + i) + j -----> &(b[i])[j]
*(*(p + i) + j) --> the element b[i][j]

Therefore, the expression *(*(p + i) + j) is equivalent to b[i][j]. In fact, the C99 standard §6.5.2.1 ¶2 says -

The definition of the subscript operator [] is that E1[E2] is identical to (*((E1)+(E2)))

This means we have the following are equivalent with context to the above program -

*(*(p + i) + j)
// equivalent to
p[i][j]
// equivalent to
b[i][j]
// equivalent to
*(*(b + i) + j)

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.