skip to Main Content

Please can someone explain to me this strange pointer behaviour. Did I miss something?!?

start first attempt

int *foo=(int*)malloc(sizeof(int)*4);//allocates memory for 4 integer with size of sizeof(int) foo points to the address of the first element-  foo=&foo[0]

for (int i = 0; i < 4; i++)
{
    *foo=i+1;
    foo++;
    printf("foo[%d] :%d n",i,foo[i]);
}

Otput is something like this

foo[0] :0
foo[1] :0
foo[2] :0
foo[3] :0

end first attempt

Lets add one tiny thing to our code:

start second attempt

int *foo=(int*)malloc(sizeof(int)*4);//same as first attempt

int* ptr=foo;//???????????????????? why this is necessary?

printf("Value of foo: %d value of ptr is: %d &foo[0] %dn",foo,ptr, &foo[0]);

for (int i = 0; i < 4; i++)
{
    *ptr=i+1;//assign and update via ptr
    ptr++;
    printf("foo[%d] :%d n",i,foo[i]);
}

Output

Value of foo: 1322628816 value of ptr is: 1322628816 &foo[0] 1322628816
foo[0] :1
foo[1] :2
foo[2] :3
foo[3] :4

end second attempt

Note: I use Ubuntu 18.04, gcc (Ubuntu 11.4.0-2ubuntu1~18.04) 11.4.0 with GNU C Library (Ubuntu GLIBC 2.27-3ubuntu1.6) stable release version 2.27

I try exactly what I wrote above

3

Answers


  1. After you do foo++, foo no longer points to the beginning of the array, it points the i+1th element of the array. When you then try to access foo[i], you’re accessing the element i places after this element, i.e. original_foo[i+1+i].

    It works in the second version because the pointer you’re indexing is not the one you’re incrementing. So foo continues to point to the beginning of the array, and foo[i] is the element you just assigned.

    Login or Signup to reply.
  2. *foo=i+1;
    

    This initializes the first int of the four-int area you malloc()ed.

    foo++;
    

    This makes foo point to the second int.

    printf("foo[%d] :%d n",i,foo[i]);
    

    You’re printing foo + i, i.e. the second (uninitialized) int, invoking UB.

    Things get only worse from there, since you keep incrementing foo and i… in the end, you’re reading from memory you haven’t even malloc()ed.


    Your second example works since you increment ptr for writing, and i (as index on foo) for reading.

    Login or Signup to reply.
  3. for (int i = 0; i < 4; i++)
    {
        *foo=i+1;                           // 1
        foo++;                              // 2
        printf("foo[%d] :%d n",i,foo[i]);  // 3
    }
    
    1. Here you assign i+1 to the int foo points at. That in itself is not wrong.
    2. Here you make foo point at the next element in the allocated memory. You’ve now lost the base pointer – unless you later restore it by counting backwards or saving the pointer before the loop starts.
    3. In foo[i] you add yet i to where the base pointer points. You’ve now effectively made it *(original_foo + i + i) which very soon becomes out of bounds.

    An idiomatic solution would be to not change foo at all:

    for (int i = 0; i < 4; i++) {
        foo[i] = i + 1;
        printf("foo[%d] :%d n", i, foo[i]);
    }
    

    Demo

    Regarding:

    int* ptr=foo;//???????????????????? why this is necessary?

    That’s the saving of the base pointer I mentioned as a possible workaround in point 2 above. In the following loop, you only change ptr and let the base pointer foo be untouched. Dereferencing foo[i] (same as *(foo + i)) then does the correct thing.

    for (int i = 0; i < 4; i++)
    {
        *ptr=i+1;                          // 1
        ptr++;                             // 2
        printf("foo[%d] :%d n",i,foo[i]); // 3
    }
    
    1. Again, assign i+1 to where ptr points.
    2. Step the temporary int* one step ahead.
    3. Dereference foo[i] (*(foo + i)) which dereferences the same address that ptr pointed at prior to ptr++.
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search