0

I was wondering if there was a way, in C++, to check if the value of a dynamic array actually exists.

int *x = new int[5];

Okay, so I think by default every value of x will be 0. But, the problem is that when I'm filling it with values, I may actually put in 0. Thus, this will cause confusion as to what tells us if the value really exists or not (0 seems to be the idiom that tells us it's NULL, but in this particular case I can't use that idiom because 0 may be a value that was given to me).

Is there another way to check if a value in a dynamic array is undefined?

  • 1
    What do you mean by "the value of a dynamic array"? In your code, the elements of the array are *uninitialized*, so they have *no* well-defined value. – Kerrek SB Apr 23 '12 at 01:56

7 Answers7

3

well, first of all, as Jonathon said, there is no guarantee that the array will be initialized to 0. You can either initialize it separately, or use int *x = new int[5](); which would do initialization for you.

As for how do you know which are valid. The simplest approach is to store a struct instead of ints. Something like this:

struct T {
    T() : valid(false), value(0) {
    }

    bool valid;
    int  value;
};

T *p = new T[5]; // each element will be initialized to false/0 because T has a constructor.

Then you can just do:

p[0].value = 10;
p[0].valid = true;

and so forth.

EDIT: As a more advanced option, you can use operator overloading to make the valid flag get set automatically like this:

struct T {
    T() : valid(false), value(0) {
    }

    T &operator=(int x) {
        valid = true;
        value = x;
        return *this;
    }

    bool valid;
    int  value;
};

T *p = new T[5]; // each element will be initialized to false/0 because T has a 
p[1] = 10;       // p[1] is now true/10

Basically, assigning an integer value to the element, will automatically mark it as valid. Though in this particular example, I have not demonstrated how to "unset" a value back to being "invalid". This may or may not make sense for your use case or coding style, just some food for thought.

Evan Teran
  • 87,561
  • 32
  • 179
  • 238
2

If it is dynamically allocated, it will NOT be zeroed for you; you must initialize the array yourself by setting all entries to some default value. If zero is a valid entry, then consider using negative one. If all positive and negative values are valid entries, then consider using a structure that contains the integer value, and a Boolean flag initialized to false.

In C, this would be:

typedef struct {
    bool valid;
    int  value;
} node;

node x[] = new node[5];
Jonathon Reinhart
  • 132,704
  • 33
  • 254
  • 328
  • 2
    you are slightly off in your recommendation. This is a syntax error since your are using `typedef`, but not providing the alias it would be named. In addition, for this case, `typedef` isn't really needed at all, it's more of a c-ism. – Evan Teran Apr 23 '12 at 02:03
  • Sorry, I am really much more of a C programmer than C++ these days. This is how I would do it in C, which was also tagged. – Jonathon Reinhart Apr 23 '12 at 02:04
  • sure, though the c tag is a bit wrong, since this uses `new`. Of course if he used `malloc` the concept is of course the same, but he is clearly using c++. – Evan Teran Apr 23 '12 at 02:54
  • still won't compile :-P. `node x[] = new node[5];` would probably be correct Java, but not c++... – Evan Teran Apr 23 '12 at 04:38
1

If you cannot sacrifice a value, say, the smallest negative or a largest positive int, to mean "not set", you need to keep track of what's set on the side. In C++ you can use std::vector<bool>:

int *x  = new int[5];
std::vector<bool> isSet(5, false);
if (!isSet[3]) {
    x[3] = 123;
    isSet[3] = true;
}
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • 1
    perfectly valid, but I would personally prefer to use an array of objects instead of 2 separate arrays because it eliminates the risk of the tracking array and the data array being out of sync. – Evan Teran Apr 23 '12 at 02:01
0

If they values you're going to use are going to be dense/contiguous, use std::vector (whose size() member will tell you how many items are currently valid). If the values are sparse, use std::set instead.

Either way, you'd be better off forgetting that new T[size] exists at all, not to mention subjecting yourself to the insanity of actually using it.

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
0

I wouldn't use a dynamic array for this job, due to the many complexities that properly managing a resource involves. In my opinion, you should take a peek at std::vector, which would turn your code into something a bit like this:

#include <vector>

...

    std::vector<int> x();
    x.resize(5);

Now that would allow you to stop worrying about the bitch that resource management is, and focus into what is actually important (that is, handling your Xses).

Misguided
  • 1,302
  • 1
  • 14
  • 22
0

But, the problem is that when I'm filling it with values, I may actually put in 0. Thus, this will cause confusion as to what tells us if the value really exists or not

There's no confusion as to whether a '0' really exists or not. If there's a 0 in the array that you didn't put there, it still exists. There's no difference between zeros that just happen to be in the array and zeros that you put there. If you need to distinquish between elements that you've assigned a value to versus elements that are not initialized, then you have to keep track of that information somewhere else.

bool *b = new bool[5](); // initialize the array to all false
int *x = new int[5]; // don't initialize the array
x[3] = 0; // set the fourth element in the array to 0
b[3] = true; // record that the fourth element in the array has been set

(Note, that you shouldn't use raw arrays and you shouldn't use new/delete)


int *x = new int[5];

Okay, so I think by default every value of x will be 0.

Not the way you're constructing that array; none of the ints in the array are initialized. They could have any value. Often when you build in 'debug' mode memory will be automatically zero initialized for you, but this is not specified by C++.

Community
  • 1
  • 1
bames53
  • 86,085
  • 15
  • 179
  • 244
0

In addition to my other answer, another approach if you think your valid indexes will be sparse, would be to use std::map as an associative array like this:

std::map<int, int> x;
x[0] = 10;
x[2] = 123;
// indexes 0 and 2 are set, the rest do not exist.

To test if a value is preset, simply do:

if(x.find(n) != x.end()) {
    // there is a value at index n
} else {
    // no value found at index n
}

If your valid indexes are contiguous, you may as well just go with std::vector, or my original answer.

Evan Teran
  • 87,561
  • 32
  • 179
  • 238