What values should I fill my arrays with to indicate an empty space?

Viewed 351

This is more of an etiquette question than anything else, but when creating new arrays what value, other than zero, should I use to indicate an empty space in the array? For example:

int* arr;
arr = new int[10];

When I create a new array like in the code above, the array will be filled with ten zeroes. The issue I'm having is that I want to use underscores when printing the array to indicate empty spaces, however, I also have zeroes as part of my data set in the array. So, should I just fill the empty array with some arbitrary value that is unlikely to show up in my data set (like -32000 for example), and use that as the indicator for empty space, or is there some sort of null value that I could use instead so that I can know for a fact that the value at that specific index is definitely an empty space?

3 Answers

should I just fill the empty array with some arbitrary value that is unlikely to show up in my data set

Well, unlikely is not the same as a value that you know for certain will not appear in the data, and the error that you get from being wrong about this will be a nasty error. Generally speaking, however, you usually do have some idea of the range of valid values and it can indeed be easier to use a sentinel value outside that range to indicate nullity. (And if you do it this way I'd recommend being very fastidious about sanitizing the input data coming into your program i.e. explicitly test for your sentinel value unexpectedly coming in from an external source.)

However, in cases where there is no such value, or just to unambiguously declare your intent, the canonical way to handle this situation in modern C++ is to use std::optional<int>. The standard library's optional is a way of turning any type into a nullable type.

What you appear to be asking about is called a sentinel -- some data value that has special meaning.

Regarding choice of sentinel, use something you know is not going to appear and make it a named constant. For example, you might use:

constexpr int NoValue = std::numeric_limits<int>::min();

If you absolutely need the entire integer range or if you cannot reliably sanitize your input to ensure that data is never accepted as a non-empty value, consider using a larger data type that can represent that range and a sentinel, or use std::optional as suggested in another answer.

Alternatively, maintain a separate array to hold that information. Such an array only requires one bit per element to represent whether the value is empty or not and so it only means a fractional increase in storage as opposed to expanding your data type beyond int. This approach trades off memory usage against memory locality, since the data about "emptiness" would not be stored adjacent to a value in your array and that may have implications for caching.

Regarding the actual initialization question: your array is uninitialized and will require setting values with std::fill or similar. Otherwise your program's behavior is undefined if you attempt to use an uninitialized value. Note that there's a special case: new int[100]() which will zero-initialize the memory. But you can't use that construction to initialize with any other value.

Consider using std::vector to avoid memory management issues, and to provide initialization with non-zero values without adding code clutter:

std::vector<int> arr(10, NoValue);

As you can see, there are choices to be made which depend on your program's requirements and its input specification. I hope this helps you make a more informed decision.

Please note that questions of "taste" are generally frowned upon in StackOverflow.

With that said, here's my preference:

Something that cannot masquerade as a valid value, like NaN, makes a good placeholder. If that isn't an option, then as you said, a value that will not/is not allowed to appear in the data set works.

Related