我正在阅读c ++代码,开发人员经常使用这种模式:
float *_array;
//...
while (expression) {
if (_array) {
// ...
_array += 1;
} else {
// ...
}
}
外部while循环将独立于_array指向的位置终止。我的问题是关于if (_array)
条件和该子句中的增量。
我首先想到它应该检查指针是否“耗尽”了数组,但似乎并非如此。我用这个简单的片段测试了它:
float *p = new float[5];
int i = 0;
for (i = 0; i < 10; i++) {
if (p) {
std::cout << "ok\n";
} else {
std::cout << "no\n";
}
p += 1;
}
这将打印10次“ok”。因此,即使指针超出定义的数组长度,if (pointer)
也会计算为true
。
但在这种背景下,if (pointer)
还有什么目的呢?
答案 0 :(得分:6)
其目的是检查指针_array
是否指向NULL
,即检查它是否是NULL
指针。
new
会引发std::bad_alloc
异常,因此无需检查NULL
。如果是malloc, calloc, realloc
或new(std::nothrow)
,如果分配失败,则返回NULL
。在这种情况下,您需要检查NULL
。
答案 1 :(得分:3)
在C和C ++中,如果指针不是NULL,则在布尔上下文中求值时返回true
,如果指针为NULL,则返回false
。
表单if (ptr) ...
是if (ptr != NULL) ...
的常用简写。
即使在特定平台中,NULL指针未由二进制零表示,此解释规则也是如此。
答案 2 :(得分:2)
空指针被隐式转换为布尔值false,非空指针转换为true。
所以你可以使用
if(_array != NULL)
或
if(_array)
§4.12布尔转换
算术,无范围枚举,指针或指针的prvalue 成员类型可以转换为bool类型的prvalue。零值, null指针值,或null成员指针值转换为 假;任何其他值都转换为true。一个类型的prvalue std :: nullptr_t可以转换为bool类型的prvalue;该 结果值是假的。
答案 3 :(得分:1)
代码存在缺陷 - 即使指针NULL
,指针也会递增。
#include <iostream>
using namespace std;
int main()
{
float *ptr = nullptr;
for(int i = 0; i < 5; ++i)
{
cout << (ptr ? "ok" : "no") << endl;
++ptr;
}
cin.get();
}
输出:
no
ok
ok
ok
ok
如果您尝试取消引用该指针,则会遇到访问冲突。将指针增量放在if(ptr)
子句中,如果它在循环之前为NULL
,它将保持NULL
。
答案 4 :(得分:1)
添加到主要答案:您的第二个代码会导致未定义的行为。
一旦循环运行6次,p
移动到数组的末尾并导致未定义的行为。指针可能只指向一个对象,或者指向一个对象,或者指向空指针。
这说明为什么“反复试验”不是学习C ++的好方法,因为很难区分定义的行为和未定义的行为之间的区别,这些行为恰好符合您的预期。
答案 5 :(得分:0)
据我了解,在C中,if
条件适用于值zero
还是non-zero
。由于NULL指针的值为零,因此if
条件失败!换句话说,此方法可以解释为对NULL指针的验证
<强>证明强>
#include <stdio.h>
int main()
{
int *p = NULL;
int a = 1;
printf("%p %d\n", p, p);
p = &a;
printf("%p %d\n", p, p);
return 0;
}
现在我们编译&amp;运行这个:
$> gcc null.c
$> ./a.out
(nil) 0
0x7fff0556ff3c 89587516
请注意,在第一个printf
中,使用%d,指针p
的值为zero
。因此,如果直接在if
条件中使用指针,它将作为true或false,可以解释为NULL指针或非NULL指针。
最佳实践
此外,我想补充说,用法来自标准的最佳做法。与潜在危险的&amp;相比,这是检查指针是否为NULL的首选方法。容易出错:
if (p == NULL) {
}
可以错误地输入(危险地):
if (p = NULL) {
}