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 when0
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) { ... }
orif (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 *