14

I cannot figure this out. Perhaps it is because it's 2am. At any rate, I am at a loss here.

#include <stdio.h>

int main()
{
    char array[] = "123456789";
    char* ptr = array;

    printf("%c\n", *(ptr++));
    printf("%c\n", *ptr);

    *ptr = array[3];
    printf("%c\n", *(ptr++));
    printf("%c\n\n", *ptr);

    return 0;
}

The result is:

1
2
4
3
  1. I have a pointer, which I assign to array.

  2. I then print, what I thought would be the first index ( '2' ), but instead get 1. -- So, I assume that *(ptr++) actually dereferences, before it increments the pointers.

  3. Then I reassign ptr the 4th index ( '4' ) and repeat step 2. This works as expected now that I see C does not calculate the parenthesis first before dereferencing.

  4. Then I print the newly incremented ptr to display ( '5' ) ... and I get 3?

How is that, step 1&2 and 3&4 are identical, but I get different results?

Nobilis
  • 7,310
  • 1
  • 33
  • 67
sherrellbc
  • 4,650
  • 9
  • 48
  • 77
  • 10
    `*ptr = array[3];` does not "reassign the pointer". However, `ptr = &array[3];` would have done. I suggest getting some sleep ;) – Oliver Charlesworth Jul 14 '13 at 06:07
  • 2
    *"Then I reassign ptr the 4th index ( '4' ) and repeat step 2"* It should be `ptr = &array[3]` – johnchen902 Jul 14 '13 at 06:07
  • Oh shoot, thats right. I forgot about the ampersand. – sherrellbc Jul 14 '13 at 06:09
  • Thanks for the posts. I was going crazy over this. I haven't programmed in C in ages it seems. You get quite use not having to deal with this material in other languages like Java. – sherrellbc Jul 14 '13 at 06:11
  • 4
    For future reference, please don't post screenshots of code and output. Paste the text directly into the question and format it with the `{}` toolbar button (or press Ctrl-K). – Marcelo Cantos Jul 14 '13 at 06:15
  • 1
    @sherrellbc I've made an edit so that the post includes the code as text and it's easy for people to copy and paste it and try it on their own. Hope you don't mind :) – Nobilis Jul 14 '13 at 09:54

5 Answers5

19

Let's go through the code step-by-step:

Step 0:

char* ptr = array;

Point the char pointer to the start of array (namely position 0).

Step 1:

printf("%c\n", *(ptr++));

Dereference the pointer at position 0, print the value residing there (1) and then increment the pointer to position 1

Step 2:

printf("%c\n", *ptr);

Dereference the pointer at position 1 and print the value residing there (2)

Step 3:

*ptr = arr[3];

Dereference the pointer at position 1 and update the value pointed to with the value at position 3 of the array. This is value 4.

Step 4:

printf("%c\n\n", *(ptr++));

Dereference the pointer at position 1, print the value we just updated (4) and then increment the pointer to position 2

Step 5:

printf("%c\n", *ptr);

Dereference the pointer at position 2 and print the value there (3).

Perhaps what you actually intended is to have ptr = &arr[3]; which will assign the pointer to a new position (namely the address of arr[3]).

Note that the braces around ptr in the above are actually redundant due to operator precedence.

For the case of *(ptr++), post-increment has higher precedence than indirection therefore it will be applied before we dereference the pointer

Braces are also unnecessary around *(++ptr) too. Here even though pre-increment and indirection have the same precedence, they are evaluated right-to-left. And so the pointer will be incremented before it is dereferenced.

Nobilis
  • 7,310
  • 1
  • 33
  • 67
  • 1
    That is exactly what I meant to do. I forgot about this notation. Although, I thought that *(ptr++) would, in its first instance, increment ptr to the next position then dereference, thus displaying 2. Although, I suppose there is really no difference if I were to attempt and use, in some similar context, something like (i++). The parenthesis do nothing to first increment i before its use. – sherrellbc Jul 14 '13 at 06:19
  • `*(++ptr)` would do that as it will first increment the pointer and then dereference it :) – Nobilis Jul 14 '13 at 06:22
  • In experimentation with the concept I discovered as much. My confusion was wondering why *(++ptr) and *(ptr++) displayed different results. It was my error to assume that the parenthesis were required to be evaluated before the dereference. [as in *(ptr+1) and *(1+ptr)] Unless -- I suppose that, when compiled, the parenthesis are evaluated first, but considering that the compiler recognizes a post-increment, the original value is used in the expression? As opposed to *(++ptr) where the pre-increment is used, and also recognized by the compiler as such. – sherrellbc Jul 14 '13 at 06:27
  • Actually, if you were to consider the operator precedence, in this example `*(ptr++)` you can even drop the parenthesis as post-increment has higher precedence than the dereference operator. You can even drop them in `*++ptr` even though `*` and post have the same precedence as they are evaluated right-to-left so the `++` will be evaluated before `*`. If you want to update the value pointed-to however, it's a different story :) – Nobilis Jul 14 '13 at 06:30
  • Sorry, a little correction to the above, I meant 'even though `*` and **pre** have the same precedence'. – Nobilis Jul 14 '13 at 06:39
  • @Nobilis **Suggestion** to add this for first answer: According to [Operators precedence](http://www.difranco.net/compsci/C_Operator_Precedence_Table.htm) postfist `++` operator has higher precedence over `*` (Dereference operator) Hence In expression `*(ptr++)` parenthesis are redundant that expression `*(ptr++)` is equals to `*ptr++` And this expression first prints `'1'` first element of string then increments `ptr` pointer. – Grijesh Chauhan Jul 14 '13 at 10:01
  • @GrijeshChauhan I've already put this in the comments do you think I should add it to the answer too? – Nobilis Jul 14 '13 at 10:03
  • @Nobilis Yes Add and format better your answer point to point/ – Grijesh Chauhan Jul 14 '13 at 10:04
7

Try this instead:

ptr = array + 3;
Yu Hao
  • 119,891
  • 44
  • 235
  • 294
  • I wanted to do it using array indexing, but forgot the ampersand in the above code as well as an extra *. – sherrellbc Jul 14 '13 at 06:12
  • Technically it should be `array + 3*sizeof(char)`. In this case it works out the same on most modern architectures but not all CPUs/compilers behave this way. – slebetman Jul 14 '13 at 06:15
  • 6
    @slebetman Wrong. Very wrong. Couldn't be wronger. Pointer arithmetic is performed by the compiler automatically. You **explicitly must not multiply by `sizeof(T)` when doing pointer arithmetic.** –  Jul 14 '13 at 06:17
  • @slebetman No, in pointer arithmetic, `+ 3` will plus 3 element size, not 3 bytes. – Yu Hao Jul 14 '13 at 06:18
  • @sherrellbc The pointer verison is simple to read and write, I'll prefer it. – Yu Hao Jul 14 '13 at 06:19
  • @slebetman as H2CO3 pointed, you are wrong and the multiplication by `sizeof` is not needed and indeed is actually wrong. In *this* scenario it's always going to work but by sheer luck, since `sizeof(char)` is guaranteed to be one. For more see [here](http://www.parashift.com/c++-faq-lite/sizeof-char.html). – Nik Bougalis Jul 14 '13 at 08:25
  • 1
    @H2CO3 while all correct, 'wronger'? Really, *wronger*? Maybe I should direct you to [english.se]... – Richard J. Ross III Jul 14 '13 at 12:40
  • @RichardJ.RossIII Nah, that would be even *wronger.* (I hope you didn't honestly believe I thought "wronger" is a proper English word ;) –  Jul 14 '13 at 13:46
  • 2
    (Or maybe I should just stop distorting the language *intenshionally?* :P) –  Jul 14 '13 at 13:48
4

ptr++ is post-increment operator, so the pointer increments AFTER it dereference it (according to the standard).

Besides, the step:

*ptr = array[3];

assigns to the array[1] value 4, so you print 4 instead of 2 and increment to the 3.

Maroun
  • 94,125
  • 30
  • 188
  • 241
alivenets
  • 161
  • 1
  • 4
4
  1. *(ptr++) advances the pointer after dereferencing. If you want it to get the 2nd value in the array, use *(++ptr).

  2. You're assigning a value to the pointer's value. In effect, you are changing the pointer (pointing to the second element) to point to 4. You're not really changing the pointer location at all. So you are still printing the 2nd element, except it now has a value of 4.

  3. You advance to the 3rd element, printing 3.

zz3599
  • 647
  • 5
  • 20
3

The correct way of pointer assignment is:

ptr = &array[3];

or

ptr = (array + 3);

You are actually assigning the value of array[3] to the value pointet by ptr.

Alex
  • 9,891
  • 11
  • 53
  • 87