首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >理解C指针、数组和负索引

理解C指针、数组和负索引
EN

Stack Overflow用户
提问于 2018-05-25 18:31:13
回答 1查看 218关注 0票数 9

我正努力学习C语言中的指针,并为此目的进行了一次测验。以下是一个问题:

代码语言:javascript
复制
#include <stdio.h>

char *c[] = {"GeksQuiz", "MCQ", "TEST", "QUIZ"};
char **cp[] = {c+3, c+2, c+1, c};
char ***cpp = cp;

int main()
{
    printf("%s ", **++cpp);
    printf("%s ", *--*++cpp+3);
    printf("%s ", *cpp[-2]+3);
    printf("%s ", cpp[-1][-1]+1);
    return 0;
}

这条线的结果:

代码语言:javascript
复制
 printf("%s ", *cpp[-2]+3);

让我困惑,但让我一步一步地解释,我是如何理解的。

  • char *c[] -是指向char的指针数组。
  • char **cp[] -是指向char指针的指针数组(我认为这是*c[]的反向包装)。
  • char ***cpp --是指向指向char的指针的指针(我认为这是**cp[]执行位置修改的包装器)。

**++cpp --由于cpp指向cp,那么++cpp将指向cp+1 (即c+2 ),因此双重取消引用将打印TEST

*--*++cpp+3 --从现在起,cpp指向cp+1++cpp将指向cp+2,即c+1,下一个操作--将给我们指向c的指针,因此最后一个取消引用将打印sQuiz

困惑来了:

cpp[-2] --从现在起,cpp指向cp+2,我可以用

代码语言:javascript
复制
printf("%p\n", cpp); // 0x601090   
printf("%p\n", cp+2); // 0x601090

在这里,我在c中打印指针的地址

代码语言:javascript
复制
printf("c - %p\n", c); // c - 0x601060
printf("c+1 - %p\n", c+1); // c+1 - 0x601068
printf("c+2 - %p\n", c+2); // c+2 - 0x601070
printf("c+3 - %p\n", c+3); // c+3 - 0x601078

因此,当我取消像这个*(cpp[0])**cpp这样的引用时,我期望得到c+1的值MCQ

代码语言:javascript
复制
printf("%p\n", &*(cpp[0])); // 0x601068

但是,当我说*(cpp[-2])时,我得到了QUIZ,但我更希望得到一些垃圾值。

所以我的问题是:

  1. *--*++cpp+3的魔力是如何工作的,我指的是--部分修改的内容,它允许我获得MCQ而不是TEST,当我像这个**cpp那样取消引用时,我假设这个指针*++cpp+3在应用--之后保持状态,但还无法想象它是如何工作的。
  2. 为什么下面的工作方式是这样的( cpp[-2]部分): (“%p\n”,&*cpp 1);// 0x601060 -> c printf("%p\n",&*(cpp));// 0x601068 -> c+1 printf("%p\n",&*(cpp-1));// 0x601070 -> c+2 printf("%p",&*(cpp-2));// 0x601078 -> c+3

它似乎有相反的顺序,我可以接受&*(cpp[0])指向c+1,但我希望&*cpp[1]指向c+2&*(cpp[-1])指向c。我在这个问题中发现了:C中是否允许负数组索引?

  1. 很明显,我混淆了很多东西,可能会称它为指针,而实际上它并不是指针,我想掌握指针的概念,所以如果有人告诉我我错了,我会很高兴的。
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-05-25 20:32:47

让我首先澄清负数指数的混淆,因为我们稍后将用它回答其他问题:

当我说*(cpp[-2])时,我得到了QUIZ,但我更希望得到一些垃圾值。

负值很好。请注意以下事项

根据定义,下标运算符E1[E2]*((E1)+(E2))完全相同。

既然知道了这一点,从cpp == cp+2开始,那么:

代码语言:javascript
复制
cpp[-2] == *(cpp-2) == *(cp+2-2) == *cp == c+3

因此:

代码语言:javascript
复制
*cpp[-2]+3 == *(c+3)+3 == c[3]+3

这意味着"QUIZ"的地址加上一个char指针的3个位置,所以您要将"QUIZ"中的字符Z的地址传递给printf,这意味着它将从那里开始打印字符串。

实际上,如果您想知道,-2[cpp]也是等价的和有效的。

现在,问题是:

  1. *--*++cpp+3的魔力是如何运作的,我的意思是--我的意思是,被修改的部分允许我得到MCQ而不是TEST,当我像这个**cpp那样取消引用时,我假设这个指针*++cpp+3在应用-之后保持状态,但是还无法想象它是如何工作的。

让我们将其分解(回想一下这里的cpp == cp+1,正如您正确指出的那样):

代码语言:javascript
复制
    ++cpp   // cpp+1 == cp+2 (and saving this new value in cpp)
   *++cpp   // *(cp+2) == cp[2]
 --*++cpp   // cp[2]-1 == c (and saving this new value in cp[2])
*--*++cpp   // *c
*--*++cpp+3 // *c+3

正如您正确指出的那样,这指向了sQuiz。但是,cppcp[2]被修改了,所以您现在有:

代码语言:javascript
复制
cp[] == {c+3, c+2, c, c}
cpp  == cp+2

在问题的其余部分中没有使用cp[2]更改这一事实,但需要注意的是--特别是因为您打印了指针的值。请参见:

  1. 为什么下面的工作方式是这样的( cpp[-2]部分): (“%p\n”,&*cpp 1);// 0x601060 -> c printf("%p\n",&*(cpp));// 0x601068 -> c+1 printf("%p\n",&*(cpp-1));// 0x601070 -> c+2 printf("%p",&*(cpp-2));// 0x601078 -> c+3

首先,让我们将&*x简化为x。然后,执行类似的操作,如果cpp == cp+2 (如上面所示),您可以看到:

代码语言:javascript
复制
cpp[ 1] == cp[3] == c
cpp[ 0] == cp[2] == c   // Note this is different to what you had
cpp[-1] == cp[1] == c+2
cpp[-2] == cp[0] == c+3

  1. 很明显,我混淆了很多东西,可能会称它为指针,而实际上它并不是指针,我想掌握指针的概念,所以如果有人告诉我我错了,我会很高兴的。

你真的做得很好!:-)

基本上,指针是表示内存地址的整数。但是,当您对它执行算术时,它会考虑到它所指向的类型的大小。这就是为什么,如果c == 0x601060sizeof(char*) == 8,那么:

代码语言:javascript
复制
c+1 == 0x601060 + 1*sizeof(char*) == 0x601068 // Instead of 0x601061
c+2 == 0x601060 + 2*sizeof(char*) == 0x601070 // Instead of 0x601062
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50535008

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档