减去指针
Subtracting 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
,现在我的看法是,我从t1
的位置中减去p1
的位置,其中p1
的位置是 while 和 t1
指向数组中的第一个位置。同样,我可能完全错了,我只是在学习指针,所以如果我的假设是错误的,请记住这一点。
while 循环实际上非常可怕。我从未在现实生活中见过这样的代码,并且会宣布任何程序员在现实生活中这样做都是疯狂的。我们需要一步一步地完成:
while (condition);
我们这里有一个带有空语句的 while 语句(";" 本身就是一个空语句(。评估条件,如果为 true,则执行该语句(由于它是一个空语句,因此不执行任何操作(,然后我们重新开始。换句话说,反复评估条件,直到它为假。
condition1 || condition2
这是一个"或"语句。评估第一个条件。如果为 true,则不计算第二个条件,结果为"true"。如果为假,则评估第二个条件,结果相应地为"真"或"假"。
while (condition1 || condition2);
这将评估第一个条件。如果这是真的,我们重新开始。如果它是假的,我们评估第二个条件。如果这是真的,我们重新开始。如果两者都是假的,我们退出循环。请注意,仅当第一个条件为 false 时,才会计算第二个条件。现在我们看一下条件:
!*p1++
!*p2++
这与 *(p1++( == 0 和 *(p2++( == 0 相同。无论结果如何,每个条件在评估后都会增加 p1 或 p2。如果 *p1 或 *p2 为零,则每个条件为真,否则为假。现在我们检查每次迭代时会发生什么:
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
就会进入身体。由于这是一个逻辑 or 表达式,因此在 while
循环终止之前,必须false
!*p1++
和!*p2++
。当*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
由于每次迭代都使用后增量,因此p1
以值 &t1[5]
结尾,p2
以值 &t2[3]
结尾。
同一数组中的指针减法根据数组元素的数量测量两个指针之间的距离。大多数表达式中使用的数组名称将衰减为等于指向其第一个元素的指针的值。所以t1
衰变成&t1[0]
,t2
衰变成&t2[0]
。
因此:
p1 - t1 => 5
p2 - t2 => 3
这里要注意的关键是如何计算表达式(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;
}
输出:
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++))
。这是后增量运算符。它递增指针,但返回旧值(在增量之前(。
循环中的表达式计算 5 次。
在第一次迭代中,p1 递增。由于
*p1
的当前值(递增前(为 0,因此!
为 0 返回1
。由于短路,不会计算表达式的其余部分。因此,只有p1
会递增。同样的事情发生在下一个循环中。
现在,我们有p1 = t1 + 2 indices
,p2 = t2
.
在第三次迭代中,不再
0
*p1
的当前值。因此,p1
和p2
都递增。同样的事情发生在第四次迭代中。
请注意,在前四次迭代中,p1
或p2
指向0
- 因此左侧或右侧的not
True
,因此 while 循环继续。
- 在第五次迭代中,p1 和 p2 都递增,但由于两者都不指向 0 值,因此循环退出。
因此,p1
递增 5 倍,p2
递增 3 倍。
总结 - p1 - t1
将包含 1 + 在 t1
和 t2
(2 + 2 + 1( 的开头连续出现的 0 的数量。 p2 - t2
的计算结果将是 1 + 在t2
开始时连续出现的 0 数 (2 + 1(。
首先:
while (!*p1++ || !*p2++);
这意味着虽然p1
的内容0
继续循环,但每次都会向p1
添加1
,直到它变得non-zero
。此后,虽然p2
的内容0
继续循环,但每次都会向p1
和p2
添加1
。如果在任何时候p1
的内容再次变得0
逻辑重复(我知道这很混乱(。
基本上,在while(first || second)
式测试中,只有当第一部分失败时,才会测试第二部分。无论测试是通过还是失败,指针都会递增。
你对(p1-t1)
的假设是正确的。该计算为您提供了 t1 和 p1 之间的整数数(因为它们是 int 指针(。因为t1
数组的开头,所以计算实际上为您提供了p1
指向的数组的索引(偏移量(。
注意#1:如果p1
和t1
是指针char
,那么减去它们会得到它们之间的字符数。如果它们是指针float
那么减去它们会给你浮点数等......指针算术以它们所指向的数据类型为单位进行加减。
注 #2:严格来说,t1 是一种数组类型。当您在指针上下文中使用它时,它会折叠为指针。例如,在指针算术中或将其分配给指针变量时。如果这让您感到困惑,请不要担心,大多数情况下它只是用作指针,因为每当上下文暗示时,编译器都会自动进行转换。
至于问题是这会在控制台上打印什么,在你删除之前答案是 0 0 0 ; 在 while 循环结束时。
这个循环的意义是什么?
首先,您使用OR,这意味着如果p1或p2指向的值为0,则将执行块。因此,直到 p1 指向第 3 个元素 (p1-t1( 将为您提供在 t1 中交叉的元素数,而 (p2-t2( 将为 0,因为 (p1-t1( 将返回 true,因此不会检查第二个条件。当 p1 指向 1 时,它将开始递增 p2,直到它指向 t2 的第 3 个元素并且结束。
我相信这就是这项任务对你的全部。
这种关系可以帮助您更好地理解 while 循环中的条件:
arr[ i ] == * ( arr + i )
执行指针减法时(如果指针类型相同(,结果是两个元素之间的距离(在数组元素中(。
假设 p1
和 p2
都是类型 T*
的指针。然后,计算的值为:
( p2 - p1 ) == ( addr( p2 ) - addr( p1 ) ) / sizeof( T )
- 1d 智能指针不适用于语法 (*)++
- 在C#中处理C++指针而不使用unsafe的最佳方法
- 为什么使用 "this" 指针调用派生成员函数?
- 函数向量_指针有不同的原型,我可以构建一个吗
- 使用指针从C++中的数组中获取最大值
- 助记符和指向成员语法的指针
- 嵌入方指针压缩已禁用
- 数组的指针从不分段故障
- C++ 指针的内存地址和指向数组的内存地址如何相同?
- 何时在引用或唯一指针上使用移动语义
- QMetaObject invokeMethod的基于函数指针的语法
- 如何从 std::atomic 中提取指针 T<T>?
- 如何在 C# 中映射双 C 结构指针?
- C++将浮点指针值舍入为小数位数
- 为什么++(*p)更改指针值
- 调整大小后指向元素值的指针unordered_map有效?
- 正在将指针转换为范围
- 使用指向成员的指针将成员函数作为参数传递
- 将OpenCV C++重写为EmguCV C#-如何使用指针
- C++-试图将函数指针推回到另一个CPP文件中的矢量时出错