Search code examples
cmultidimensional-arrayc99

Why isn't indexing a 2D Array by pointer arithmetic the same as using [j] brackets, though the spec says it should be?


Learning C, I stumbled upon this video on which page 82 of the C99 specification appears (though it's dated 2007, maybe a revision?).

Therein it is stated that any expression that indexes arrays using subscripts, such as E1[E2], where one is pointer to object type and the other is type integer, is identical to (*((E1)+(E2))), because of the conversion rules that apply to the + operator. That is to say, using pointer arithmetic is the same as using the square brackets.

My question is: why doesn't this seem to be the case in my code? I have a 2D char array and I'm passing it to a function, which means it gets implicitly converted to type pointer to char array. One of the operations to assign values to its members works properly, the other one (that in the code below is commented out) doesn't, and instead accesses seemingly random memory addresses.

int main(void) {
    char frame[S_HEIGHT][S_WIDTH];
    frame_init(frame);
    // ...
}

// ...

int frame_init(char (*frame)[S_WIDTH]){
    char ch = 'M';
    for(int i = 0; i < S_HEIGHT; i++){
        for(int j = 0; j < S_WIDTH; j++){
            *(*(frame + i) + j) = ch;    // this works! and so does (frame)[i][j] of course
         // *(frame + i)[j] = ch;        // this should be equivalent, but accesses wrong addresses
        }
    }
}

Of course, if you do the unravelling manually, following the rules of the specification, you see that

(frame)[i][j] == *(frame + i)[j] == *(*(frame + i) + j)

but only the first and third work, the second doesn't. Though it should, since *(frame + i) is of type pointer to char, and it therefore is a valid expression for subscript indexing. It compiles and everything.

What's the deal with this? Is it just that I'm using a newer revision of C, where this was changed? I tried looking up the spec, but I could only find this, which like hell I'm going to pay for. Is there no free way of reading the spec?

I really appreciate whoever takes the time to read and share their knowledge. I love C, and I love you too. Best wishes, Michele.


Solution

  • *(frame + i)[j]
    

    means:

    *((frame + i)[j])
    

    which is:

    frame[i + j][0]
    

    You meant:

    (*(frame + i))[j]
    

    which indeed is equivalent to:

    frame[i][j]
    

    You might be interested in https://en.cppreference.com/w/c/language/operator_precedence . * has precedence 2, but [] has precedence 1.

    Is there no free way of reading the spec?

    No. Where the ingestible version of the standard in cppreference is not enough, the mighty link https://port70.net/~nsz/c/c11/n1570.html comes up, which technially contains the draft of the C standard.