如果我需要在 C++ 中区分 0 和 NULL 怎么办?

What if I need to differentiate 0 from NULL in C++?

** 请不要批评代码本身的用途。它来自 Pat Morin 的开放数据结构一书。不是我的第一选择,它已分配 reading/practice。我只是想知道是否有办法区分,或者有更好的方法来解决这个问题。教科书--> http://opendatastructures.org/ods-cpp/**

** 另一个注意事项:我来自 Java,那里是允许的。我的代码仍然可以编译,只是 "fixes" it**

我很惊讶以前没有出现过这样的问题,因为这似乎是一个如此简单的问题。也许它被掩埋了,或者我没有使用正确的术语。

我有一个 for 循环遍历向量中的数据。如果找到,我需要 return 正在搜索的值。如果找不到怎么办?这是我的代码。

int find(int x) {
    for(int i=0;i<bag.size();i++){
        // if x is equal to data, return data
        if (bag[i]==x){
            return bag[i]; // ends loop as soon as one instance is found
        }
    }
    // if we made it this far, no match was found.
    return NULL;

}

很简单。假设 0 是我可能需要记录和搜索的有效值之一。事实上,它实际上是 returns 0,而不是 "NULL"。研究表明它是一回事。我如何指定或区分?除了 return 一个不会出现在程序中的模糊数字,因为我们可能并不总是拥有这种奢侈(比如 -1 或 -9999999)。例如,搜索您的帐户余额。没有数字是不可能的。

为什么要 return 从查找函数中搜索的值?您已经知道该值,它是您传递给函数的值。 Return 找到的元素的位置,因为此信息更有用。当找不到该值时,您可以 return 一个特殊的位置,例如 -1。或者您可以遵循标准库的模型和 return 结束迭代器,它表示超出范围末尾的位置。

你在谈论一种邪恶的做法,来自 Java 和 C# 开发人员,在那里你可以 return null 作为无效结果。

好吧,你不能用 C++ 来做。 Java 和 C# 声明了堆上的几乎所有内容,并且访问对象始终由引用完成。这意味着您始终 return 来自函数的指针,并且您始终可以 return 空值作为 return 值。

当函数不是 return 指针时,这在 C++ 中是不可能的。例如,函数 std::string returnString() 不能 return null 作为 return 值。

此外,您不应该 return null 作为无效输出。即使在 C# 和 Java 中,这在很多层面上都是错误的!如果您的函数失败,只需抛出异常,或将您的 return 值作为引用参数传递并使函数 return 为真或假。

您还可以找到不太激进的解决方案,例如 returning -1(例如 javascript 中的 indexOf())或 return 诸如 std::string::nposstd::vector:end 对 C++ STL 进行了更多调整。

这就是 boost::optional<T> 的用途。实际上,此类型表示 "There may be a T, but there may not be a T"。用户可以检查是否有 T。理想情况下,您不会依赖 T 的任何特殊值,而是使用 optional<T> 代替。 optional<T> 是完全通用的,几乎可以应用于您可能需要使用的任何 T,它不依赖于 T.

的某些特殊值或状态
boost::optional<int> find(int x) {
    for(int i=0;i<bag.size();i++){
        // if x is equal to data, return data
        if (bag[i]==x){
            return bag[i]; // ends loop as soon as one instance is found
        }
    }
    // if we made it this far, no match was found.
    return boost::none;    
}
int main() {
    if (auto opt = find(5))
        std::cout << *opt;
}

永远不要使用 NULL,这是一件很糟糕的事情。始终使用 nullptr,它实际上更安全,它更安全的原因之一是因为您的错误代码无法编译。

您可以通过多种方式编写函数

bool find( int x ) 
{
    std::vector<int>::size_type i = 0;

    while (  i < bag.size() && bag[i] != x ) i++;

    return i != bag.size();
}

std::vector<int>::size_type find( int x ) 
{
    std::vector<int>::size_type i = 0;

    while (  i < bag.size() && bag[i] != x ) i++;

    return i;
}

#include <algorithm>

//...

std::vector<int>::iterator find( int x ) 
{
    return std::find( beg.begin(), bag.end(), x );
}

并通过以下方式对应使用功能

if ( find( x ) ) { /*...*/ }

if ( find( x ) != bag.size() ) { /*...*/ }

if ( find( x ) != bag.end() ) { /*...*/ }

至于你在标题中的一般问题post

What if I need to differentiate 0 from NULL in C++?

那么你需要使用 nullptr 而不是 NULL 来区分 0 和 NULL。:)

#define XOR_MSB(x) (x^0x80000000)

int find(bool found) {
    return found ? XOR_MSB(0) : NULL;
}

int main()
{
    int value = find(false);
    if (value == NULL) printf("not found\n");
    else printf("%d\n", XOR_MSB(value));
    value = find(true);
    if (value == NULL) printf("not found\n");
    else printf("%d\n", XOR_MSB(value));
    return 0;
}