【问题标题】:increment pointer within if (pointer) condition在 if(指针)条件内递增指针
【发布时间】:2015-04-26 09:02:29
【问题描述】:

我在看c++代码,开发者经常使用这种模式:

float *_array;

//...
while (expression) {

    if (_array) {
        // ...
        _array += 1;
    } else {
        // ...
    }
}

外部 while 循环将独立于 _array 指向的位置终止。我的问题是关于 if (_array) 条件和该子句中的增量。

我首先认为它应该检查指针是否“用尽”数组,但似乎并非如此。我用这个简单的 sn-p 对其进行了测试:

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) 的目的还有什么?

【问题讨论】:

    标签: c++ c arrays pointers


    【解决方案1】:

    它的目的是检查指针_array是否指向NULL,即检查它是否是一个NULL指针。

    new 抛出std::bad_alloc 异常,因此无需检查NULL。对于malloc, calloc, reallocnew(std::nothrow),如果分配失败,则返回NULL。在这种情况下,您需要检查NULL

    【讨论】:

    • 什么时候会这样?它可以通过增量发生还是只能通过主动将其设置为NULL 来发生?
    • @basilikum;在答案中添加了一个段落。它不能通过增量发生。
    • new 并不总是抛出由于memory overcommit
    • @namezero;使用new(std::nothrow) 可以避免bad_alloc
    • @hacks 是的,我只是想补充一点,经常捕获 bad_alloc 是徒劳的。
    【解决方案2】:

    在 C 和 C++ 中,当指针在布尔上下文中求值时,如果指针不为 NULL,则返回 true;如果指针为 NULL,则返回 false

    if (ptr) ...if (ptr != NULL) ... 的常用简写形式。

    即使在特定平台中,NULL 指针不是用二进制零表示的,此解释规则也是正确的。

    【讨论】:

      【解决方案3】:

      空指针隐式转换为布尔值false,非空指针转换为true。

      所以你可以使用任何一个

      if(_array != NULL)
      

      if(_array)
      

      § 4.12 布尔转换

      算术、无范围枚举、指针或指向的指针的纯右值 成员类型可以转换为布尔类型的纯右值。一个零值, 空指针值,或空成员指针值转换为 错误的;任何其他值都将转换为 true。类型的prvalue std::nullptr_t 可以转换为 bool 类型的纯右值;这 结果值为假。

      【讨论】:

        【解决方案4】:

        添加到主要答案:您的第二个代码会导致未定义的行为。

        一旦循环运行 6 次,p 就会移动到数组的末尾并导致未定义的行为。指针可能只指向一个对象,或者指向一个对象,或者是空指针。

        这说明了为什么“反复试验”不是学习 C++ 的好方法,因为很难区分已定义的行为和这次碰巧符合您预期的未定义行为。

        【讨论】:

          【解决方案5】:

          代码有缺陷——即使是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

          【讨论】:

          • 感谢您的补充。这个 sn-p 只是给我看的,看看超出数组限制的指针是否会评估为 false。我没有多想。
          【解决方案6】:

          据我了解,在 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;
          }
          

          现在当我们编译并运行它时:

          $> gcc null.c
          $> ./a.out
          (nil) 0
          0x7fff0556ff3c 89587516
          

          请注意,在第一个 printf 中,带有 %d 的指针 p 的值是 zero。因此,如果你直接在if 条件中使用指针,它将作为真或假,可以解释为 NULL 指针或非 NULL 指针。

          最佳实践

          另外,我想补充一点,该用法来自标准最佳实践。与潜在危险和容易出错的情况相比,这是检查指针是否为 NULL 的首选方法:

          if (p == NULL) {
          }
          

          可能会(危险地)错误地输入:

          if (p = NULL) {
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2021-12-11
            • 1970-01-01
            • 1970-01-01
            • 2010-09-23
            • 2017-01-05
            • 1970-01-01
            相关资源
            最近更新 更多