我最近得到了这段代码作为家庭作业分析(最近我的意思是大约3周前)。我们应该逐行检查代码并确定打印语句(不编译/运行)。
我大约一半通过它,然后指针开始操纵一组int,我只是无法跟踪它了。任何人都可以帮助解释被操纵的值和原因吗?
我想这个代码和一个很好的解释对于我来说是巨大的帮助,而不是那些来自没有指针的语言的人。
以下是代码(注意,评论是我自己的,而不是教师的):
int main() {
// Pointers (* var_name) point to an address in memory. They can be
// dereferenced by using (* var_name) during assignment. The operator (&)
// gives the address in memory of a variable, which is useful for assigning
// pointers to (point) to that location in memory (a type of assignment).
int i = 50, j = 100;
int k[] = {10, 20, 30, 40, 50};
// Declare a pointer to p, and a pointer to q
int *p, *q;
// Declare a pointer to a pointer s
int **s;
// Declare a pointer to a pointer to a pointer t
int ***t;
// Since p points to an address in memory, and & gives the address in memory,
// assign p to be the same memory location as i
p = &i;
printf("%d %d\n", i, *p);
// Since q points to an address in memory, and & gives the address in memory,
// assign q to be the same memory location as j
q = &j;
printf("%d %d\n", j, *q);
// Since s points to a pointer to an address in memory, and & gives the address
// in memory, assign s to be the same memory location as p
s = &p;
printf("%d %d\n", *p, **s);
// Since t points to a pointer to a pointer to an address in memory, and & gives
// the address in memory, assign t to be the same memory location as s. Since s
// points to the same location as p, t now points to the same location as t.
t = &s;
printf("%d %d %d %d\n", *p, *q, **s, ***t);
// The pointer p now has the same reference (in memory) as the pointer q
p = q;
printf("%d %d %d %d\n", *p, *q, **s, ***t);
// Since s points to a pointer to an address in memory, and & gives the address
// in memory, assign s to be the same memory location as q. Since p and q point
// to the same location, an equivalent statement is (s = &p)
s = &q;
printf("%d %d %d %d\n", *p, *q, **s, ***t);
/*
* This is where I get seriously lost, and I really have no clue.
*/
// p now points to the first element of k, because the first element of k is
// equivalent to *k (they are both pointers)
p = k;
*p = *q;
p++;
s = &p;
**s = 500;
q = p + 2;
*q = 1000;
p = q - 1;
*p = 750;
q ++;
*q = *q * 100;
printf("%d %d %d %d %d\n", k[0], k[1], k[2], k[3], k[4]);
**s = -100;
***t = -200;
printf("%d %d %d %d %d\n", k[0], k[1], k[2], k[3], k[4]);
printf("%d %d %d %d %d %d\n", i, j, *p, *q, **s, ***t);
return 0;
}
编译并运行时,它会提供以下输出(供参考):
50 50
100 100
50 50
50 100 50 50
100 100 100 100
100 100 100 100
100 500 750 1000 5000
100 500 -200 1000 5000
50 100 -200 5000 -200 -200
所以我想知道,在大约10次操纵的巨大块中会发生什么?我无法遵循它。另外,如果我在代码中的评论是错误的,请告诉我,这只是我对它的理解。
PS - 我知道语句p = k
指定指针p
指向int[] k
的第一个元素,但我不知道关于k
......
答案 0 :(得分:5)
所以,让我们一步一步来。我只会向您展示记忆操作并让您找出正在打印的内容。每个内存位置(方框)上方是其各自的地址,内部是其内容。
请注意,变量上方的内存地址是指示性的。无法保证变量将以这种方式放置在堆栈中(很可能是他们赢了)。
int *p, *q;
在这里,您不要声明指向p
或q
",而是指向int
的2个指针,称为p
, q
。
int **s;
int ***t;
相同,指向int
的指针,指向s
,指针指向指向int
t
的指针。
所以,让我们来'''到目前为止的记忆。
i: 0x1000 j: 0x1004
+------+ +------+
| 50 | | 100 |
+------+ +------+
k: 0x1008 0x100C 0x1010 0x1014 0x1018 0x101C
+------+ +------+------+------+------+------+
|0x100C|---->| 10 | 20 | 30 | 40 | 50 |
+------+ +------+------+------+------+------+
p: 0x1020 q: 0x1024 s: 0x1028 t: 0x102C
+------+ +------+ +------+ +------+
|XXXXXX| |XXXXXX| |XXXXXX| |XXXXXX|
+------+ +------+ +------+ +------+
现在,让我们运行代码:
p = &i;
现在p
指向i
:
i: 0x1000 j: 0x1004
+------+ +------+
+-->| 50 | | 100 |
| +------+ +------+
|
| k: 0x1008 0x100C 0x1010 0x1014 0x1018 0x101C
| +------+ +------+------+------+------+------+
| |0x100C|---->| 10 | 20 | 30 | 40 | 50 |
| +------+ +------+------+------+------+------+
|
| p: 0x1020 q: 0x1024 s: 0x1028 t: 0x102C
| +------+ +------+ +------+ +------+
+---|0x1000| |XXXXXX| |XXXXXX| |XXXXXX|
+------+ +------+ +------+ +------+
下一个命令是:
q = &j;
现在q
指向j
:
i: 0x1000 j: 0x1004
+------+ +------+
+-->| 50 | | 100 |<------------------------------------+
| +------+ +------+ |
| |
| k: 0x1008 0x100C 0x1010 0x1014 0x1018 0x101C |
| +------+ +------+------+------+------+------+ |
| |0x100C|---->| 10 | 20 | 30 | 40 | 50 | |
| +------+ +------+------+------+------+------+ |
| |
| p: 0x1020 q: 0x1024 s: 0x1028 t: 0x102C |
| +------+ +------+ +------+ +------+ |
+---|0x1000| |0x1004|-+ |XXXXXX| |XXXXXX| |
+------+ +------+ | +------+ +------+ |
| |
+-----------------------------------+
接下来我们有:
s = &p;
s
是指向int
指针的指针,而p
是指向int
的指针。现在s
指向p
:
i: 0x1000 j: 0x1004
+------+ +------+
+-->| 50 | | 100 |<------------------------------------+
| +------+ +------+ |
| |
| k: 0x1008 0x100C 0x1010 0x1014 0x1018 0x101C |
| +------+ +------+------+------+------+------+ |
| |0x100C|---->| 10 | 20 | 30 | 40 | 50 | |
| +------+ +------+------+------+------+------+ |
| |
| p: 0x1020 q: 0x1024 s: 0x1028 t: 0x102C |
| +------+ +------+ +------+ +------+ |
+---|0x1000| |0x1004|-+ |0x1020| |XXXXXX| |
+------+ +------+ | +------+ +------+ |
^ | | |
| +------+----------------------------+
| |
+------------------------+
接下来:
t = &s;
t
是指向int
指针的指针,s
是指向int
的指针。现在t
指向s
:
i: 0x1000 j: 0x1004
+------+ +------+
+-->| 50 | | 100 |<------------------------------------+
| +------+ +------+ |
| |
| k: 0x1008 0x100C 0x1010 0x1014 0x1018 0x101C |
| +------+ +------+------+------+------+------+ |
| |0x100C|---->| 10 | 20 | 30 | 40 | 50 | |
| +------+ +------+------+------+------+------+ |
| |
| p: 0x1020 q: 0x1024 s: 0x1028 t: 0x102C |
| +------+ +------+ +------+ +------+ |
+---|0x1000| |0x1004|-+ |0x1020|<----|0x1028| |
+------+ +------+ | +------+ +------+ |
^ | | |
| +------+----------------------------+
| |
+------------------------+
下一步:
p = q;
我们将q
的内容分配给p
。这意味着p
不再指向i
,但它现在指向q
指向的位置,即j
:
i: 0x1000 j: 0x1004
+------+ +------+
| 50 | +->| 100 |<------------------------------------+
+------+ | +------+ |
+-------------+ |
| k: 0x1008 0x100C 0x1010 0x1014 0x1018 0x101C |
| +------+ +------+------+------+------+------+ |
| |0x100C|---->| 10 | 20 | 30 | 40 | 50 | |
| +------+ +------+------+------+------+------+ |
| |
| p: 0x1020 q: 0x1024 s: 0x1028 t: 0x102C |
| +------+ +------+ +------+ +------+ |
+---|0x1004| |0x1004|-+ |0x1020|<----|0x1028| |
+------+ +------+ | +------+ +------+ |
^ | | |
| +------+----------------------------+
| |
+------------------------+
下一步:
s = &q;
我们指定s
指向q
的地址。因此,现在s
不再指向p
,而是指向q
:
i: 0x1000 j: 0x1004
+------+ +------+
| 50 | +->| 100 |<------------------------------------+
+------+ | +------+ |
+-------------+ |
| k: 0x1008 0x100C 0x1010 0x1014 0x1018 0x101C |
| +------+ +------+------+------+------+------+ |
| |0x100C|---->| 10 | 20 | 30 | 40 | 50 | |
| +------+ +------+------+------+------+------+ |
| |
| p: 0x1020 q: 0x1024 s: 0x1028 t: 0x102C |
| +------+ +------+ +------+ +------+ |
+---|0x1004| |0x1004|-+ |0x1024|<----|0x1028| |
+------+ +------+ | +------+ +------+ |
^ | | |
| +------+----------------------------+
| |
+-----------+
下一步:
p = k;
我们将k
的内容分配给p
。所以现在p
指向k
指向的位置,这是数组的第一个元素:
i: 0x1000 j: 0x1004
+------+ +------+
| 50 | | 100 |<------------------------------------+
+------+ +------+ |
+-------------+ |
| k: 0x1008 | 0x100C 0x1010 0x1014 0x1018 0x101C |
| +------+ +->+------+------+------+------+------+ |
| |0x100C|---->| 10 | 20 | 30 | 40 | 50 | |
| +------+ +------+------+------+------+------+ |
| |
| p: 0x1020 q: 0x1024 s: 0x1028 t: 0x102C |
| +------+ +------+ +------+ +------+ |
+---|0x100C| |0x1004|-+ |0x1024|<----|0x1028| |
+------+ +------+ | +------+ +------+ |
^ | | |
| +------+----------------------------+
| |
+-----------+
下一步:
*p = *q;
此命令说:&#34;获取q
指向的位置的内容,并将其分配到p
指向的位置&#34;。 q
指向j
,等于100,p
指向数组的第一个元素:
i: 0x1000 j: 0x1004
+------+ +------+
| 50 | | 100 |<------------------------------------+
+------+ +------+ |
+-------------+ |
| k: 0x1008 | 0x100C 0x1010 0x1014 0x1018 0x101C |
| +------+ +->+------+------+------+------+------+ |
| |0x100C|---->| 100 | 20 | 30 | 40 | 50 | |
| +------+ +------+------+------+------+------+ |
| |
| p: 0x1020 q: 0x1024 s: 0x1028 t: 0x102C |
| +------+ +------+ +------+ +------+ |
+---|0x100C| |0x1004|-+ |0x1024|<----|0x1028| |
+------+ +------+ | +------+ +------+ |
^ | | |
| +------+----------------------------+
| |
+-----------+
下一步:
p++;
这是&#34;棘手&#34;命令(虽然当你意识到正在发生的事情时并不那么棘手)。在正常情况下,这会将p
变量增加1.但因为p
是一个指针,它将增加它(应该)所指向的变量类型的大小,以便p
指向下一个内存位置。在这种情况下,sizeof(int)
即{4}(这不一定是真的)。所以现在p
指向数组的下一个单元格:
i: 0x1000 j: 0x1004
+------+ +------+
| 50 | | 100 |<------------------------------------+
+------+ +------+ |
+-------------+ |
| k: 0x1008 | 0x100C 0x1010 0x1014 0x1018 0x101C |
| +------+ | +------+------+------+------+------+ |
| |0x100C|--+->| 100 | 20 | 30 | 40 | 50 | |
| +------+ | +------+------+------+------+------+ |
| +-------------^ |
| p: 0x1020 q: 0x1024 s: 0x1028 t: 0x102C |
| +------+ +------+ +------+ +------+ |
+---|0x1010| |0x1004|-+ |0x1024|<----|0x1028| |
+------+ +------+ | +------+ +------+ |
^ | | |
| +------+----------------------------+
| |
+-----------+
下一步:
s = &p
s
指向p
的位置:
i: 0x1000 j: 0x1004
+------+ +------+
| 50 | | 100 |<------------------------------------+
+------+ +------+ |
+-------------+ |
| k: 0x1008 | 0x100C 0x1010 0x1014 0x1018 0x101C |
| +------+ | +------+------+------+------+------+ |
| |0x100C|--+->| 100 | 20 | 30 | 40 | 50 | |
| +------+ | +------+------+------+------+------+ |
| +-------------^ |
| p: 0x1020 q: 0x1024 s: 0x1028 t: 0x102C |
| +------+ +------+ +------+ +------+ |
+---|0x1010| |0x1004|-+ |0x1020|<----|0x1028| |
+------+ +------+ | +------+ +------+ |
^ | | |
| +------+----------------------------+
| |
+------------------------+
下一步:
**s = 500;
此命令显示:&#34;转到s
指向的位置并获取其内容,让我们将其称为*s
,然后转到{{1}的位置}指向并指定值500. *s
指向s
,p
指向第二个数组单元格:
p
下一步:
i: 0x1000 j: 0x1004
+------+ +------+
| 50 | | 100 |<------------------------------------+
+------+ +------+ |
+-------------+ |
| k: 0x1008 | 0x100C 0x1010 0x1014 0x1018 0x101C |
| +------+ | +------+------+------+------+------+ |
| |0x100C|--+->| 100 | 500 | 30 | 40 | 50 | |
| +------+ | +------+------+------+------+------+ |
| +-------------^ |
| p: 0x1020 q: 0x1024 s: 0x1028 t: 0x102C |
| +------+ +------+ +------+ +------+ |
+---|0x1010| |0x1004|-+ |0x1020|<----|0x1028| |
+------+ +------+ | +------+ +------+ |
^ | | |
| +------+----------------------------+
| |
+------------------------+
此处,如上所述,由于q = p + 2;
和q
是指针,因此此命令会将p
加q
的内容分配给p
。 2 * sizeof(int)
指向第二个数组单元格,所以现在p
指向第4个数组单元格:
q
下一步:
i: 0x1000 j: 0x1004
+------+ +------+
| 50 | | 100 | +-------------------+
+------+ +------+ | |
+-------------+ v |
| k: 0x1008 | 0x100C 0x1010 0x1014 0x1018 0x101C |
| +------+ | +------+------+------+------+------+ |
| |0x100C|--+->| 100 | 500 | 30 | 40 | 50 | |
| +------+ | +------+------+------+------+------+ |
| +-------------^ |
| p: 0x1020 q: 0x1024 s: 0x1028 t: 0x102C |
| +------+ +------+ +------+ +------+ |
+---|0x1010| |0x1018|-+ |0x1020|<----|0x1028| |
+------+ +------+ | +------+ +------+ |
^ | | |
| +------+----------------------------+
| |
+------------------------+
转到*q = 1000;
指向的位置并指定1000:
q
下一步:
i: 0x1000 j: 0x1004
+------+ +------+
| 50 | | 100 | +-------------------+
+------+ +------+ | |
+-------------+ v |
| k: 0x1008 | 0x100C 0x1010 0x1014 0x1018 0x101C |
| +------+ | +------+------+------+------+------+ |
| |0x100C|--+->| 100 | 500 | 30 | 1000 | 50 | |
| +------+ | +------+------+------+------+------+ |
| +-------------^ |
| p: 0x1020 q: 0x1024 s: 0x1028 t: 0x102C |
| +------+ +------+ +------+ +------+ |
+---|0x1010| |0x1018|-+ |0x1020|<----|0x1028| |
+------+ +------+ | +------+ +------+ |
^ | | |
| +------+----------------------------+
| |
+------------------------+
p = q - 1;
现在将指向p
指向的上一个位置,即第三个数组单元格:
p
下一步:
i: 0x1000 j: 0x1004
+------+ +------+
| 50 | | 100 | +-------------------+
+------+ +------+ | |
+-------------+ v |
| k: 0x1008 | 0x100C 0x1010 0x1014 0x1018 0x101C |
| +------+ | +------+------+------+------+------+ |
| |0x100C|--+->| 100 | 500 | 30 | 1000 | 50 | |
| +------+ | +------+------+------+------+------+ |
| +-------------------^ |
| p: 0x1020 q: 0x1024 s: 0x1028 t: 0x102C |
| +------+ +------+ +------+ +------+ |
+---|0x1014| |0x1018|-+ |0x1020|<----|0x1028| |
+------+ +------+ | +------+ +------+ |
^ | | |
| +------+----------------------------+
| |
+------------------------+
转到*p = 750;
指向的位置并指定750:
p
下一步:
i: 0x1000 j: 0x1004
+------+ +------+
| 50 | | 100 | +-------------------+
+------+ +------+ | |
+-------------+ v |
| k: 0x1008 | 0x100C 0x1010 0x1014 0x1018 0x101C |
| +------+ | +------+------+------+------+------+ |
| |0x100C|--+->| 100 | 500 | 750 | 1000 | 50 | |
| +------+ | +------+------+------+------+------+ |
| +-------------------^ |
| p: 0x1020 q: 0x1024 s: 0x1028 t: 0x102C |
| +------+ +------+ +------+ +------+ |
+---|0x1014| |0x1018|-+ |0x1020|<----|0x1028| |
+------+ +------+ | +------+ +------+ |
^ | | |
| +------+----------------------------+
| |
+------------------------+
与上面相同,将q++;
移动到指向它指向的下一个内存位置,即数组的第5个单元格:
q
下一步:
i: 0x1000 j: 0x1004
+------+ +------+
| 50 | | 100 | +------------+
+------+ +------+ | |
+-------------+ v |
| k: 0x1008 | 0x100C 0x1010 0x1014 0x1018 0x101C |
| +------+ | +------+------+------+------+------+ |
| |0x100C|--+->| 100 | 500 | 750 | 1000 | 50 | |
| +------+ | +------+------+------+------+------+ |
| +-------------------^ |
| p: 0x1020 q: 0x1024 s: 0x1028 t: 0x102C |
| +------+ +------+ +------+ +------+ |
+---|0x1014| |0x101C|-+ |0x1020|<----|0x1028| |
+------+ +------+ | +------+ +------+ |
^ | | |
| +------+----------------------------+
| |
+------------------------+
转到*q = *q * 100;
指向的位置并获取其内容(50)。乘以100(= 5000)。最后将此值指定给q
指向的位置:
q
下一步:
i: 0x1000 j: 0x1004
+------+ +------+
| 50 | | 100 | +------------+
+------+ +------+ | |
+-------------+ v |
| k: 0x1008 | 0x100C 0x1010 0x1014 0x1018 0x101C |
| +------+ | +------+------+------+------+------+ |
| |0x100C|--+->| 100 | 500 | 750 | 1000 | 5000 | |
| +------+ | +------+------+------+------+------+ |
| +-------------------^ |
| p: 0x1020 q: 0x1024 s: 0x1028 t: 0x102C |
| +------+ +------+ +------+ +------+ |
+---|0x1014| |0x101C|-+ |0x1020|<----|0x1028| |
+------+ +------+ | +------+ +------+ |
^ | | |
| +------+----------------------------+
| |
+------------------------+
转到**s = -100;
指向(s
)的位置并获取其内容,我们将其称为p
。现在转到*s
指向的位置(第3个数组单元格)并指定-100:
*s
下一步:
i: 0x1000 j: 0x1004
+------+ +------+
| 50 | | 100 | +------------+
+------+ +------+ | |
+-------------+ v |
| k: 0x1008 | 0x100C 0x1010 0x1014 0x1018 0x101C |
| +------+ | +------+------+------+------+------+ |
| |0x100C|--+->| 100 | 500 | -100 | 1000 | 5000 | |
| +------+ | +------+------+------+------+------+ |
| +-------------------^ |
| p: 0x1020 q: 0x1024 s: 0x1028 t: 0x102C |
| +------+ +------+ +------+ +------+ |
+---|0x1014| |0x101C|-+ |0x1020|<----|0x1028| |
+------+ +------+ | +------+ +------+ |
^ | | |
| +------+----------------------------+
| |
+------------------------+
转到***t = -200;
指向(t
)的位置并获取其内容,让我们调用此s
。现在转到*t
指向(*t
)的位置并获取其内容,让我们调用此q
。现在转到**t
指向的位置(再次指向数组的第3个单元格)并指定-200:
**t
我希望这个答案可以为你和他人澄清一些事情。在学习和玩指针时总是记忆,它会让你的生活变得更轻松。
问候。
答案 1 :(得分:1)
绘制图形以显示事物是有帮助的。我在下面添加了解决方案,但要想出来,只需在图表中绘制所有关系。
p = k; // p now points at the first element of k (value=10)
*p = *q; // replace first element in k with *q (value=100) -> array now 100, 20, 30, ..
p++; // p now points to the second element of k
s = &p; // s points at p, p points at second element of k
**s = 500; // replace second element of k with 500 -> 100, 500, 30,..
q = p + 2; // q now points at 4th element of k (value=40)
*q = 1000; // set value to 1000 -> 100, 500, 30, 1000, 50
p = q - 1; // p now points to 3rd element
*p = 750; // set to 750 -> 100, 500, 750, 1000, 50
q++; // increase q, now points at 5th element
*q = *q * 100; // multiply value of 5th element by 100 -> 100, 500, 750, 1000, 5000
**s = -100; // s points to p, which points to 3rd element -> 100, 500, -100, 1000, 5000
***t = -200; // t points to s, so replace same value -> 100, 500, -200, 1000, 5000
答案 2 :(得分:0)
int main() {
int i = 50, j = 100;
int k[] = {10, 20, 30, 40, 50};
int *p, *q;
int **s;
int ***t;
p = &i;
printf("%d %d\n", i, *p); //50 50
q = &j;
printf("%d %d\n", j, *q); //100 100
s = &p;
printf("%d %d\n", *p, **s); // 50 50
t = &s;
printf("%d %d %d %d\n", *p, *q, **s, ***t);
p = q;
printf("%d %d %d %d\n", *p, *q, **s, ***t);
s = &q;
printf("%d %d %d %d\n", *p, *q, **s, ***t);
// k is a pointer to a memory where the array is stored
// in this case a memory with values [10,20,30,40,50]
// p will also point to this memory address
p = k;
// *q is j , p is pointing to the array => *p will be the first element of the array
// *p = *q => firts element of array will be j
// the new array will be [100,20,30,40,50]
*p = *q;
//in case of pointers, the ++ oprtator will act like this : p = p + sizeof(*p) wich means next int at that memory location, in our case, next element in array
//if we have p+2 , it will be translated as p + 2*sizeof(*p) which means the 3rd element of the array (k[2])
p++;
//s is pointer to p, p is pointer to 2nd element of array (k[1])
s = &p;
// **s = *p = k[1], our array will be [100,500,30,40,50]
**s = 500;
//now, we move p, 2 elements forwards, that means p = &k[3]
//q will point to k[3]
q = p + 2;
//k[3] will be 1000=> [100,500,30,1000,50]
*q = 1000;
//p will be &k[3] -1 => &k[2]
p = q - 1;
// k[2] = 750 => [100,500,750,1000,50]
*p = 750;
// q is &k[3], q++ will be next element , &k[4]
q ++;
// *(&k[4]) = *(&k[4]) * 100 => k[4] = k[4] * 100 => [100.500,750,1000,5000]
*q = *q * 100;
printf("%d %d %d %d %d\n", k[0], k[1], k[2], k[3], k[4]);
//s is &p (from line 33), p is k[2] => **s => *(*(&p)) =>*(*(&(&k[2])) => k[2]
// k[2] = -100
**s = -100;
//t is &s => *(*(*(*(&s)))) => *(*(*(&(&(&k[2]))))) => k[2]
// k[2] = -200
***t = -200;
printf("%d %d %d %d %d\n", k[0], k[1], k[2], k[3], k[4]);
//i is 50
//j is 100
//*p = *(&k[2]) = k[2] = -200
//*q = *(&k[4]) = k[4] = 5000
//**s = *(*(&p)) = **&&k[2] = -200
//***t = ***&s = **s = -200
printf("%d %d %d %d %d %d\n", i, j, *p, *q, **s, ***t);
return 0;
}