Difference between *ptr += 1 and *ptr++ in C
Asked Answered
P

5

123

I just started to study C, and when doing one example about passing pointer to pointer as a function's parameter, I found a problem.

This is my sample code :

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

int* allocateIntArray(int* ptr, int size){
    if (ptr != NULL){
        for (int i = 0; i < size; i++){
            ptr[i] = i;
        }
    }
    return ptr;
}

void increasePointer(int** ptr){
    if (ptr != NULL){
        *ptr += 1; /* <----------------------------- This is line 16 */
    }
}

int main()
{
    int* p1 = (int*)malloc(sizeof(int)* 10);
    allocateIntArray(p1, 10);

    for (int i = 0; i < 10; i++){
        printf("%d\n", p1[i]);
    }

    increasePointer(&p1);
    printf("%d\n", *p1);
    p1--;
    free(p1);
    fgets(string, sizeof(string), stdin);
    return 0;
}

The problem occurs in line 16, when I modify *ptr+=1 to *ptr++. The expected result should be the whole array and number 1 but when I use *ptr++ the result is 0.

Is there any diffirence between +=1 and ++? I thought that both of them are the same.

Propagable answered 10/2, 2016 at 3:39 Comment(8)
Note that the given code won't compile as you haven't declared string.Sain
Other notes: 1) allocateIntArray is a bad name as it seems you malloc the array from the function, but you don't. I suggest fillIntArray instead. 2) You don't utilize the return value of allocateIntArray. I suggest you change the return type to void. 3) Shouldn't if (ptr != NULL) in function increasePointer be if (*ptr != NULL)? 4) The cast in malloc is unneccessary. See Sourav's comment above. 5) This: for (int i = 0; i < 10; i++){ printf("%d\n", p1[i]); } and printf("%d\n", *p1); p1--; needs to be enclosed in if(p1 != NULL). 6) string.h is unused.Sain
Related: ++ on a dereferenced pointer in C?Hedgepeth
p+=1 is like ++p, not like p++Augustin
this question was asked 4 years ago: Is ++ the same as += 1 for pointersSally
@Sally Almost, but not quite. The linked question doesn't involve the dereference operator, which is the crux of the OP's issue here.Nostoc
There's one common thing about the two expressions: do use paranthesis! At least for the second one... If people reading some code wonder what the precedence it, then you've done it wrong.Wet
This is why I always use parentheses for everything. Memorizing operator precedence is only useful for code golf.Romanfleuve
A
293

The difference is due to operator precedence.

The post-increment operator ++ has higher precedence than the dereference operator *. So *ptr++ is equivalent to *(ptr++). In other words, the post increment modifies the pointer, not what it points to.

The assignment operator += has lower precedence than the dereference operator *, so *ptr+=1 is equivalent to (*ptr)+=1. In other words, the assignment operator modifies the value that the pointer points to, and does not change the pointer itself.

Amazonite answered 10/2, 2016 at 3:45 Comment(1)
For beginners, a mnemonic is the similarity between *p++ and *++p. Operator precedence of the latter is clear, the one of the former follows.Iorgos
E
23

The order of precedence for the 3 operators involved in your question is the following :

post-increment ++ > dereference * > assignment +=

You can check this page for further details on the subject.

When parsing an expression, an operator which is listed on some row will be bound tighter (as if by parentheses) to its arguments than any operator that is listed on a row further below it. For example, the expression *p++ is parsed as *(p++), and not as (*p)++.

Long story short, in order to express this assignment *ptr+=1 using the post-increment operator you need to add parentheses to the dereference operator to give that operation precedence over ++ as in this (*ptr)++

Eduardo answered 11/2, 2016 at 9:59 Comment(1)
Interesringly, this is currently the only answer which contains solution... (*ptr)++Aubine
S
7

Let's apply parentheses to show the order of operations

a + b / c
a + (b/c)

Let's do it again with

*ptr   += 1
(*ptr) += 1

And again with

*ptr++
*(ptr++)
  • In *ptr += 1, we increment the value of the variable our pointer points to.
  • In *ptr++, we increment the pointer after our entire statement (line of code) is done, and return a reference to the variable our pointer points to.

The latter allows you to do things like:

for(int i = 0; i < length; i++)
{
    // Copy value from *src and store it in *dest
    *dest++ = *src++;

    // Keep in mind that the above is equivalent to
    *(dest++) = *(src++);
}

This is a common method used to copy a src array into another dest array.

Superfine answered 11/2, 2016 at 17:25 Comment(2)
"and return a reference to the variable our pointer points to." C doesn't have references.Rattlehead
@MilesRout Perhaps calling it an lvalue might be more accurate? But I'm not sure how to put it without adding jargon.Superfine
B
4

Very good question.

In K&R "C programming language" "5.1 Pointers and Addresses", we can get an answer for this.

"The unary operators * and & bind more tightly than arithmetic operators"

*ptr += 1      //Increment what ptr points to.

"Unary operators like * and ++ associate right to left."

*ptr++        //Increment prt instead of what ptr point to.

//It works like *(ptr++).

The correct way is:

(*ptr)++      //This will work.
Bugger answered 4/3, 2016 at 3:41 Comment(1)
This is the first time I comment on Stack Overflow. I have updated the format of the code.^^ Thanks for your suggestion.Bugger
C
3

*ptr += 1 : Increment data that ptr points to. *ptr++ : Increment pointer that is point to next memory location instead of the data that pointer points to.

Curate answered 8/3, 2016 at 1:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.