3

I wrote a program the involved two rows of integers that would periodically swap places. So, what I did was allocate two separate pointers to integers that would model the needed rows. I then placed both of the pointers into a constant pointer array that would easily facilitate the swapping.

The problem I am having was by complete mistake. Take this for example:

#include <stdio.h>
#include <stdlib.h>

int main(void) {
    char* a = malloc(sizeof(char)*5);
    char* temp[] = {a};
    int i, h, k = 'a';

    for(i = 0; i < 5; i++)
        a[i] = k++;

    for(i = 0; i < 5; i++)
        printf("%c ", temp[0][i]);

    free(a);
    return 0;
}

With output: a b c d e IdeOne

I accidentally attempted to access the members of the array contained within the static array by second-order dereferencing: "[][]"

I did not think much of this event because everything compiled and ran perfectly, even giving the expected results at the output. The problem came when I ran a memory analysis and found that I was getting tons of addressing errors and alleged memory leaks.

So, to start the debugging process I wanted to come here and ask why this worked and if it's valid C syntax. I was under the impression that:

temp[0]

Would dereference to char*, a. It would then take a further dereference of a to access its members. Further, I was under the impression that:

temp[row][col]

Is translated to:

*(*(temp + row*col) + col)

at run time. As such, the double dereference of temp[0][i] should give an offset from temp and not access a at all.


What's more interesting is that this:

#include <stdio.h>
#include <stdlib.h>

int main(void) {
    char* a = malloc(sizeof(char)*5);
    char* b = malloc(sizeof(char)*5);
    char* temp[] = {a, b};
    int i, h, k = 'a', j = 'A'; 

    for(i = 0; i < 5; i++){
        a[i] = k++;
        b[i] = j++;
    }

    for(i = 0; i < 5; i++){
        for(h = 0; h < 5; h++)
            printf("%c ", temp[i][h]);
        puts(""); 
    }

    free(a);
    free(b);
    return 0;
}    

Does not compile when run at IdeOne. However, this code does compile using Microsoft Visual Studio Professional 2013 and gcc in c99 mode.

Any ideas or suggestions on how to properly do what I was attempting to do? That is, access members a and b that are contained within the static array temp without using really ugly syntax like:

*(temp[i] + sizeof(char)*h)
sherrellbc
  • 4,650
  • 9
  • 48
  • 77
  • 3
    Your first program is completely fine, and your reasoning about addressing is correct (except `row*col` calculations). The second one accesses five indexes of `temp` while there only two available. – hamstergene Apr 22 '14 at 08:42
  • Arrays aren't "*dereferenced*". – alk Apr 22 '14 at 08:49
  • @alk, Arrays are constant pointers to memory and as such are dereferenced when used. For example, some `int* foo[5]` array really is the same as a constant integer array that pointers to a block of memory `sizeof(int)*5`. It follows that `foo[2]` points to the third integer, but one may also use `*(foo+2)` to dereference to the same member. Perhaps you are correct in that the correct jargon was not used in the title, but everyone seemed to get the idea here. – sherrellbc Apr 22 '14 at 14:15
  • I do not see any reason why to use incorrect wording by intention. – alk Apr 22 '14 at 14:30
  • `int * foo[5] ` is an array of **pointers to** `int`. I has a size of `5 * sizeof (int *)`. – alk Apr 22 '14 at 14:34
  • I did not intentionally do anything, I just don't see the difference given how the compiler interprets the array indexing brackets anyway. – sherrellbc Apr 22 '14 at 14:34
  • You got me, I did not mean to add the asterisk. Thanks – sherrellbc Apr 22 '14 at 14:35
  • Sorry, but if you "*... did **not** intend to put an asterisk*, your statement "*foo[2] points to the third integer*" is wrong. Correct would be "*foo[2] **holds** the third integer*". The former is correct for `int * foo[5]`. However stating "*... `foo + 2` points to the third integer*" would be correct. – alk Apr 22 '14 at 14:37
  • Oh boy, quite the pedant. Thank you again. I was referring to the fact that `foo` is a constant pointer and as such *(foo+2) directs the user towards the third integer. – sherrellbc Apr 22 '14 at 14:39
  • "*quite the pedant*" err, not me but the subject: This is math! Never mind however .. ;-) – alk Apr 22 '14 at 14:41

3 Answers3

3

temp[row][col] is not equivalent to *(*(temp + row*col) + col), but actually equivalent to *(*(temp + row) + col).

Your second example code is incorrect because temp is an array of 2 elements, but you are accessing temp[i] with i ranges from 0 to 5.

Yu Hao
  • 119,891
  • 44
  • 235
  • 294
  • I see what you mean. I suppose I was thinking in the context of a `char**` with memory "blocks" corresponding to the rows .. or something like that. I get what I meant but it has no relevancy here. – sherrellbc Apr 22 '14 at 14:18
  • Say I had some: `int temp[3][3]`, would it not be structured in memory as: `1 2 3 4 5 6 7 8 9` ? Where we have symbolic "blocks" in this contiguous memory corresponding to the rows of the 2D array? That is, `1 2 3, 4 5 6, 7 8 9`. As such, if we want to access `temp[2][2]` arbitrarily, we would have to do: `*(*(temp+2*3)+2)`, correct? The first `col` in the expression that I included in the original post was `number of columns`, rather than `col` th8at was included in `temp[row][col]`. The expression you include: `*(*(temp + row) + col)` appears valid only for `char*` arrays. – sherrellbc Apr 22 '14 at 14:24
  • ajay lists below a excerpt from the C99 standard, so it must be correct - I just do not see how. Are 2D arrays allocated using constant pointers to the rows? If so, that would make much more sense than what I was thinking and the above expression would therefore be valid. – sherrellbc Apr 22 '14 at 14:30
  • @sherrellbc The compiler knows the element of `temp` is another array, so when it sees `temp + row`, it knows how much size advance to find the next element. – Yu Hao Apr 22 '14 at 14:57
1

You guessed it right when you thought temp[0] equals a and temp[1] equals b. But wait why are you going beyond that like you are trying to dereference something like temp[2]? You did not initialize this thing right!

Your program causes undefined behaviour by accessing memory past the end of the array. The compiler is not always obliged to give you an error message. Check this question.

Community
  • 1
  • 1
bubble
  • 3,408
  • 5
  • 29
  • 51
1

The C99 standard §6.5.2.1 ¶2 says -

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

Therefore, the expression temp[row][col] is evaluated as

temp[row][col] --> *((temp[row]) + col) --> *(*(temp + row) + col)
|_______|  |
    |      |
   E1     E2

and not as *(*(temp + row*col) + col). Please note the difference. Therefore, your first program is fine.

In the second program, the statement

char* temp[] = {a, b};

defines and initializes temp to be an array of 2 pointers to characters. However, in the for loop, you access the array as temp[i][h] and i ranges from 0 to 4. Accessing elements out of the bound of an array is undefined behaviour. Therefore, your second program is wrong.

ajay
  • 9,402
  • 8
  • 44
  • 71