[英]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: 所以我的问题是:
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
保留了--
应用后的状态,但无法想象它是如何工作的。
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中是否允许使用负数组索引?
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 getQUIZ
, 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: 现在,问题:
- How the magic with
*--*++cpp+3
works, I mean what is modified by the -- part that allows me to getMCQ
instead ofTEST
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: 但是, cpp
和cp[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: 看到:
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
. 首先,让我们简化&*x
到x
。 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
- 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 == 0x601060
和sizeof(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.