Getting distinct enum values C++ - c++

I'm trying to get a distinct value from my enumeration using void pointers.
I've an enum declaration of a list of animals
enum Animal {Rat, Ox, Tiger, Rabbit, Dragon, Snake, Horse, Sheep, Monkey, Rooster, Dog, Pig};
So firstly, i have a function that returns me a value from my enumeration randomly
VoidPtr getAnAnimal()
{
VoidPtr anAnimal;
Animal *a = new Animal;
int k = rand() % 12;
*a = static_cast<Animal>(k);
anAnimal = a;
return anAnimal;
}
Then during my construction of array, I've a conditional statement that states if the array has the same value, it is suppose to randomly generate another enum value
void constructSet(VoidPtr* animalArray, int size)
{
for(int i = 0; i < size; i++)
{
animalArray[i] = getAnAnimal();
int k = 0;
while ((k < i) && (animalArray[i] == animalArray[k]))
{
animalArray[i] = getAnAnimal();
k++;
}
}
}
Unfortunately, it still returns me the same enum value despite calling for another value if the array are the same.

Your error is that when comparing animalArray[i]==animalArray[k] you compare the addresses of the enums not their value. The proper comparison would be (edited after comment, obviously this is not what clean code looks like, but the mistake lies in passing the enum as a void*)
*static_cast<Animal*>(animalArray[i])==*static_cast<Animal*>(animalArray[k])
However, you should reconsider storing your Animal as pointer.
In C++ there is usually no reason to allocate objects by new (neither do you need to work with pointers in C++, unless you really have to). At least not for simple problems as yours.

Your algorithm in constructSet does not really correspond to your description.
I've a conditional statement that states if the array has the same
value, it is suppose to randomly generate another enum value
The two instructions animalArray[i] = getAnimal(); and k++ should be in different branches of a condition. k++ should iterate while the animalArray[i] is different from animalArray[k]. Suppose for example that *animalArray[i] != *animalArray[0] but *animalArray[i] == *animalArray[1] you will insert it even if the array has a same value.
Moreover k should be reinitialized each time a new animal is inserted.
Here is a possible alternative algorithm. I have not checked for the compilation errors.
void constructSet(VoidPtr* animalArray, int size)
{
int attempt = 0;
for(int i = 0; i < size; i++)
{
animalArray[i] = getAnAnimal();
int k = 0;
while ((k < i) && (*reinterpret_cast<const Animal*>(animalArray[i]) != *reinterpret_cast<const Animal*>(animalArray[k])))
k++;
if (k < i && attempt < 12) { // retry?
--i;
++attempt;
}
else // accept the animal
attempt = 0;
}
}

Related

Allocating pointer to a pointer

I have 5 buffers and 20 frames to write in them. Being one frame per buffer, at a certain moment i will have to overwrite buffers with the newest frame.
At random moments i need to read the oldest frame(its id and data) from all the buffers.
I am obliged to use a pointer to a pointer for my buffers, but since i suck at pointers, not even the allocation works, giving me a SEGMENTATION FAULT and not sure why.
What i have until now:
void fakeFrame(uint16_t *data)
{
for (auto i = 0; i < 1440; i++)
for (auto j = 0; j < 1440; j++)
data[(i * 1440) + j] = std::rand()%2;
}
int main()
{
uint16_t **p_frameBuffers;
uint32_t *p_frameIdxs;
uint16_t wrIdx = 0;
uint16_t reIdx = 0;
uint16_t currentFrameCounter = 0;
uint16_t nbBuffers = 5;
for(auto i =0; i< nbBuffers; i++)
{
p_frameBuffers[i] = (uint16_t*)malloc(1440*1440*2);
}
while(currentFrameCounter <= 20)
{
wrIdx++;
wrIdx %= nbBuffers;
if(wrIdx == reIdx)
{
std::cout<<"i passed the limit";
}
currentFrameCounter++;
p_frameIdxs[wrIdx] = currentFrameCounter;
fakeFrame(p_frameBuffers[wrIdx]);
}
std::cout<<"\n";
return 0;
}
I can see a few different problems with this code here.
You declare the long-form of the function for fakeFrame() in the beginning of the program, when the standard is usually to declare the function header first.
This is like a warning to the program that a function is about to be used, and that it's not part of a class or anything. Just standalone.
Example:
#include <iostream>
void fakeFrame();
int main()
{
return 0;
}
void fakeFrame()
{
for (auto i = 0; i < 1440; i++)
for (auto j = 0; j < 1440; j++)
data[(i * 1440) + j] = std::rand()%2;
}
You're also using some of these 16 and 32 bit unsigned ints as if they were arrays, so I was deeply confused about that. Did you mean to set them as arrays?
You also have some variables being declared in a non-array context but being used as arrays. I'm not deeply familiar with the uint variable/object types but I know they aren't usually meant to function as standalone arrays.
Also, no variable called m_pFrameBuffers is actually declared in the code you provided. Plus this is also used as an array, so it should really be declared as one.
I hope this provides at least some insight into what's not working. I'm actually kind of surprised that the void function ran before, it's improperly formatted.
In the end this is what did it: the pointer to a pointer is actually an array of pointers (which i did not know, of course)
p_frameBuffers = (uint16_t**)malloc((sizeof(uint16_t*)*nbBuffers));
for(auto i = 0; i < nbBuffers; i++)
{
p_frameBuffers[i] = (uint16_t*)malloc(1440*1440*2);
}

Merge Sort returns the same array I input

I implemented a mergesort algorithm but it returns the exact same array I pass as an input. The following is the code. I am suspecting the pseudocode that our professor gave us is wrong. But I am not sure. I have tried to implement is as best as I can.
int len(double *a) {
int count = 0;
while (a[count] != '\0') {
count++;
}
return count;
}
double* merge(double* b, double* c, int N) {
int i = 0;
int j = 0;
double* result = new double[N];
for(int k = 0; k < N; k++) {
if ((i < len(b)) && (j >= len(c) || b[i] <= c[j])) {
result[k] = b[i++];
} else {
result[k] = c[j++];
}
}
return result;
}
void merge_sort(double* a, int N) {
if (N >= 2) {
int mid = (N+1)/2;
double *left = new double[mid];
double *right = new double[mid];
for (int i = 0; i < mid; i++) {
left[i] = a[i];
}
for (int j = 0; j < mid; j++) {
right[j] = a[mid + j];
}
merge_sort(left, mid);
merge_sort(right, mid);
a = merge(left, right, N);
}
}
Any help would be really appreciated.
In the last line, you assign your result to the local var a, which is then lost. You need to return a, or pass the input as a reference/pointer, otherwise any changes are only to the local copy.
Arguments in the function are basically local variables, they behave like any local variable in this function, except their initial value is set by code that calls this function. a is a pointer that stores the address of first element of your double array.
As it's a local variable, you can modify it but when the function ends, it will be discarded like all other local variables of the function.
There are several ways to deal with this problem, each with their own up and downsides. The most obvious is to return final value of a when you're done sorting. You could also pass a pointer TO a pointer to this function, and then you would be able to modify the pointer outside the function:
void function(int** argument){
*argument = another_function();
}
, but that severely restricts the source of your input. It no longer could be a local array passed by address like this:
int x = 10;
int *y = &x; // if this is what you want to change
function(&y); // this works
// now x is still 10, y points to a different place in memory which can store a different value
int x[1]; // if you would like to change this array in place though...
function(x); // this is how you would call the function, but it would fail because it can't change the address that x refers to
You main issue is here:
// You pass in a pointer to the data here.
// the parameter `a` holds a pointer to the data.
void merge_sort(double* a, int N) {
if (N >= 2) {
// STUFF
// Here you write over `a` (which is fine)
// BUT: You don't pass the value back.
// So the caller never knows what the new value is.
a = merge(left, right, N);
}
}
To fix this. I think it is a mistake to allocate a new array in merge(). Rather re-use the array you have. You have already copied the data into left and right to be sorted. The merge should merge the data back into the original array a.
// Change this:
a = merge(left, right, N);
into
merge(a, left, right, N);
Now in merge() you can use a as the destination.
void merge(double* result, double* b, double* c, int N)
// No longer need to allocate space for result now.
There are a couple of other issues:
1: What do you need len() for?
int len(double *a) {
int count = 0;
while (a[count] != '\0') {
count++;
}
return count;
}
You should already know the length of all parts you should not be re-measuring it. Also this function is completely wrong (the double array is not \0 terminated).
2: The length of b and c is not obvious.
double* merge(double* b, double* c, int N) {
You get the wrong value because you call len() which is not correct.
You could calculate from N but that has issues in that you need to make sure both you merge functions use exactly the same method and that is error prone in the long run. I would personally pass the size of each array as parameters to the function.
3: You leak your intermediate arrays!
You call new to allocate storage.
double *left = new double[mid];
double *right = new double[mid];
But you don't deallocate these objects so they are leaked (for every call to new there should be a corespodning call to delete).
Overall. You can solve a cople of issues by using more C++ style techniques (rather than the C style you are using). Iterators and std::vector spring to mind.

Trying to copy a 2D dimensional array of objects to another function

I'm trying to copy an array from one class to to another class by passing it to a function but I'm running into issues. The array that I'm trying to copy seems to lose all its data.
// A.h
class A
public:
virtual void Test();
private:
A* array2D[30][32];
// A.cpp
void A::Test()
{
B* f = new B();
f->pass(array2D);
}
// B.h
class A;
class B
{
public:
void pass(A *a[][32]);
private:
A *a[30][32];
}
// B.cpp
void B::pass(A *array2D[][32])
{
for (int i = 0; i <= 30; i++)
{
for (int j = 0; j <= 32; j++)
{
a[i][j] = array2D[i][j];
}
}
}
My guess is that it's happening when I'm passing it but I'm not sure what I'm doing wrong.
My guess is that it's happening when I'm passing it but I'm not sure what I'm doing wrong.
First, your for loops to populate the array go out-of-bounds on the last iteration of the nested for loop:
void B::pass(A *array2D[][32])
{
for (int i = 0; i <= 30; i++) // This goes out-of-bounds on the last iteration
{
for (int j = 0; j <= 32; j++) // This also goes out-of-bounds.
{
a[i][j] = array2D[i][j];
}
}
}
Using <= in a for loop is an indication that things can go wrong, and they do go wrong with your code. The fix would simply be:
void B::pass(A *array2D[][32])
{
for (int i = 0; i < 30; i++)
{
for (int j = 0; j < 32; j++)
{
a[i][j] = array2D[i][j];
}
}
}
This will work, however it is inefficient (unless a great optimizing compiler sees that this is inefficient and changes the code).
The better way to do this is a simple call to std::copy:
#include <algorithm>
void B::pass(A *array2D[][32])
{
std::copy(&array2D[0][0], &array2D[29][32], &a[0][0]);
}
The reason why this works is that two-dimensional arrays in C++ have their data layout in contiguous memory, thus it is essentially a one-dimensional array. So giving the starting and ending address of the array elements is all that's required.
A compiler will more than likely see that you are copying a trivially-copyable type (a pointer), thus the call to std::copy results in a call to memcpy.

C++ applying "typing" on an array of elements

EDIT: This is a school assignment, I didn't decide on this design so please don't suggest to change it.
Consider the following hierarchy :
A
/ \
B E
/\
C D
I have an array of pointers to A (A**) , and I need to create two methods :
First one counts every object of type B and its relatives.
Second one counts only the object of exactly B type.
For the first one I'm using this code:
int countTypeOfBs(A** arr, int size){
int count = 0;
for (int i = 0; i < size; i++)
if (dynamic_cast<B *>(arr[i]))
count++;
return count;
}
And I'm stuck with the second one, I've tried this :
int countBs(A** arr, int size){
int count = 0;
for (int i = 0; i < size; i++)
if (!strcmp(typeid((*A[i])).name(), "B"))
count++;
return count;
}
But I'm getting an error saying expression must have a constant value ..
How can I solve this ?
EDIT: It was a typo, I accidently used A[i] instead of arr[i] . It fixed the problem .
The typeid-operator can be applied to a type, or an expression, and returns a reference to the appropriate std::type_info object. And those can simply be compared with operator== for equality.
The implementation will know whether reference-equality is enough, or it needs a string-comparison, don't try to second-guess it.

Aliasing vector correctly

I have not been able to find the answer elsewhere, so I guess I just have to ask this one: I am trying to get an alias for a vector (in which int pointers are stored), as below:
void conversion(Engine * ENGINES)
{//The Engine class has a vector of int* as a public data member called SITE
for (int i = 0; i < 3; i++)
{
vector <int*>* current = &(ENGINES[i].SITE);//the problematic line
int j_max = current -> size();
cout << j_max << endl;
for (int j = 0; j < j_max; j++)
{
for (int k = 0; k < 3; k++)
{
if (*current[j][k] == 2)
*current[j][k] = 1;
if (*current[j][k] == -1)
*current[j][k] = 0;
}
}
}
}
The problem is that there seems to be an inversion of the indices for the *current[a][b]. I want to be able to use current as a normal vector, but now the indexing is reversed compared to:
vector <int*> current1 = ENGINES[1].SITE;
so that *current[i][j] = current1[j][i] for some reason. Is there a mistake in my syntax?
I believe your problem is that [] has higher precedence than unary *. So you're getting *(current[j][k]) instead of (*current)[j][k], which is what you want.
However you could eliminate that problem by just taking a reference rather than a pointer:
vector <int*>& current = (ENGINES[i].SITE); and then just remove your extra loading * operators on access to current.
The problem is that [] has greater precedence than * (dereference), so *current[i][j] is interpreted as *(current[i][j]), which is probably not what you want.
Actually, this idiom of aliasing is commonly expressed as a reference, not a pointer:
vector <int*>& current = ENGINES[i].SITE;
and use simply current[i][j].
As I suspected in my comment, use a reference.
vector <int*> &current = ENGINES[i].SITE;