简体   繁体   English

理解C指针,数组和负索引

[英]Understanding C pointers, arrays and negative indices

I am trying to learn pointers in C, and taking a quiz for this purpose. 我正在尝试学习C中的指针,并为此目的进行测验。 Here is the question: 这是一个问题:

#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;
}

The result of the line: 该行的结果:

 printf("%s ", *cpp[-2]+3);

confuses me, but let me explain step by step, how I understand that. 困惑我,但让我一步一步解释,我是如何理解的。

  • char *c[] - is array of pointers to char . char *c[] - 是char的指针数组。
  • char **cp[] - is array of pointers that points to pointer to char (I consider this as a wrapper for *c[] in reverse order). char **cp[] - 是指向char的指针数组(我认为这是反向顺序的*c[]的包装器)。
  • char ***cpp - is a pointer to pointer that points to pointer to char (I consider this a wrapper for **cp[] to perform on place modifications). char ***cpp - 是指向指向char的指针的指针(我认为这是**cp[]的包装器,用于执行位置修改)。

**++cpp - since cpp points to cp , then ++cpp will point to cp+1 which is c+2 , so double dereference will print TEST . **++cpp - 因为cpp指向cp ,那么++cpp将指向cp+1 ,即c+2 ,因此双重取消引用将打印TEST

*--*++cpp+3 - since now cpp points to cp+1 , then ++cpp will point to cp+2 which is c+1 , and the next operation -- will give us pointer to c , so the last dereference will print sQuiz . *--*++cpp+3 - 因为现在cpp指向cp+1 ,然后++cpp将指向cp+2 ,即c+1 ,而下一个操作--将给我们指向c指针,所以最后一个解引用将打印sQuiz

Here comes confusion: 这里出现了混乱:

cpp[-2] - since now cpp points to cp+2 , which I can confirm with cpp[-2] - 因为现在cpp指向cp+2 ,我可以确认

printf("%p\n", cpp); // 0x601090   
printf("%p\n", cp+2); // 0x601090

here I print addresses of pointers in c 在这里我打印c的指针地址

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

so when I dereference like this *(cpp[0]) or **cpp I expectedly get the value MCQ of c+1 所以当我像这样取消引用*(cpp[0])**cpp我希望得到c+1 MCQ

printf("%p\n", &*(cpp[0])); // 0x601068

but when I say *(cpp[-2]) I get QUIZ , but I would rather expect to get some garbage value. 但是当我说*(cpp[-2])我得到了QUIZ ,但我宁愿期望得到一些垃圾值。

So my questions are: 所以我的问题是:

  1. How the magic with *--*++cpp+3 works, I mean what is modified by the -- part that allows me to get MCQ instead of TEST when I dereference like this **cpp , I assume that this pointer *++cpp+3 preserves the state after the -- is applied, but cannot imagine yet how it works. 如何神奇与*--*++cpp+3的作品,我的意思是通过修改后的--部分,让我得到MCQ ,而不是TEST时提领我喜欢这个**cpp ,我认为这个指针*++cpp+3保留了--应用后的状态,但无法想象它是如何工作的。

  2. Why the following works the way it works (the cpp[-2] part): 为什么以下工作方式( cpp[-2]部分):

     printf("%p\\n", &*cpp[1]); // 0x601060 -> c printf("%p\\n", &*(cpp[0])); // 0x601068 -> c+1 printf("%p\\n", &*(cpp[-1])); // 0x601070 -> c+2 printf("%p", &*(cpp[-2])); // 0x601078 -> c+3 

It seems that it has reverse order, I can accept &*(cpp[0]) pointing to c+1 , but I would expect &*cpp[1] to point to c+2 , and &*(cpp[-1]) to c . 似乎它有逆序,我可以接受&*(cpp[0])指向c+1 ,但我希望&*cpp[1]指向c+2 ,并且&*(cpp[-1])c Which I found in this question: Are negative array indexes allowed in C? 我在这个问题中找到了: C中是否允许使用负数组索引?

  1. I obviously confuse many things, and may call something a pointer that in reality is not one, I would like to grasp the concept of pointer, so will be glad if someone show me where I am wrong. 我显然很混淆很多事情,并且可能会把一些指针称为实际上不是一个指针,我想掌握指针的概念,所以如果有人告诉我我错在哪里会很高兴。

Let me clarify first the negative index confusion, since we will use it later to answer the other questions: 让我首先澄清消极指数的混淆,因为我们稍后会用它来回答其他问题:

when I say *(cpp[-2]) I get QUIZ , but I would rather expect to get some garbage value. 当我说*(cpp[-2])我得到QUIZ ,但我宁愿期望得到一些垃圾值。

Negative values are fine. 负值很好。 Note the following : 请注意以下事项

By definition, the subscript operator E1[E2] is exactly identical to *((E1)+(E2)) . 根据定义,下标运算符E1[E2]*((E1)+(E2))完全相同。

Knowing that, since cpp == cp+2 , then: 知道了,因为cpp == cp+2 ,那么:

cpp[-2] == *(cpp-2) == *(cp+2-2) == *cp == c+3

And therefore: 因此:

*cpp[-2]+3 == *(c+3)+3 == c[3]+3

Which means the address of "QUIZ" plus 3 positions of a char pointer, so you are passing to printf the address of the character Z in "QUIZ" , which means it will start printing the string from there. 这意味着"QUIZ"的地址加上char指针的3个位置,所以你要在"QUIZ"中传递printf字符Z的地址,这意味着它将从那里开始打印字符串。

Actually, in case you wonder, -2[cpp] is also equivalent and valid. 实际上,如果你想知道, -2[cpp]也是等价且有效的。


Now, the questions: 现在,问题:

  1. How the magic with *--*++cpp+3 works, I mean what is modified by the -- part that allows me to get MCQ instead of TEST when I dereference like this **cpp , I assume that this pointer *++cpp+3 preserves the state after the -- is applied, but cannot imagine yet how it works. 如何神奇与*--*++cpp+3的作品,我的意思是通过修改后的-部分,让我得到MCQ ,而不是TEST时提领我喜欢这个**cpp ,我认为这个指针*++cpp+3保留了 - 应用后的状态,但无法想象它是如何工作的。

Let's break it down (recall that cpp == cp+1 here, as you correctly point out): 让我们把它分解(回想一下cpp == cp+1 ,正如你正确指出的那样):

    ++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

And that points to sQuiz as you correctly pointed out. 正如你正确指出的那样,这指向了sQuiz However, cpp and cp[2] were modified, so you now have: 但是, cppcp[2]被修改了,所以你现在有了:

cp[] == {c+3, c+2, c, c}
cpp  == cp+2

The fact that cp[2] changed is not used in the rest of the question, but it is important to note -- specially since you printed the values of the pointers. cp[2]改变的事实并没有在剩下的问题中使用,但重要的是要注意 - 特别是因为你打印了指针的值。 See: 看到:

  1. Why the following works the way it works (the cpp[-2] part): 为什么以下工作方式( cpp[-2]部分):

     printf("%p\\n", &*cpp[1]); // 0x601060 -> c printf("%p\\n", &*(cpp[0])); // 0x601068 -> c+1 printf("%p\\n", &*(cpp[-1])); // 0x601070 -> c+2 printf("%p", &*(cpp[-2])); // 0x601078 -> c+3 

First, let's simplify &*x into x . 首先,让我们简化&*xx Then, doing something similar as above, if cpp == cp+2 (as above), you can see that: 然后,做类似上面的事情,如果cpp == cp+2 (如上所述),你可以看到:

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. I obviously confuse many things, and may call something a pointer that in reality is not one, I would like to grasp the concept of pointer, so will be glad if someone show me where I am wrong. 我显然很混淆很多事情,并且可能会把一些指针称为实际上不是一个指针,我想掌握指针的概念,所以如果有人告诉我我错在哪里会很高兴。

You actually got it quite well! 你真的搞定了! :-) :-)

Basically, a pointer is an integer that represents a memory address. 基本上,指针是表示存储器地址的整数。 However, when you perform arithmetic on it, it takes into account the size of the type it points to. 但是,当您对其执行算术时,它会考虑它指向的类型的大小。 That is the reason why, if c == 0x601060 and sizeof(char*) == 8 , then: 这就是为什么,如果c == 0x601060sizeof(char*) == 8 ,那么:

c+1 == 0x601060 + 1*sizeof(char*) == 0x601068 // Instead of 0x601061
c+2 == 0x601060 + 2*sizeof(char*) == 0x601070 // Instead of 0x601062

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM