Par*_*ras 29 c arrays pointers
我正在尝试使用C指针文献.在其中一个插图中,我遇到了以下代码.
# include <stdio.h>
int main()
{
static int a[]={0,1,2,3,4};
static int *p[]={a, a+1, a+2, a+3, a+4};
int **ptr;
ptr =p;
**ptr++;
printf("%d %d %d\n", ptr-p, *ptr-a, **ptr);
*++*ptr;
printf("%d %d %d\n", ptr-p, *ptr-a, **ptr);
++**ptr;
printf("%d %d %d\n", ptr-p, *ptr-a, **ptr);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我收到输出为.
1 1 1
1 2 2
1 2 3
Run Code Online (Sandbox Code Playgroud)
我在为这个输出辩护时遇到了问题.我在副本上制作了很多盒子,以便轻松掌握问题.我能够证明输出的合理性1 1 1,我的麻烦始于声明,*++*ptr.
因为,一元运算符从右到左执行.因此,*ptr将首先处理,然后ptr将增加值.在这个增量之后,我不确定会发生什么,书中说不知何故p也会增加指向此数组中的下一个元素.输出1 2 2只能通过增量来实现p.
我不确定这种问题是否恰好适合stackoverflow.
我尽我所能,浪费了至少10页,上面画着盒子.
任何澄清将不胜感激.
Gri*_*han 53
记住数组名称可以很容易地衰减到大多数表达式中第一个元素的指针(读取一些异常,其中数组名称不会衰减成指向第一个元素的指针?由@ H 2 CO 3回答).
为了更好地理解,请考虑我的图表:
首先,假设a存储在存储器中如下.
a
+----+----+----+----+---+
| 0 | 1 | 2 | 3 | 4 |
+----+----+----+----+---+
? ? ? ? ?
| | | | |
a a+1 a+2 a+3 a+3
Run Code Online (Sandbox Code Playgroud)
声明static int *p[] = {a, a+1, a+2, a+3, a+4};创建一个新的整数指针数组,具有以下值:
p[0] == a
p[1] == a + 1
p[2] == a + 2
p[3] == a + 3
p[4] == a + 4
Run Code Online (Sandbox Code Playgroud)
现在,p也可以假设存储在内存中,如下所示:
p
+----+----+----+----+-----+
| a |a +1| a+2| a+3| a+4 |
+----+----+----+----+-----+
? ? ? ? ?
| | | | |
p p+1 p+2 p+3 p+4
Run Code Online (Sandbox Code Playgroud)
分配后,ptr = p;事情会是这样的:
p a
+----+----+----+----+-----+ +----+----+----+----+---+
| a |a +1| a+2| a+3| a+4 | | 0 | 1 | 2 | 3 | 4 |
+----+----+----+----+-----+ +----+----+----+----+---+
? ? ? ? ? ? ? ? ? ?
| | | | | | | | | |
p p+1 p+2 p+3 p+4 a a+1 a+2 a+3 a+3
ptr
Notice: ptr points to first location in pointer array p[]
Run Code Online (Sandbox Code Playgroud)
现在我们**ptr++;在第一个printf语句之前考虑表达式.
ptr等于 p指针数组中第一个元素的地址.因此,ptr指向p[0]数组中的第一个元素(或者我们可以说ptr== &p[0]).
*ptr装置p[0]
和因为p[0]IS a,所以 *ptr是a(所以*ptr== a).
因为*ptr是a,那**ptr就是 *a== *(a + 0)== a[0]那就是0.
请注意,在表达式中**ptr++;,我们不会将其值赋给任何lhs变量.
所以效果**ptr++;就像ptr++;== ptr = ptr + 1= p + 1
这样在这个表达式之后ptr指向p[1](或者我们可以说ptr== &p[1]).
打印1:
在第一次打印之前,事情变成:
p a
+----+----+----+----+-----+ +----+----+----+----+---+
| a | a+1| a+2| a+3| a+4 | | 0 | 1 | 2 | 3 | 4 |
+----+----+----+----+-----+ +----+----+----+----+---+
? ? ? ? ? ? ? ? ? ?
| | | | | | | | | |
p p+1 p+2 p+3 p+4 a a+1 a+2 a+3 a+3
ptr
Notice: ptr is equals to p + 1 that means it points to p[1]
Run Code Online (Sandbox Code Playgroud)
现在我们可以理解First printf:
ptr - p输出1因为:
ptr = p + 1,所以ptr - p== p + 1 - p==1
*ptr - a输出1因为:
ptr = p + 1,所以*ptr == *(p + 1)== p[1]== a + 1
这意味着:*ptr - a= a + 1 - a==1
**ptr输出1因为:
*ptr== a + 1从点-2
所以**ptr== *(a + 1) == a[1]==1
在第一次printf之后我们有一个表达式 *++*ptr;.
正如我们从第2点所知,*ptr== p[1].所以,++*ptr(即++p[1])将p[1]增加到a + 2
再次明白,在表达式中*++*ptr;我们不会将其值赋给任何lhs变量,因此效果 *++*ptr;就是++*ptr;.
现在,在第二次打印之前,事情变成:
p a
+----+----+----+----+-----+ +----+----+----+----+---+
| a |a+2 | a+2| a+3| a+4 | | 0 | 1 | 2 | 3 | 4 |
+----+----+----+----+-----+ +----+----+----+----+---+
? ? ? ? ? ? ? ? ? ?
| | | | | | | | | |
p p+1 p+2 p+3 p+4 a a+1 a+2 a+3 a+3
ptr
Notice: p[1] became a + 2
Run Code Online (Sandbox Code Playgroud)
打印2:
现在我们可以理解第二个 printf:
ptr - p输出1因为:
ptr = p + 1,所以ptr - p== p + 1 - p==1
*ptr - a输出2因为:
ptr = p + 1so *ptr == *(p + 1)== p[1]== a + 2
这意味着:*ptr - a== a + 2 - a==2
**ptr输出2因为:
*ptr== a + 2从点-2
所以**ptr== *(a + 2) == a[2]==2
现在++**ptr;在第三个printf之前表达.
正如我们从第3点所知,**ptr== a[2].所以++**ptr== ++a[2]将a[2]增加到3
所以在第三次打印之前,事情变成:
p a
+----+----+----+----+-----+ +----+----+----+----+---+
| a | a+2| a+2| a+3| a+4 | | 0 | 1 | 3 | 3 | 4 |
+----+----+----+----+-----+ +----+----+----+----+---+
? ? ? ? ? ? ? ? ? ?
| | | | | | | | | |
p p+1 p+2 p+3 p+4 a a+1 a+2 a+3 a+3
ptr
Notice: a[2] = 3
Run Code Online (Sandbox Code Playgroud)
打印3:
现在我们可以理解第三个 printf:
ptr - p输出1因为:
ptr = p + 1so ptr - p== p + 1 - p==1
*ptr - a输出2因为:
ptr = p + 1so *ptr == *(p + 1)== p[1]== a + 2
这意味着:*ptr - a= a + 2 - a==2
**ptr输出3因为:
*ptr== a + 2从点-2
所以**ptr== *(a + 2) == a[2]==3
编辑注意:两个指针的区别有类型ptrdiff_t,为此,正确的转换说明符%td不是%d.
还有一点:我希望补充一点
,因为我相信这对新学员会有所帮助
假设我们有以下两行多一个4 个 printf的在你的代码之前,return 0;
**++ptr; // additional
printf("%d %d %d\n", ptr-p, *ptr-a, **ptr); // fourth printf
Run Code Online (Sandbox Code Playgroud)
可以检查这个工作代码@ Codepade,这行输出2 2 3.
因为ptr等于p + 1,增量++操作后ptr变为p + 2 (或者我们可以说ptr== &p[2]).
之后,双重参与操作** ==> **(p + 2) == *p[2]== *(a + 2)== a[2]== 3.
现在,再次因为我们在这个语句中没有任何赋值操作,所以表达式的效果**++ptr;就是这样++ptr;.
所以表达后的东西**++ptr;如下图所示:
p a
+----+----+----+----+-----+ +----+----+----+----+---+
| a | a+2| a+2| a+3| a+4 | | 0 | 1 | 3 | 3 | 4 |
+----+----+----+----+-----+ +----+----+----+----+---+
? ? ? ? ? ? ? ? ? ?
| | | | | | | | | |
p p+1 p+2 p+3 p+4 a a+1 a+2 a+3 a+3
ptr
Notice: ptr is equals to p + 2 that means it points to p[2]
Run Code Online (Sandbox Code Playgroud)
打印4:
考虑到Forth printf我添加了问题:
ptr - p输出2因为:
ptr = p + 2so ptr - p== p + 2 - p==2
*ptr - a输出2因为:
ptr = p + 2so *ptr == *(p + 2)== p[2]== a + 2
这意味着:*ptr - a= a + 2 - a==2
**ptr输出3因为:
*ptr== a + 2从点-2以上
所以**ptr== *(a + 2) == a[2]==3
如果你编译时有一些警告(clang甚至不需要任何标志),你会发现你的程序有三个无关的*操作符.简化你疯狂的表达产生:
ptr++;
++*ptr;
++**ptr;
Run Code Online (Sandbox Code Playgroud)
从那以后,你应该能够清楚地看到发生了什么:
ptr++只是递增ptr,所以它指向的第二个元素p.这个操作ptr - p永远都是1.
++*ptr增加指向的任何内容ptr.这改变了第二个元素,p指向第三个元素a而不是第二个元素(它被初始化为).这*ptr - a相当于2.同样**ptr是2来自a.
++**ptr增加任何指向的东西ptr.这增加了第三个元素a,使它成为一个3.