减去指针
我被要求描述这些代码行在做大学作业
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; }
我的意思是,2个inttypes的数组被创build和填充值,2个指针被创build并指向每个数组,然后我开始有麻烦了。
while (!*p1++ || !*p2++);
对我来说这是说0
移动*p1
的位置一个位置或者0
移动*p2
的位置一个位置,我对这个假设真的没有信心吗?
cout << (p1-t1) << endl;
所以然后我们转到cout
,现在我的意思是,我从t1
的位置减去p1
的位置,其中p1
被while定位, t1
指向数组中的第一个位置。 再次我可能是完全错误的我只是学习指针,所以请记住,如果我错了我的假设。
while循环实际上很可怕。 在现实生活中,我从来没有见过这样的代码,并且会宣布任何程序员在现实生活中都这么做。 我们需要经过这一步一步:
while (condition);
我们在这里有一个空的陈述(“;”本身是一个空的陈述)。 条件被评估,如果它是真的,那么语句被执行(它什么都不做,因为它是一个空的语句),我们又重新开始。 换句话说,条件反复评估,直到它是假的。
condition1 || condition2
这是一个“或”声明。 第一个条件被评估。 如果这是真的,那么第二个条件不被评估,结果是“真”。 如果它是假的,则评估第二个条件,结果是“真”或“假”。
while (condition1 || condition2);
这是评估第一个条件。 如果这是真的,我们从头开始。 如果它是假的,我们评估第二个条件。 如果那是真的,我们从头开始。 如果两者都是假的,我们退出循环。 请注意,第二个条件仅在第一个条件为假时才被评估。 现在我们来看看条件:
!*p1++ !*p2++
这与*(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].
t1与&t1 [0]相同。 p1-t1 ==&t1 [5] – &t1 [0] == 5. t2与&t2 [0]相同。 p2-t2 ==&t2 [3] – &t2 [0] == 3。
你对t1
, t2
, p1
和p2
评估是正确的。
while (!*p1++ || !*p2++);
我不喜欢这种编码风格,因为很容易假设程序员错误地在那里放置了分号。 为了表明一个空的身体是真正意图的,空的身体应该以某种方式加以区分(如同一个评论,放在一个单独的行,或使用大括号代替)。
只要条件true
while
进入人体。 由于这是一个逻辑或expression式,所以!*p1++
和!*p2++
在while
循环终止前必须为false
。 当*p1++
和*p2++
变为非零时,会发生这种情况。 由于逻辑或 短路 (如果第一个expression式是true
,则不计算第二个expression式),在每次迭代开始时, 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
由于每次迭代使用后增量 ,因此p1
以值&t1[5]
结束,并且p2
以值&t2[3]
。
相同arrays中的指针相减以数组元素的数量来衡量两个指针之间的距离。 在大多数expression式中使用的数组名将衰减到等于指向其第一个元素的值。 所以t1
衰减到&t1[0]
, t2
衰减到&t2[0]
。
从而:
p1 - t1 => 5 p2 - t2 => 3
这里要注意的关键是如何评估expression式(a || b)
。 首先,评估expression式a
。 如果a
返回true,则不计算b
因为具有True
的任何事物的OR
为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; }
输出:
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
!*p1++
相当于(!(*(p1++))
。这是后增值操作符。它增加指针但返回旧值(在增量之前)。
循环中的expression式被评估5次。
-
在第一次迭代中,p1递增。 由于
*p1
的当前值(递增之前)是0,所以!
0返回1
。 由于短路,其余的expression不被评估。 因此只有p1
得到增加。 -
同样的事情发生在下一个循环。
现在,我们有p1 = t1 + 2 indices
, p2 = t2
。
-
在第三次迭代中,
*p1
当前值不再是0
。 因此p1
和p2
都是递增的。 -
同样的事情发生在第四次迭代。
请注意,在前四次迭代中, p1
或p2
指向0
– 所以左侧或右侧的不是True
,因此while循环继续。
- 在第五次迭代中,p1和p2都是递增的,但是既然都不指向0值,循环就会退出。
因此, p1
递增5次, p2
递增3次。
总结 – p1 - t1
将包含1 +在t1
和t2
(2 + 2 + 1)的开始连续出现的0的数目。 在t2
(2 + 1)的开始, p2 - t2
将评估为1 +连续出现的0的数目。
第一:
while (!*p1++ || !*p2++);
这意味着当p1
的内容是0
,每次循环加1
到p1
直到变为non-zero
。 此后,当p2
的内容为0
,每次循环将p1
和p2
都加1
。 如果在任何时候p1
的内容再次变为0
逻辑重复(我知道这是混乱)。
基本上在一段while(first || second)
风格testing第二部分是只testing,如果第一部分失败。 无论testing通过还是失败,指针都会增加。
你对(p1-t1)
假设是正确的。 这个计算给你t1和p1之间的整数 (因为它们是int指针)。 因为t1
是数组的开始,所以计算实际上给了你指向p1
指向的数组的索引(偏移量)。
注1:如果p1
和t1
是char
指针,那么减去它们会给你它们之间的字符数 。 如果它们是float
指针,那么减去它们会得到浮点数等等。指针算术以它们指向的数据types为单位进行加减。
注2:严格地说t1是一个数组types。 当你在指针上下文中使用它时,它会折叠成一个指针。 例如在指针算术中,或者当你把它赋给一个指针variables。 如果让你感到困惑,不用担心,大多数情况下它只是作为指针工作,因为只要上下文隐含,编译器就会自动进行转换。
至于问题是什么,这将打印在控制台上,答案是0 0之前,你删除; while循环的结尾。
这个循环的意义是什么?
首先你使用的是OR,意思是如果p1或p2指向的任何一个值是0,块将被执行。 因此,直到p1指向第三个元素(p1-t1)将给你在t1中交叉元素的数量,而(p2-t2)将为0,因为(p1-t1)将返回true,所以第二个条件将不会被检查。 当p1指向1时,它会开始递增p2,直到它指向t2的第3个元素,结束。
这是我相信的所有这些任务。
这个关系可以帮助你更好地理解while循环中的条件:
arr[ i ] == * ( arr + i )
当做指针减法(如果指针是相同types的),结果是两个元素之间的距离(在数组元素中)。
假设p1
和p2
都是T*
types的指针。 然后,计算的值是:
( p2 - p1 ) == ( addr( p2 ) - addr( p1 ) ) / sizeof( T )