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

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.

Related

Getting distinct enum values 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;
}
}

How to return C++ Array Pointer in method

First, I made funciton that return Array[2]'s pointer.
int* ReturnArray(int a, int b) {
static int Array[2];
Array[0] = a;
Array[1] = b;
return Array;
}
And I made simple 2-Dimensional array in Main.
int a, b;
in >> NumberOfSize;
int** S = new int*[NumberOfSize];
for (int i = 0; i < NumberOfSize; i++)
S[i] = new int[2];
Last, I added ReturnArray(a,b) to set the value of S[i]
for (int i = 0; i < NumberOfSize; i++)
{
in >> a >> b;
S[i] = ReturnArray(a, b);
}
But in Main, I cannot get right value in Array S[i][j].
When I changed upper way to under, I can set the right value in array S.
for (int i = 0; i < NumberOfSize; i++)
{
in >> a >> b;
S[i][0] = ReturnArray(a, b)[0];
S[i][1] = ReturnArray(a, b)[1];
}
What happended in upper way?
And How can i get right value in only one call ReturnArray function?
(sorry for my fool english.)
The problem it's that you have a static local variable in the function, that means all calls to the function will share the same array and modify the same array, which means only the values set in the last call will be the ones you use.
One way to solve the problem is to do your dynamic allocation and copy the values separately like you do in your working example. Another possible solution is to use another data structure with proper copy-semantics, like e.g. std::pair or std::tuple, and don't have any static array (or anything static at all) in the function.

Pointer to Elements of an Array printing the memory address rather than the value of the element

I am currently writing a program for a class that takes user input to either add or remove a number from a dynamic array, and then print all the values of the array in ascending order.
From what I have already researched, all I need to do to get the value of the element in the array to print is to ensure the dereference operator is inserted next to the pointer name. However, when done as below (newArray[i]) I get a compile-time error saying that the operand to the right of the '' must be a pointer, even though newArray is declared as pointer at the beginning of the function.
void output(int *arrayPtr, int size){
int small;
int i, j;
int *newArray;
newArray = new int[size];
for (i = 0; i < size; i++){
*newArray[i] = arrayPtr[i];
}
for (i = 0; i < size; i++){
small = *newArray[i];
for (j = 0; j < size; j++){
if (*newArray[j] < small){
*newArray[j] = small;
}
std::cout << small;
}
int number = small;
removeNumber(*& arrayPtr, number, size);
}
}
I feel like there is something totally obvious I am missing, but I would greatly appreciate any help or ideas!!
small = *newArray[i];
That should just be:
small = newArray[i];
(Same thing in the other places you compare/assign *newArray[i]
What your first operation is doing is first dereferencing newArray, which means it gets the value of the first element in the array, and then attempting to index that. The element is not a pointer, so this of course fails. When you index, it also implicitly dereferences the pointer. You could also write:
small = *(newArray + i);
However, generally you only use pointer arithmetic when you need the actual pointer, since indexing is easier to read if you need the value.
Going through your code, a few other things seem off:
for (i = 0; i < size; i++){
*newArray[i] = arrayPtr[i];
}
This might compile but I don't think it is right, I'm guessing you mean:
for (i = 0; i < size; i++){
newArray[i] = arrayPtr[i];
}
Also:
removeNumber(*& arrayPtr, number, size);
While this is technically correct, *& first returns a pointer reference, then turns around and dereferences it again. I wouldn't be surprised if the compiler optimizes it away anyway, but it is unnecessary.

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;

C++ two dimensional arrays with pointers

I have a problem with two dimensional arrays :( I feel very stupid and Visual C does not help me :( and I also think that my mistake is very stupid but still I can't find it :( I have this code:
double matrix[100][100]; //which is full with a matrix 3x4
double nVector[10000]; // for negative doubles
//I wanted to see if there are negative doubles in each row and column
//and I want this to happen with function
And this is my function:
double* negativeVector(double*nVector, double*fromVector, int m, int n){
int position = 0;
double *myNegArray = nVector;
double *myMatrix = fromVector;
for(int i = 0; i < m*n; i++)
if(*(*(myMatrix+i)) < 0){
*(myNegArray+position) = *(*(myMatrix+i));
position++;
}
return myNegArray;
}
//for double*nVector I'm passing nVector
//for double*fromVector I'm passing *matrix
Visual C tells me that I have an error C2100: illegal indirection here: *(*(myMatrix+i)) I hope someone can help me (happy)
Thanks in advance!
*(*(myMatrix+i)) is wrong. This is a common mistake.
2D matrix does not create an array of pointers which you can access this way. It is a different structure. Even though an array is a pointer, 2D array is not a pointer to pointer, and it cannot be dereferrenced twice. Nor you have any other way to access element at coordinates (x,y) without knowing the layout in memory, because pointers to every line are nowhere to be found. For instance, char **argv parameter of main() is not a 2D array. This is an array of pointers to arrays, which is something else.
There're two ways to fix it.
One is replace
double *myMatrix = fromVector;
by
double *myMatrix[100] = (appropriate cast)fromVector;
and index it as myMatrix[i/n][i%n]
But then remember that 100 is a constant expression, and it cannot be passed as a parameter. Alternatively, you can implement the indexing operation yourself:
Pass additional parameter: matrix line size (100)
Instead of *(*(myMatrix+i)), write:
int row = i/n;
int col = i%n;
*(myMatrix+row*line_size+col) is your element.
first you might wanna start a small struct like
struct tmp {
bool negative;
double value;
};
and make your own way up to the
tmp *myvars [100][100];
.
instead try using that struct and try the std::vectors instead of arrays if that's possible then try using pointers on decalring the variable "1 time only" when declaring the variable as i said above
then pass arguments
( tmp *mystructpointer )
mystructpointer->.......
access your matrix directly ... peice of cake :D
If you are passing *matrix, you are actually passing a double[100] (an array of 100 doubles), that happens to be passed as a pointer to its first element. If you advance further than those 100 doubles using i added to that pointer, you advance into the next array of 100 doubles, since the 100 arrays of 100 doubles are stored next to each other.
Background: A multi-dimensional array is an array whose element type is itself an array. An array like double a[100][100]; can be declared equivalently as typedef double aT[100]; aT a[100];. If you use an array like a pointer, a temporary pointer is created to the array's first element (which might be an array). The * operator is such an operation, and doing *a creates a pointer of type double(*)[100] (which is a pointer to an array of 100 doubles), and dereferences it. So what you end up with *matrix is a double[100]. Passing it to the negativeVector function will create a pointer to its first element, which is of type double*.
Your pointer parameters point to the start of each of two arrays of 100 doubles each. So you should rewrite the function as
double* negativeVector(double*nVector, double*fromVector, int m, int n){
int position = 0;
double *myNegArray = nVector;
double *myMatrix = fromVector;
for(int i = 0; i < m*n; i++)
if(*(myMatrix + i) < 0){
*(myNegArray + position) = *(myMatrix + i);
position++;
}
return myNegArray;
}
Notice that since your i iterates beyond the first of the 100 arrays stored in the 2d array, you will formally not be correct with this. But as it happens those arrays must be allocated next to each other, it will work in practice (and in fact, is recommended as a good enough work around for passing multi-dimensional arrays around as pointers to their first scalar element).
I have no clue why you are copying the arrays twice (once in the parameters of the function and a second time by declaring some new arrays)... You should also think of using the STL... std::vector will make the your life way easier ;)
double* negativeVector(double*nVector, double*fromVector, int m, int n){
int position = 0;
double *myNegArray = nVector;
double *myMatrix = fromVector;
for(int i = 0; i < m*n; i++)
if(*((myMatrix+i)) < 0){
*(myNegArray+position) = *((myMatrix+i));
position++;
}
return myNegArray;
}
is that homework? some templates - just for fun ;-)
double matrix[100][100];
double nVector[10000];
template< const int m, const int n >
double* negativeVector( double* myNegArray, const double (&myMatrix)[m][n] )
{
int position = 0;
for( int i = 0; i < m; ++i )
{
for( int j = 0; j < n; ++j )
{
const double value = myMatrix[ i ][ j ];
if ( value < 0 )
{
myNegArray[ position ] = value;
++position;
}
}
}
return myNegArray;
}
int main()
{
//...initialize matrix here...
negativeVector( nVector, matrix );
}
Perhaps rewrite this using std::vector to increase readability? (#):
#include <vector>
std::vector< std::vector<double> > matrix; //which is full with a matrix 3x4
std::vector<double> row;
row.resize(100,0);
matrix.resize(100,row);
std::vector<double> nVector; // for negative doubles, no size, we'll "push_back"
//I wanted to see if there are negative doubles in each row and column
//and I want this to happen with function
This is the stl enabled version of the function:
//I'm returning void because nvector contains the result,
//so I don't feel the need to return anything. vectors contain their
//own size so n and m are also not needed. Alsom pass in references
void negativeVector(std::vector<double>& nVector,
std::vector< std::vector<double> >& fromVector){
nVector.clear();
int i,j;
for(i = 0; i < fromVector.size(); i++) {
for(j = 0; j < fromVector[i].size(); j++) {
if(fromVector[i][j] < 0){
nVector.push_back(fromVector[i][j]);
}
}
}
}
call with:
negativeVector(nVector, matrix);
Once the function completes, nVector contains all negative numbers in matrix.
Read more about std::vector here.
(#) for people like me who are too lazy/stupid to comprehend code containing pointers.
Take a look at C++ Faq site:
How do I allocate multidimensional arrays using new?
link
And read until point [16.20] summarize all the answers you are getting and at the end you get a very useful Matrix template class.
Have a good read.