减去指针

时间:2014-10-14 16:53:01

标签: c++ pointers

我被要求描述这些代码行正在为大学作业做些什么

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个int类型的数组并填充了值,创建了2个指针并指向每个数组,然后我开始遇到麻烦。

while (!*p1++ || !*p2++);

对我来说这是说0移动*p1一个地方的位置或0移动*p2一个地方的位置时,我真的不自信在那个假设中?

cout << (p1-t1) << endl;

然后我们转到cout,现在我的看法是,我从p1的位置减去t1的位置,其中p1被while和t1点定位到数组中的第一个位置。 我可能完全错了,我只是在学习指针,所以如果我的假设错了,请记住这一点。

6 个答案:

答案 0 :(得分:46)

while循环实际上非常可怕。我在现实生活中从来没有见过这样的代码,并且会宣称任何程序员在现实生活中都是疯狂的。我们需要逐步完成这个步骤:

while (condition);

我们这里有一个带有空语句的while语句(&#34 ;;&#34;单独是一个空语句)。评估条件,如果是,则执行语句(由于它是一个空语句,它什么都不做),我们重新开始。换句话说,重复评估条件直到它为假。

condition1 || condition2

这是&#34;或&#34;声明。评估第一个条件。如果是,则第二个条件评估,结果为&#34; true&#34;。如果为假,则评估第二个条件,结果为&#34; true&#34;或&#34;假&#34;因此。

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与&amp; t1 [0]相同。 p1-t1 ==&amp; t1 [5] - &amp; t1 [0] == 5。 t2与&amp; t2 [0]相同。 p2 - t2 ==&amp; t2 [3] - &amp; t2 [0] == 3.

答案 1 :(得分:14)

您对t1t2p1p2的评估是正确的。

while (!*p1++ || !*p2++);

我不喜欢这种编码风格,因为很容易假设程序员错误地在那里放置了分号。为了表明空体是真正的意图,应该以某种方式区分空体(例如注释,放在单独的线上,或者使用花括号)。

只要条件为whiletrue就会进入身体。由于这是 逻辑 - 或 表达式,!*p1++!*p2++false循环之前必须为while终止。当*p1++*p2++都变为非零时,就会发生这种情况。因为逻辑 - 或 短路 (如果第一个表达式为true,则不评估第二个表达式), p1p2在每次迭代开始时采用以下内容:

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]

同一数组中的指针减法根据数组元素的数量来衡量两个指针之间的距离。大多数表达式中使用的数组名称将衰减为等于指向其第一个元素的指针的值。因此t1衰减到&t1[0]t2衰退到&t2[0]

因此:

p1 - t1 => 5
p2 - t2 => 3

答案 2 :(得分:13)

这里要注意的关键是如何评估表达式(a || b)。首先,评估表达式a。如果a返回true,则b未评估OR,因为True Trueint 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++))相当于*p1。这是后增量运算符。它递增指针但返回旧值(在增量之前)。

循环中的表达式被评估5次。

  1. 在第一次迭代中,p1递增。由于!的当前值(在递增之前)为0,因此1为0将返回p1。由于短路,不评估表达式的其余部分。因此只有p1 = t1 + 2 indices会增加。

  2. 在下一个循环中也会发生同样的事情。

  3. 现在,我们有p2 = t2*p1

    1. 在第三次迭代中,0的当前值不再是p1。因此,p2p1都会增加。

    2. 同样的事情发生在第四次迭代中。

    3. 请注意,在前四次迭代中,p20指向not - 因此左侧或右侧的True为{ {1}}因此while循环继续。

      1. 在第五次迭代中,p1和p2都递增,但由于两者都没有指向0值,所以循环退出。
      2. 因此p1增加5倍,p2增加3倍。

        汇总 - p1 - t1将包含1 +在t1t2(2 + 2 + 1)开头连续出现的0的数量。 p2 - t2将在t2(2 + 1)的开头评估为1 + 0的数字。

答案 3 :(得分:6)

首先:

while (!*p1++ || !*p2++);

这意味着,当 p1的内容为0时,每次都会循环向1添加p1直到它成为non-zero。此后,p2的内容0继续循环,每次都向1p1添加p2。如果 p1的内容再次变为0,则逻辑会重复(我知道这会令人困惑)。

基本上在while(first || second)样式测试中,如果第一部分失败,则第二部分进行测试。无论测试通过还是失败,指针都会递增。

您对(p1-t1)的假设是正确的。该计算为您提供t1和p1之间的 整数 (因为它们是int指针)。因为t1是数组的开头,所以计算实际上为您提供了p1指向的数组的索引(偏移量)。

注意#1:如果p1t1char指针,那么减去它们会为您提供个字符数它们之间。如果它们是float指针,那么减去它们会给你浮点数等等......指针算术以它们所指向的数据类型为单位进行加减和减法。

注意#2:严格来说,t1是一种数组类型。在指针上下文中使用它时, 折叠为指针。例如,在指针运算中或将其指定给指针变量时。如果这让您感到困惑,请不要担心,大多数情况下它只是作为指针工作,因为编译器会在上下文隐含的情况下自动进行转换。

答案 4 :(得分:2)

这种关系可以帮助您更好地理解while循环中的条件:

arr[ i ] == * ( arr + i )

当执行指针减法(如果指针属于同一类型)时,结果是两个元素之间的距离(在数组元素中)。

假设p1p2都是T*类型的指针。然后,计算出的值是:

( p2 - p1 ) == ( addr( p2 ) - addr( p1 ) ) / sizeof( T )

答案 5 :(得分:2)

至于问题是在控制台上打印的是什么,在你删除之前,答​​案是0 0;在while循环结束时。

这个循环的重要性是什么?

首先使用OR表示如果p1或p2指向的任何一个值为0,则执行。因此,直到p1指向第3个元素(p1-t1)将给出在t1中交叉的元素数,而(p2-t2)将为0,因为(p1-t1)将返回true,因此不会检查第二个条件。当p1指向1时,它将开始递增p2,直到它指向t2的第3个元素并且结束。

这就是我相信的所有这项任务。