C语言指针和不同的结果?

14
我无法理解这个问题。也许是因为现在已经两点了。无论如何,在这里我束手无策。
#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;
}

结果是:

1
2
4
3
  1. 我有一个指针,它被赋值为array

  2. 然后我打印出了我认为是第一个索引('2'),但实际上得到了1。 -- 因此,我认为*(ptr++)实际上在增加指针之前进行了解引用。

  3. 然后,我重新分配了ptr的第4个索引('4'),并重复步骤2。现在这个工作正常了, 我发现C语言不会在解引用之前计算括号。

  4. 然后我打印新增的ptr以显示('5')...但我得到了3

为什么步骤1和2与步骤3和4相同,但结果却不同?


10
*ptr = array[3];并没有“重新分配指针”的意思。然而,ptr = &array[3];会实现这一点。我建议您休息一下 ;) - Oliver Charlesworth
2
然后我将 ptr 重新分配给第四个索引('4'),并重复步骤2。应该是 ptr =&array [3] - johnchen902
天啊,没想到。我忘记了&符号。 - sherrellbc
感谢您的帖子。我因此而疯狂了。好久没用C语言编程了,似乎已经忘记了。在其他语言(如Java)中不需要处理这种材料,你会变得相当不习惯。 - sherrellbc
4
请注意,以后请勿发布代码和输出的截图。请直接将文本粘贴到问题中,并使用“{}”工具栏按钮(或按下Ctrl-K)进行格式化。 - Marcelo Cantos
1
@sherrellbc 我进行了编辑,将代码作为文本包含在帖子中,这样大家就可以轻松地复制粘贴并自己尝试了。希望你不介意 :) - Nobilis
5个回答

19

让我们逐步浏览代码:

步骤 0:

char* ptr = array;

Point the char pointer to the start of array (namely position 0). 将char指针指向数组的开头(即位置0)。 步骤1:
printf("%c\n", *(ptr++));

在位置0解引用指针,打印存储在该位置的值(1),然后将指针增加到位置1。 步骤2:
printf("%c\n", *ptr);

Dereference是指解引用指针,将指针所指向的内存地址中的值取出来。在这里,需要解引用位置1处的指针,并打印出其中存储的值(2)。 步骤3:
*ptr = arr[3];

Dereference是指对指针进行解引用操作,此处需要解引用位置为1的指针,并将其指向的值更新为数组中位置为3的值。该值为4。
步骤4:
printf("%c\n\n", *(ptr++));

解引用指针位置1,打印我们刚刚更新的值(4),然后将指针递增到位置2。 步骤5:
printf("%c\n", *ptr);

解引用指针位置2并打印该位置的值(3)。
也许你实际想要的是 ptr = &arr[3];,这将把指针分配给一个新的位置(即arr[3]的地址)。
请注意,上面代码中括号周围的ptr实际上是多余的,因为运算符优先级
对于*(ptr++)的情况,后缀递增比间接运算符具有更高的优先级,因此在我们对指针进行解引用之前将应用后缀递增。 *(++ptr)周围的括号也是不必要的。即使前缀递增和间接运算符具有相同的优先级,它们也是从右到左进行评估的。因此,在对指针进行解引用之前,指针将被递增。

1
这正是我想要做的。我忘记了这个符号。尽管我认为*(ptr++)在第一次实例中会增加ptr到下一个位置,然后进行解引用,因此显示2。但是,我想如果我尝试并使用类似情况下的(i++)之类的东西,那么实际上没有什么区别。括号不会使i首先递增其使用。 - sherrellbc
实际上,如果考虑到运算符优先级,在这个例子*(ptr++)中,你甚至可以省略括号,因为后置递增的优先级比解引用运算符更高。在*++ptr中,即使*和后置递增具有相同的优先级,也可以省略它们,因为它们按从右到左的顺序进行评估,所以++会在*之前被评估。然而,如果你想要更新指向的值,那就是另外一回事了 :) - Nobilis
抱歉,对上面的内容稍作更正,我的意思是“即使*pre具有相同的优先级”。 - Nobilis
根据运算符优先级的规定,后缀 ++ 运算符比解引用运算符 * 的优先级更高。因此,在表达式 *(ptr++) 中,括号是多余的,该表达式等同于 *ptr++。这个表达式先打印字符串的第一个元素 '1',然后再递增指针 ptr - Grijesh Chauhan
@GrijeshChauhan 我已经在评论中写了这个,你认为我也应该把它加到答案里吗? - Nobilis
显示剩余3条评论

7
请尝试使用以下方法:
ptr = array + 3;

我想使用数组索引来完成它,但是在上面的代码中忘记了&符号以及多余的*。 - sherrellbc
6
@slebetman,错误。非常错误。再错误不过了。指针算术运算会由编译器自动执行。在进行指针算术运算时,绝不能显式地乘以 sizeof(T)请注意不要改变原文的意思。 - user529758
@slebetman 不,指针算术中,“+3”将加上3个元素的大小,而不是3个字节。 - Yu Hao
1
@H2CO3 虽然都是正确的,但是'wronger'这个单词用得有些奇怪了吧?也许我应该把你引导到[english.se]... - Richard J. Ross III
2
(或许我应该停止故意扭曲语言了?:P) - user529758
显示剩余4条评论

4

ptr++后增量 运算符,所以指针在解引用之后再递增(根据标准)。

此外,步骤为:

*ptr = array[3];

将值4分配给array[1],因此您打印出4而不是2,并增加到3。


请尽快查看帮助中心,并注意编辑内容。 - Grijesh Chauhan

4
  1. *(ptr++) 取得指针所指的值后再将指针向后移动一位。如果您想要取得数组的第二个值,请使用*(++ptr)

  2. 您正在给指针的值赋值。实际上,您是在改变指针(指向第二个元素)使其指向4。您并没有真正改变指针的位置。因此,您仍然打印出了第二个元素,只是它现在的值为4。

  3. 您前进到第三个元素,并打印出3。


3
指针赋值的正确方式是:
ptr = &array[3];

或者
ptr = (array + 3);

你实际上是将array[3]的值赋给了ptr指向的值。

是的,我忘记了加上&符号。 - sherrellbc

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