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?).
3 Answers
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
1 Comment
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 when0is 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
-1is 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);
}
}
Comments
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 *
NULLandnullptrare a fancy way to spell0for pointers. There some minor differences between those spellings, but all of them represent the same pointer value (null), so you can't discern between them.intas "empty". The assignmentarr[0] = NULLwill assignarr[0]to be zero, not mark it as "empty".NULLisn't part of c++, and I don't think thatint arr[4]=0would compile, what's the intent there? If you can clarify your question, maybe in the process you could find an answer.arris an array, not a pointer. The name of an array can be used as if it is a pointer in some contexts but not others. But that does not mean an array is a pointer, nor vice versa.