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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.