在C语言中,*ptr += 1和*ptr++有什么区别?

123
我刚开始学习C语言,在做一个关于将指针传递给函数作为参数的例子时,我遇到了一个问题。
这是我的示例代码:
#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;
}

当我把*ptr+=1修改为*ptr++时,问题出现在第16行。预期结果应该是整个数组和数字1,但当我使用*ptr++时,结果为0。

+=1++之间有什么区别吗?我认为它们都是相同的。


2
请注意,由于您尚未声明“string”,因此给定的代码无法编译。 - Spikatrix
6
其他注释:1)"allocateIntArray" 是个不好的名字,因为看起来像你在函数中使用 malloc 分配数组内存,但实际上你没有这样做。我建议改用 "fillIntArray"。2)你没有利用 "allocateIntArray" 的返回值。我建议将其更改为 "void" 类型。3)在 increasePointer 函数中,判断应该是 if (*ptr != NULL),而不是 if (ptr != NULL)。4)在 malloc 中进行强制转换是不必要的。请参见上面 Sourav 的评论。5)需要将以下代码 for (int i = 0; i < 10; i++){ printf("%d\n", p1[i]); }printf("%d\n", *p1); p1--; 包含在 if(p1 != NULL) 中。6)"string.h" 没有被使用。 - Spikatrix
9
p+=1 相当于 ++p,而不是 p++ - Kos
5
这个问题是4年前提出的:指针中++和+=1是否相同 - ren
3
几乎对了,但并不完全正确。这个相关的问题并没有涉及到解引用操作符,而这恰恰是原帖中的核心问题所在。 - Jason C
显示剩余3条评论
5个回答

293

这个差异是由于操作符优先级引起的。

后置递增运算符++的优先级高于解引用运算符*。因此*ptr++等同于*(ptr++)。换句话说,后置递增修改了指针本身,而不是它所指向的内容。

赋值运算符+=的优先级低于解引用运算符*,因此*ptr+=1等同于(*ptr)+=1。换句话说,赋值运算符修改了指针指向的值,而不是指针本身。


4
对于初学者而言,“助记符”是指 *p++*++p 之间的相似性。后者的运算优先级很明确,前者的优先级则需要遵循一定规则。 - Walter Tross

23
您问题涉及的3个操作符的优先级如下:
后缀递增 ++ > 解引用 * > 赋值 += 您可以查看这个页面了解更多详细信息。
简而言之,为了使用后缀递增运算符表达此赋值 *ptr+=1,您需要在解引用运算符周围添加括号,以使该操作比++具有更高的优先级,即这样的语句:(*ptr)++

3
有趣的是,这目前是唯一一个包含解决方案的答案... (*ptr)++。(说明:该句话描述了某个答案是当前唯一一个包含解决方案的,后面的代码(*ptr)++不属于需要翻译的内容。) - hyde

7

让我们使用括号来显示操作顺序(operator precedence)

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

让我们再用以下方式做一次:

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

再次使用

*ptr++
*(ptr++)
  • *ptr += 1中,我们增加指针所指向的变量的值。
  • *ptr++中,我们在整个语句(代码行)完成后递增指针,并返回指针所指向的变量的引用。

后者允许您执行以下操作:

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++);
}

这是一种常用的方法,用于将src数组复制到另一个dest数组中。


并返回指针所指向变量的引用。C语言没有引用。 - Miles Rout
@MilesRout 或许称其为左值可能更准确?但我不确定如何在不添加术语的情况下表达它。 - Mateen Ulhaq

4
非常好的问题。
在K&R的《C语言编程》第5.1章“指针和地址”中,我们可以得到这个答案。
“一元运算符*和&比算术运算符具有更高的优先级”。
*ptr += 1      //Increment what ptr points to.

"像 * 和 ++ 这样的一元运算符从右到左结合。"
*ptr++        //Increment prt instead of what ptr point to.

//它的作用类似于*(ptr++)。

正确的方式是:

(*ptr)++      //This will work.

这是我第一次在Stack Overflow上发表评论。我已经更新了代码的格式。^^感谢您的建议。 - Nick.Sang

3

*ptr += 1:增加指针所指向的数据。 *ptr++:将指针指向下一个内存位置,而不是指向指针指向的数据。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接