关于C中指针递减的困惑

时间:2015-08-27 06:55:24

标签: c pointers pointer-arithmetic

考虑以下计划:(参见现场演示here

#include <stdio.h>
int main(void)
{
    char c[]={'s','h','r','e','y','a','\0'};
    char *ptr=c;
    for(int i=0;i<6;i++)
        printf("%c",ptr[i]);
    printf("\n");

    char (*s)[7];
    s=&c;
    for(int i=0;i<6;i++)
        printf("%c",(*s)[i]);
    printf("\n");

    ptr=&c[5];       // ptr points to 6th char of string
    for(int i=5;i>=0;i--)
        printf("%c",ptr[i]);
}

该计划未给出预期结果。我得到的结果是:

SHREYA

SHREYA

但如果我写下最后一个循环,就像下面一样,它可以正常工作。

for(int i=5;i>=0;i--)
     printf("%c",c[i]);

我在这里对指针的理解是错误的?为什么在最后一个for循环中写printf("%c",ptr[i]);时,我只得到最后一个char作为输出。

4 个答案:

答案 0 :(得分:6)

完成作业后

ptr=&c[5];

ptr指向数组的fifth元素,即a。现在在循环内打印ptr[i]

让我们从循环的开头开始,看看它打印的内容。

*(ptr+5),超出了数组c[]

{'s','h','r','e','y','a','\0'};
  ^   ^   ^   ^   ^   ^    ^    ^  ^  ^  ^
  0   1   2   3   4   5    6    G  G  G  G   //G -> Garbage
                      ^                  ^
                     ptr              (ptr+5)

类似地,这继续,直到i0,即最后一次迭代,即*(ptr+0)。在其上打印a

答案 1 :(得分:5)

指定ptr=&c[5];使ptr保留字符串第5个元素的地址。

如果您想要访问前面的元素,则需要否定索引来回退字符串。

ptr=&c[5];       // ptr points to 6th char of string
for(int i=4;i>=0;i--)
    printf("%c",ptr[-i]);

或者

ptr=&c[5];       // ptr points to 6th char of string
for(int i=-4;i<=0;i++)
    printf("%c",ptr[i]);

还请考虑第5个元素被移位4个位置(因为第一个位于偏移0处,从0到4计数有5个符号)。

另一个有效,因为数组c总是指向元素0的地址。

答案 2 :(得分:3)

使用ptr=&c[5];,您的指针指向'a'

第一个循环将指向UB,因为它将是'a'+5的地址,依此类推。

您需要的是:

ptr=&c[5];
for(int i=5;i>=0;i--){
    printf("%c",*ptr);
    ptr--;
}

或者

ptr=c;
for(int i=5;i>=0;i--){
    printf("%c",ptr[i]);
}

许多其他方法......

答案 3 :(得分:3)

问题在于代码的这一部分:

ptr=&c[5];       // ptr points to 6th char of string
for(int i=5;i>=0;i--)
    printf("%c",ptr[i],i);

将上述内容更改为:

ptr=&c[5];       // ptr points to 6th char of string
for(int i=5;i>=0;i--)
    printf("%c",ptr[i-5],i);

ptr[i]您可以带一个未定义的引用,因为ptr+5ptr+4等可能无法访问,并且它们不指向数组。

更好的方法是简单地指向数组的基础并打印如下:

ptr=&c[0];       // ptr points to the base address of the char array
for(int i=5;i>=0;i--)
    printf("%c",ptr[i]);