Home > Enterprise >  Checking when value in array is 0 but not NULL C
Checking when value in array is 0 but not NULL C

Time:01-02

I'm newbie and I need little help. I tried different ways, but from what I can see NULL means 0 in c , so when want my (for example) int arr[4]=0, then it says that it's also NULL. Is there any way to see when value is 0 and not NULL (or empty?).

CodePudding user response:

Sounds like a job for std::optional:

#include <iostream>
#include <optional>

int main()
{
    std::optional<int> arr[] = { 10, 0, std::nullopt, -52 };

    for (auto i = 0U; i < sizeof(arr) / sizeof(*arr); i  )
    {
        if (arr[i])
        {
            std::cout << "arr[" << i << "] = " << *(arr[i]) << std::endl;
        }
        else
        {
            std::cout << "arr[" << i << "] = std::nullopt" << std::endl;
        }
    }
}

Output:

arr[0] = 10
arr[1] = 0
arr[2] = std::nullopt
arr[3] = -52

CodePudding user response:

It sounds like you're looking for a null concept for your data type (int array[4]), but you want 0 to be a valid (non-null) value. The null concept is useful when your variable is not guaranteed to hold valid data. You need a null concept if, for a variable x, you want to be able to ask the question "does x contain a valid value?".

First, recognize that NULL is an implementation-defined way to represent a pointer that points at nothing. Here, implementation means "specific compiler". Usually, NULL is an integer constant equal to 0, which in practice makes it ill-suited to differentiate from your otherwise-valid value of 0.

TL;DR: I think you want to use std::vector, but you have several options available.

Null concept for int

Depending on what your data represents, you may be able to represent a null by selecting a value or range of values that are not valid for your specific use case, but otherwise representable using your data type.

Some example null concepts for int data type:

  • 0-- is a perfectly fine null when 0 is not a valid value. The null test code is very clean as well: if (x) { ... }.
  • negative values-- You can select a specific negative value or the entire range of negative values. Or even a subrange of all negative values, although I've never seen this last one in practice. Generally the specific value of -1 is used. The null test code looks like: if (x >= 0) { ... } or if (x != -1) { ... }.
  • extreme positive values-- You can select a very large number to represent the null concept. If a valid instance of your data will never reach this value. I recommend std::numeric_limits<int>::max(), which requires #include <limits>. The null test looks like: if (x != std::numeric_limits<int>::max()) { ... }

std::optional<T>

When all possible values of your data type represent valid values, then you need to include extra overhead if you want to represent the null concept. std::optional<T> wraps any data type and is used specifically for the case where you need to represent invalid data. The access semantics looks very similar to accessing a pointer.

#include <optional>

void do_something(int);

int main() {
    std::optional<int> a; // default initialization is "empty"
    std::optional<int> b = 1; // can be assigned just as if it were the type

    if (a) { // You can check in a natural-feeling way if the data is valid
        do_something(*a); // and access the data as if it were a pointer
        do_something(a.value()); // or use std::optional<T>::value()
    }

    // If the data may be invalid, you must check before accessing
    // *a; // WRONG: throws an exception
    // a.value(); // WRONG: for the same reason

    // If you know for certain the data is valid, feel free to access it
    do_something(*b);

    // You can't access it entirely as if it were an int, dereferencing is necessary
    // int c = b   2; // invalid, no overloaded operator  for std::optional<int> type
    int c = *b   2; // valid

    // An array of optionals looks similar to an array of ints
    std::optional<int> array[4]; // initialized as all empty

Just don't deal with invalid data at all

If your data doesn't necessarily need to exist until it is valid then you can use a variable size container to just... not have invalid data at all.

std::vector<T> is the go-to dynamically sized container in C , and allows you to have just enough space to handle only the data you need. std::vector<T> also has many class methods that allow easy access to container information such as std::vector<T>::size() or iterators with std::vector<T>::begin() and std::vector<T>::end().

#include <vector>

void do_something(int);

int main() {
    std::vector<int> data; // initially empty, no elements

    // you can add new values
    data.push_back(1); // vector contains { 1 }
    data.emplace_back(2); // vector contains { 1 , 2 }

    // looping is the same as with arrays
    for (int i = 0; i < data.size(); i  ) {
        do_something(data[i]);
    }

    // or you can use range-based for loops for cleaner looking code
    for (auto& d : data) {
        do_something(d);
    }
}

CodePudding user response:

If that is an array of pointers:

int* arr[10] = {};

Then here is how you check if an element is null:

if (arr[4] == nullptr) 

And here is how you check if the pointed value is zero:

if (*arr[4] == 0) // note the *
  •  Tags:  
  • c
  • Related