我被要求描述这些代码行正在为大学作业做些什么
int main() {
int t1[] = {0,0,1,1,1}, t2[] = {0,0,1,1,1};
int *p1 = t1, *p2 = t2;
while (!*p1++ || !*p2++);
cout << (p1-t1) << endl;
cout << (p2-t2) << endl;
}
Run Code Online (Sandbox Code Playgroud)
我的看法是,创建了2个int类型的数组并填充了值,创建了2个指针并指向每个数组,然后我开始遇到麻烦.
while (!*p1++ || !*p2++);
Run Code Online (Sandbox Code Playgroud)
对我来说这是说在0移动*p1一个地方的位置或0移动*p2一个地方的位置时,我对这个假设真的没有信心吗?
cout << (p1-t1) << endl;
Run Code Online (Sandbox Code Playgroud)
那么我们继续前进cout,现在我对此的看法是,我正在从位置减去p1位置t1,在那里p1被while定位并t1指向数组中的第一个位置.我可能完全错了,我只是在学习指针,所以如果我的假设错了,请记住这一点.
gna*_*729 46
while循环实际上非常可怕.我从来没有在现实生活中看到这样的代码,并且会宣称任何程序员在现实生活中都是疯狂的.我们需要逐步完成这个步骤:
while (condition);
Run Code Online (Sandbox Code Playgroud)
我们在这里有一个带有空语句的while语句(";"只是一个空语句).评估条件,如果它是真实的,则执行该语句(什么也不做,因为它是一个空语句),我们从头再来.换句话说,重复评估条件直到它为假.
condition1 || condition2
Run Code Online (Sandbox Code Playgroud)
这是一个"或"声明.评估第一个条件.如果为真,则不评估第二个条件,结果为"真".如果为假,则评估第二个条件,结果为"真"或"假".
while (condition1 || condition2);
Run Code Online (Sandbox Code Playgroud)
这评估了第一个条件.如果这是真的,我们从头开始.如果它是假的,我们评估第二个条件.如果这是真的,我们从头开始.如果两者都为假,我们退出循环.请注意,仅在第一个条件为假时才评估第二个条件.现在我们来看看条件:
!*p1++
!*p2++
Run Code Online (Sandbox Code Playgroud)
这与*(p1 ++)== 0和*(p2 ++)== 0相同.无论结果如何,每个条件在评估后都会增加p1或p2.如果*p1或*p2为零,则每个条件为真,否则为false.现在我们检查每次迭代会发生什么:
p1 = &t1 [0], p2 = &t2 [0]
*p1++ == 0 is true, *p2++ == 0 is never evaluated, p1 = &t1 [1], p2 = &t2 [0].
*p1++ == 0 is true, *p2++ == 0 is never evaluated, p1 = &t1 [2], p2 = &t2 [0].
*p1++ == 0 is false, *p2++ == 0 is true, p1 = &t1 [3], p2 = &t2 [1].
*p1++ == 0 is false, *p2++ == 0 is true, p1 = &t1 [4], p2 = &t2 [2].
*p1++ == 0 is false, *p2++ == 0 is false, p1 = &t1 [5], p2 = &t2 [3].
Run Code Online (Sandbox Code Playgroud)
t1与&t1 [0]相同.p1-t1 ==&t1 [5] - &t1 [0] == 5.t2与&t2 [0]相同.p2 - t2 ==&t2 [3] - &t2 [0] == 3.
jxh*_*jxh 14
你在你的评价是正确的t1,t2,p1,和p2.
while (!*p1++ || !*p2++);
Run Code Online (Sandbox Code Playgroud)
我不喜欢这种编码风格,因为很容易假设程序员错误地放置了分号.为了表明空体是真正的意图,应该以某种方式区分空体(例如注释,放在单独的线上,或者使用花括号).
的while,只要该条件是进入体内true.由于这是一个逻辑或表达,二者!*p1++和!*p2++必须false在之前while循环终止.当两者都变为非零时*p1++,*p2++就会发生这种情况.因为逻辑或 短路(如果第一个是第一个表达式,则不评估第二个表达式true),在每次迭代开始时进行以下操作p1并p2采用以下内容:
iter p1 *p1 p2 *p2 condition
---- -- --- -- --- ---------
0 &t1[0] 0 &t2[0] 0 !*p1++ is true, !*p2++ not evaluated
1 &t1[1] 0 &t2[0] 0 !*p1++ is true, !*p2++ not evaluated
2 &t1[2] 1 &t2[0] 0 !*p1++ is false, !*p2++ is true
3 &t1[3] 1 &t2[1] 0 !*p1++ is false, !*p2++ is true
4 &t1[4] 1 &t2[2] 1 !*p1++ is false, !*p2++ is false
Run Code Online (Sandbox Code Playgroud)
由于每次迭代都使用后递增,因此p1以值结束&t1[5],并p2以值结束&t2[3].
同一阵列内的指针减法根据数组元素的数量来测量两个指针之间的距离.大多数表达式中使用的数组名称将衰减为等于指向其第一个元素的指针的值.所以t1衰败&t1[0],t2衰败&t2[0].
从而:
p1 - t1 => 5
p2 - t2 => 3
Run Code Online (Sandbox Code Playgroud)
Ank*_*ain 13
这里要注意的关键是如何(a || b)评估表达式.首先,a评估表达式.如果a返回true,b则不会因为OR任何东西而True被评估True.这称为短路.
它有助于以下列方式扩充代码 -
int main(void){
int t1[] = {0,0,1,1,1}, t2[] = {0,0,1,1,1};
int *p1 = t1, *p2 = t2;
cout << *p1 << " " << *p2 << endl;
cout << p1 << " " << p2 << endl;
while (!*p1++ || !*p2++) {
cout << *p1 << " " << *p2 << endl;
cout << p1 << " " << p2 << endl;
}
cout << (p1-t1) << endl;
cout << (p2-t2) << endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
输出:
0 0
0x7fff550709d0 0x7fff550709f0
0 0
0x7fff550709d4 0x7fff550709f0
1 0
0x7fff550709d8 0x7fff550709f0
1 0
0x7fff550709dc 0x7fff550709f4
1 1
0x7fff550709e0 0x7fff550709f8
5 // Final p1 - t1
3 // Final p2 - t2
Run Code Online (Sandbox Code Playgroud)
!*p1++相当于(!(*(p1++)).这是后增量运算符.它递增指针但返回旧值(在增量之前).
循环中的表达式被评估5次.
在第一次迭代中,p1递增.由于*p1(递增前)的当前值为0,因此!返回0 1.由于短路,不评估表达式的其余部分.因此只会p1增加.
同样的事情发生在下一个循环中.
现在,我们有p1 = t1 + 2 indices,和p2 = t2.
在第三次迭代中,*p1不再是当前值0.因此,两个p1和p2递增.
同样的事情发生在第四次迭代中.
请注意,在前四次迭代中,要么指向p1或者p2指向a 0- 所以not左侧或右侧都是True,因此while循环继续.
因此p1增加5次,并且p2增加3次.
总结 - p1 - t1将包含1 +在开头t1和t2(2 + 2 + 1)连续出现的0的数量.p2 - t2将评估在t2(2 + 1)的开头连续出现的1 + 0的数量.
第一:
while (!*p1++ || !*p2++);
Run Code Online (Sandbox Code Playgroud)
这意味着虽然内容 p1是0保持循环每次添加1,p1直到它成为non-zero.之后,在内容p2就是0不断循环添加1到两个p1并p2各一次.如果在任何时候的内容 p1成为0再次逻辑重复(我知道这是令人困惑).
基本上在while(first || second)样式测试中,第二部分仅在第一部分失败时进行测试.无论测试通过还是失败,指针都会递增.
你的假设(p1-t1)是正确的.该计算为您提供t1和p1之间的整数数(因为它们是int指针).因为t1是数组的开头,计算实际上为您提供了p1指向数组的索引(偏移量).
注意#1:如果p1和t1是char指针然后减去它们将给出它们之间的字符数.如果它们是float指针,那么减去它们会给你浮点数等等......指针算法以它们指向的数据类型为单位添加和减去.
注2:严格来说t1是一种数组类型.当您在指针上下文中使用它时,它会折叠到指针.例如,在指针运算中或将其指定给指针变量时.如果这让您感到困惑,请不要担心,大多数情况下它只是作为指针工作,因为编译器会在上下文隐含时自动进行转换.