如何增加指针地址和指针的值?

131
假设我们,
int *p;
int a = 100;
p = &a;

以下代码实际上会做什么,以及如何做到的?
p++;
++p;
++*p;
++(*p);
++*(p);
*p++;
(*p)++;
*(p)++;
*++p;
*(++p);

我知道,从编码的角度来看,这有点凌乱,但我想知道当我们像这样编码时会发生什么。
注意:假设地址a = 5120300 存储在指针p 中,其地址为3560200。那么,在每个语句执行后,p & a 的值将是多少?

4
为什么不在调试器中运行它? - AndersK
28
为什么不直接尝试一下呢?printf会打印一个指针并用 %p 表示。 - Brian Roach
如果你对行为感到好奇,那就动手试试吧。只需编写一个简单的C程序,涵盖所有这些用例,并查看它是否对你有意义。 - Cyrus
@AndersK。也许OP期望未定义的行为?...或者也许不是。 - Mateen Ulhaq
5个回答

258
首先,++运算符优先于*运算符,而()运算符优先于其他所有运算符。
其次,如果你不将++number操作符赋值给任何变量,它与number++操作符是相同的。区别在于number++先返回number,然后再递增number,而++number先递增number,然后再返回它。
第三,通过增加指针的值,你实际上是按照其内容的大小增加它的值,就像在数组中进行迭代一样。
所以,总结一下:
ptr++;    // Pointer moves to the next int position (as if it was an array)
++ptr;    // Pointer moves to the next int position (as if it was an array)
++*ptr;   // The value pointed at by ptr is incremented
++(*ptr); // The value pointed at by ptr is incremented
++*(ptr); // The value pointed at by ptr is incremented
*ptr++;   // Pointer moves to the next int position (as if it was an array). But returns the old content
(*ptr)++; // The value pointed at by ptr is incremented
*(ptr)++; // Pointer moves to the next int position (as if it was an array). But returns the old content
*++ptr;   // Pointer moves to the next int position, and then gets accessed, with your code, segfault
*(++ptr); // Pointer moves to the next int position, and then gets accessed, with your code, segfault

由于这里有很多案例,我可能犯了一些错误,请纠正我。
编辑:
所以我错了,优先级比我写的要复杂一些,可以在这里查看: http://en.cppreference.com/w/cpp/language/operator_precedence

15
ptr++,值不会增加,指针会增加。这些一元运算符具有相同的优先级,但是它们是从右到左进行评估的。该代码意味着“获取指针ptr所指向的内容,然后递增ptr”。这是非常常见的C代码(也确实令人困惑)。对于(ptr)++,括号不起作用。 - Lundin
非常感谢您,Lundin,我还有什么遗漏吗? - felipemaia
@Lundin 你好,上面的答案现在已经更正了吗?谢谢。 - Unheilig
5
第一句话仍然完全错误,后缀++的优先级高于与前缀++同级别的一元*运算符。除此之外,看起来还不错。 - Lundin
4
你确定它会出现分段错误吗?也许这只是未定义的行为? - jotik

18

检查了程序,结果如下:

p++;    // use it then move to next int position
++p;    // move to next int and then use it
++*p;   // increments the value by 1 then use it 
++(*p); // increments the value by 1 then use it
++*(p); // increments the value by 1 then use it
*p++;   // use the value of p then moves to next position
(*p)++; // use the value of p then increment the value
*(p)++; // use the value of p then moves to next position
*++p;   // moves to the next int location then use that value
*(++p); // moves to next location then use that value

2
@alex 使用它的意思是,例如考虑语句 'int *a = p++;'。这里指针 'p' 的第一个值将被使用,然后 'p' 将移动到下一个位置。因此,在执行上述语句后,'a' 将具有由 'p' 指向的先前位置的地址,而 'p' 将指向下一个位置。也就是说,首先像上面那样使用 'p' 的值进行赋值表达式,然后增加 'p' 的值以指向下一个位置。 - Sujith R Kumar
简而言之,我认为他使用“使用它”这个短语来代替更正式的术语“分配”。就是这样。 - Apekshik Panigrahi

7
以下是各种“只需打印”建议的实例。我发现这很有启示性。
#include "stdio.h"

int main() {
    static int x = 5;
    static int *p = &x;
    printf("(int) p   => %d\n",(int) p);
    printf("(int) p++ => %d\n",(int) p++);
    x = 5; p = &x;
    printf("(int) ++p => %d\n",(int) ++p);
    x = 5; p = &x;
    printf("++*p      => %d\n",++*p);
    x = 5; p = &x;
    printf("++(*p)    => %d\n",++(*p));
    x = 5; p = &x;
    printf("++*(p)    => %d\n",++*(p));
    x = 5; p = &x;
    printf("*p++      => %d\n",*p++);
    x = 5; p = &x;
    printf("(*p)++    => %d\n",(*p)++);
    x = 5; p = &x;
    printf("*(p)++    => %d\n",*(p)++);
    x = 5; p = &x;
    printf("*++p      => %d\n",*++p);
    x = 5; p = &x;
    printf("*(++p)    => %d\n",*(++p));
    return 0;
}

它返回

(int) p   => 256688152
(int) p++ => 256688152
(int) ++p => 256688156
++*p      => 6
++(*p)    => 6
++*(p)    => 6
*p++      => 5
(*p)++    => 5
*(p)++    => 5
*++p      => 0
*(++p)    => 0

我将指针地址转换为int类型,以便更容易地进行比较。

我使用GCC进行了编译。


1
我会将其更改为在操作后包括x和p的值。 - NetJohn

4

关于如何增加指针地址和指针的值,我认为++(*p++);是被明确定义的,并且可以实现你所要求的功能,例如:

#include <stdio.h>

int main() {
  int a = 100;
  int *p = &a;
  printf("%p\n",(void*)p);
  ++(*p++);
  printf("%p\n",(void*)p);
  printf("%d\n",a);
  return 0;
}

在序列点之前,它不会修改同一件事两次。我认为对于大多数用途来说,这不是一个很好的风格——它对我来说有点太神秘了。


实际上,括号是不必要的:++*p++ 将成功地增加值和指针(后缀 ++ 比解引用 * 绑得更紧,在前缀 ++ 之前发生)。只有在需要在增加值之前获得值时才需要括号 (*p++)++。如果你全部使用前缀,++*++p 也会正常工作,而无需括号(但是会在指针增加后增加指向的值)。 - cmaster - reinstate monica

3
        Note:
        1) Both ++ and * have same precedence(priority), so the associativity comes into picture.
        2) in this case Associativity is from **Right-Left**

        important table to remember in case of pointers and arrays: 

        operators           precedence        associativity

    1)  () , []                1               left-right
    2)  *  , identifier        2               right-left
    3)  <data type>            3               ----------

        let me give an example, this might help;

        char **str;
        str = (char **)malloc(sizeof(char*)*2); // allocate mem for 2 char*
        str[0]=(char *)malloc(sizeof(char)*10); // allocate mem for 10 char
        str[1]=(char *)malloc(sizeof(char)*10); // allocate mem for 10 char

        strcpy(str[0],"abcd");  // assigning value
        strcpy(str[1],"efgh");  // assigning value

        while(*str)
        {
            cout<<*str<<endl;   // printing the string
            *str++;             // incrementing the address(pointer)
                                // check above about the prcedence and associativity
        }
        free(str[0]);
        free(str[1]);
        free(str);

结合律是什么? - 71GA
2
在代码中,您可以看到str++,现在这里和++具有相同的优先级(俗称相同的优先级),并且str++没有使用括号分隔,例如(str++)或(*str)++,因此必须确定它应该如何评估。所以从右到左意味着(x = str++),然后(y = *x)。 - Abhishek D K

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