private:
struct info{
int size = 0;
int key = 0;
int capacity = 1;
std::vector<int*> *value = new std::vector<int*>(capacity);
};
int keyCapacity_;
int size_;
std::vector<info*> *keys_;
within a function...
//some code
keys_ = new std::vector<info*>(keyCapacity_);
//some code
(*keys_)[size_] = new info;
(*keys_)[size_]->(*value)[size] = inputValue; //getting error on this line
(*keys_)[size_]->size += 1;
(*keys_)[size_]->key = key;
I have a pointer to a vector of struct info. Then within info there is a pointer to a vector that will hold values. Very large amounts of data may be input and the program resizes the vectors if needed. The current input value is added to the first open spot on the vector which is size_. On the line I've identified above I am getting an error:
a3.hpp:67:20: error: expected unqualified-id before ‘(’ token
(*keys_)[size_]->(*value)[size] = value;
^
a3.hpp:67:22: error: invalid type argument of unary ‘*’ (have ‘int’)
(*keys_)[size_]->(*value)[size] = value;
How can I access this vector to change the value?
Well, *value is not in scope in this context. It's in parentheses, so it will be evaluated separately. To get to value, you need:
(*keys_)[size_]->value
And then you want to dereference that:
*((*keys_)[size_]->value)
The extra set of parens probably isn't necessary, but it makes things clear. Then you want to index that:
(*((*keys_)[size_]->value))[size]
And I am assuming that size_ and size are correct, different indices. Be careful with your naming. That similarity could trip you up very easily.
As a side note, do realize that using new is almost never what you want to do in modern C++. You probably want to be using smart pointers instead.
(*keys_)[size_]
this one is right
(*keys_)[size_]->(*value)[size]
but this one is not. it will look like you are calling (*value)[size] which doesnt make any sense. its a syntax error.
so you have to call the value first and then dereference it as a whole. like this (*keys_)
int size = yourSize;
(*((*keys_)[size_]->value))
after that you will can now access its index and object inside it.
(*((*keys_)[size_]->value))[size] = &value;
The quick fix for your line is this: (*((*keys_)[size_]->value))[size] = inputValue;
But seriously, don't use C style pointers. Change your code to this instead:
private:
struct info {
int size = 0;
int key = 0;
int capacity = 1;
std::vector<int> value;
}
int keyCapacity_;
int size_;
std::vector<std::unique_ptr<info>> keys_;
And in that function:
//some code
keys_.resize(keyCapacity_);
//some code
keys_[size_] = std::make_unique<info>();
keys_[size_]->value[size] = inputValue;
keys_[size_]->size += 1;
keys_[size_]->key = key;
Since you haven't given a complete example, I can't be entirely sure, but the code still looks wrong to me, because it seems you try to write to a vector that has size 0. From what I can see this should work, but take it was a grain of salt:
//some code
keys_.resize(keyCapacity_);
//some code
keys_[size_] = std::make_unique<info>();
keys_[size_]->value.push_back(inputValue);
keys_[size_]->size += 1;
keys_[size_]->key = key;
Related
I am trying to create a sorting function with the parameters being a pointer of a list and I am trying to access an element of the given list. Hopefully this code speaks for the problem better than I can:
void bubbleSort(std::vector<int> *L) {
unsigned int i = 0; int temp;
while(isSorted(*L)) {
if(i==L->size()-1) {
i = 0;
}
if(i<L[i]/*<-ERROR here.*/) {
temp = L[i+1]; // ERROR HERE
L[i+1] = L[i]; // ERROR HERE
L[i] = temp; // ERROR HERE
}
}
}
You don't need to painfully dereference every individual use of L (and indeed doing so is error-prone, as you've demonstrated by missing one in your answer).
Instead, just write:
void bubbleSort(std::vector<int> *Lptr) {
auto &L = *Lptr;
and keep the rest of the code the same.
NB. It would be even better to change the function itself, to
void bubbleSort(std::vector<int> &L) {
as it should have been written in the first place, but I'm assuming there's some artificial reason you can't do that.
The function accepts a pointer to an object of type std::vector<int>.
void bubbleSort(std::vector<int> *L) {
To access the original vector using the pointer, you can write either *L or L[0]. That is, both expressions yield an lvalue reference of type std::vector<int> & to the vector.
To get the i-th element of the vector using the subscript operator through the pointer, you can write either (*L)[i] or L[0][i],
However, in this if statement:
if(i<L[i]/*<-ERROR here.*/) {
You are trying to compare the variable i of type unsigned int to the object L[i] of type std::vector<int>. When i is not equal to 0, this yields a non-existent object of the vector type.
It seems you mean something like the following instead:
if ( (*L)[i] < (*L)[i+1] ) {
or:
if ( L[0][i] < L[0][i+1] ) {
or, vice versa:
if ( L[0][i+1] < L[0][i] ) {
Depending on whether the vector is sorted in ascending or descending order.
Pay attention to the fact that there is no sense in declaring the parameter as a pointer to a std::vector<int>. The function would be much clearer and readable if it accepted the vector by reference instead:
void bubbleSort(std::vector<int> &L) {
In this case, the if statement would look like this:
if ( L[i] < L[i+1] ) {
Although I prefer to change the source code as other answer. But, for this question, you can use ->at() function to access the element in a vector pointer.
if(i<L->at(i)) {
temp = L->at(i+1);
L->at(i+1) = L->at(i);
L->at(i) = temp;
}
I recently started working with C++ for numerical computations where I want to use a Struct Operators to store 3D Fields over the course of the simulation.
I create the 3D arrays on the heap with
const unsigned int RES = 256;
auto arr3D = new double [RES][RES][RES];
because from what I've tested this approach is faster than using either Boost_multiarr, Eigen Tensor or nested Vectors.
So far this worked fine with my minimalistic Test.cpp but when I try to implement these same 3D Arrays as Members of my Struct Operators, I cannot use the auto command anymore:
const unsigned int RES = 256;
struct Operators {
public:
std::complex<double>*** wfc; // edited, see 'spitconsumers' comment
Operators(Settings &set) { // just another structure used by Operators
wfc = new std::complex<double> [RES][RES][RES];
// ...Initializing wfc using Settings
};
In this case I found no way of declaring wfc, such that I do not get errors of the type
error: cannot convert 'std::complex (*)[256][256]' to 'std::complex***' in assignment
So my question is how to correctly declare the 3D Array wfc and whether maintaining this Structure approach is at all possible/useful. Would it generally be faster to access the wfc[i][j][k] if wfc was not member of a structure? (I will have to do this ~10^6 times)
Thanks in advance!
The error message returns the correct declaration, std::complex<double>(*wfc)[RES][RES];.
const unsigned int RES = 256;
struct Settings {};
struct Operators {
public:
std::complex<double>(*wfc)[RES][RES]; // edited, see 'spitconsumers' comment
Operators(Settings& set) { // just another structure used by Operators
wfc = new std::complex<double>[RES][RES][RES];
// ...Initializing wfc using Settings
// Setting the last element
wfc[254][254[254] = 42;
};
}
In your error message, the compiler is telling you that new complex [RES][RES][RES] is returning the type std::complex (*)[256][256].
double wfc should be std::complex*** wfc.
Class member types must be known, and since you are not initialising the member variable while it is being defined, the compiler cannot deduce the type of the variable, which is why auto doesn't work as a class member type, when you aren't immediately assigning something to it. But you are assigning the value directly to the variable in your test program, allowing the compiler to deduce the type there.
Also, the new operator is returning a pointer to an array of uninitialised std::complex<double>** pointers. You need to call new for all of the uninitialised pointers.
std::complex<double>*** wfc;
wfc = new std::complex<double>** [RES];
for(int i = 0; i < RES; i++) {
wfc[i] = new std::complex<double>* [RES];
for(int j = 0; j < RES; j++) {
wfc[i][j] = new std::complex<double> [RES];
for(int k = 0; k < RES; k++) {
wfc[i][j][k] = /* insert default value here */;
}
}
}
I am still perfecting the art of posting here so bear with me, I will edit and fix anything suggested!
I have a homework that requires me to create functions that manipulate vectors. The "catch" is that all the data passed to the function is passed by reference to this struct:
struct Vector { // this struct must stay as is
int sze = 0; // "size" took out i for compatability
int capacity = 0;
int * data = nullptr ;
}a,b,c;
i.e.
void construct_vector ( Vector& v, int size= 0, int initVal= 0);
The problem that I am having is in the function construct_vector() I have to, you guessed it, construct a vector and use int* data to point to the vector on the heap? I am not positive about that last part). I just know I have to use the int pointer to point to the vector created within the construct function, and cannot for the life of me figure out how to do that.
An example of what I am trying:
void construct_vector ( Vector &v, int size, int initVal){
std::vector<int> t(size,initVal);
*v.data = &t ; // ERROR: Assigning to 'int' from incompatible type 'std::vector<int> *'
v.capacity = size; //
v.sze = size;
for (int i=0; i < t.size(); i++){
/* I originally tried to implement a
dynamic int pointer here but I cannot change int* data
to int*data[sze] within the struct*/
}
}
The reason int * data must point to the vector is because the data is passed to the subsequent functions by reference to struct member v:
void destroy_vector ( Vector & v );
void copy_data ( Vector & v );
Edit: My problem was that I misunderstood the objective of my assignment but I think the answers I received can really help people understand dynamic memory and how it should be used within functions. So I am going to leave everything as is!
You have two problems here:
std::vector<int> t(size,initVal);
*v.data = &t ; // ERROR: Assigning to 'int' from
First, *v.data and &t are different types, one is int, the other is a pointer to a vector of ints.
You can get it compile with (but you SHOULD NOT, see the second problem)
v.data = t.data();
The other problem is the vector is local to the function. As soon as the function returns, your pointer will dangle.
So the right solution for your problem is using a dynamic array:
v.data = new int[size];
Don't forget to delete[] it in the struct's destructor when you are done using it:
delete [] data;
Instead of
std::vector<int> t(size,initVal);
*v.data = &t ;
You need
v.data = new int[size];
To fill up the object with the input value, use
for ( int i = 0; i < size; ++i )
{
v.data[i] = initVal;
}
You can use std::fill to make your code a bit simpler.
std::fill(v.data, v.data+size, initVal);
Make sure to follow The Rule of Three when you manage dynamic memory yourself.
I am trying to return an array Data Member from one smaller 2D Array Object, and trying to insert the array into a larger 2D array object. But when attempting this, I came into two problems.
First problem is that I want to return the name of the 2D array, but I do not know how to properly syntax to return 2D Array name.
This is what my 2D Array data member looks like
private:
int pieceArray[4][4];
// 2D Smaller Array
and I want to return this array into a function, but this one causes a compiler error:
int Piece::returnPiece()
{
return pieceArray; //not vaild
// return the 2D array name
}
I tired using this return type and it worked:
int Piece::returnPiece()
{
return pieceArray[4][4];
}
But I am unsure if this is what I want, as I want to return the array and all of it's content.
The other problem is the InsertArray() function, where I would put the returnPiece() function in the InsertArray()'s argument.
The problem with the InsertArray() is the argument, heres the code for it:
void Grid::InsertArray( int arr[4][4] ) //Compiler accepts, but does not work
{
for(int i = 0; i < x_ROWS ; ++i)
{
for (int j = 0; j < y_COLUMNS ; ++j)
{
squares[i][j] = arr[i][j];
}
}
}
The problem with this is that it does not accept my returnPiece(), and if i remove the "[4][4]", my compiler does not accept.
Mostly all these are syntax errors, but how do I solve these problems?
Returning the whole pieceArray in returnPiece()
The correct syntax for the argument in InsertArray()
The argument of InsertArray() accepting the returnPiece()
These 3 are the major problems that I need help with, and had the same problem when I attempt to use the pointer pointer method. Does anyone know how to solve these 3 problems?
When passing your array around, you have to decide whether or not you want to make a copy of the array, or if you just want to return a pointer to the array. For returning arrays, you can't (easily) return a copy - you can only return a pointer (or reference in C++). For example:
// Piece::returnPiece is a function taking no arguments and returning a pointer to a
// 4x4 array of integers
int (*Piece::returnPiece(void))[4][4]
{
// return pointer to the array
return &pieceArray;
}
To use it, call it like so:
int (*arrayPtr)[4][4] = myPiece->returnPiece();
int cell = (*arrayPtr)[i][j]; // cell now stores the contents of the (i,j)th element
Note the similarity between the type declaration and using it - the parentheses, dereferencing operator *, and brackets are in the same places.
Your declaration for Grid::InsertArray is correct - it takes one argument, which is a 4x4 array of integers. This is call-by-value: whenever you call it, you make a copy of your 4x4 array, so any modification you make are not reflected in the array passed in. If you instead wanted to use call-by-reference, you could pass a pointer to an array instead:
// InsertArray takes one argument which is a pointer to a 4x4 array of integers
void Grid::InsertArray(int (*arr)[4][4])
{
for(int i = 0; i < x_ROWS; i++)
{
for(int j = 0; j < y_COLUMNS ; j++)
squares[i][j] = (*arr)[i][j];
}
}
These type declarations with pointers to multidimensional arrays can get really confusing fast. I recommend making a typedef for it like so:
// Declare IntArray4x4Ptr to be a pointer to a 4x4 array of ints
typedef int (*IntArray4x4Ptr)[4][4];
Then you can declare your functions much more readable:
IntArray4x4Ptr Piece::returnPiece(void) { ... }
void Grid::InsertArray(IntArray4x4Ptr arr) { ... }
You can also use the cdecl program to help decipher complicated C/C++ types.
It seems like you need to read up more on pointers in C++ and on pass by reference vs. pass by value.
Your returnPiece method is defined as returning the value of a single cell. Given the index (e.g., [4][4]) you return a copy of the contents of that cell, so you won't be able to change it, or more correctly, changing it would change the copy.
I'm sure someone will give you the correct syntax, but I would really recommend learning this stuff since otherwise you may use the code that you do get incorrectly.
Here is how I would do it:
class Array {
public:
Array() {
for (int i = 0; i < 4; ++i)
{
for (int j = 0; j < 4; ++j)
{
(*this)(i, j) = 0;
}
}
}
int &operator()(int i, int j)
{
return pieceArray[i][j];
}
private:
int pieceArray[4][4];
};
You can then do something like:
Array x; // create 4x4 array
x(1, 2) = 3; // modify element
Trouble with Adam Rosenfield's arrayPtr in that Piece::pieceArray can change out from under you. (Copy-by-reference vs Copy-by-value.)
Copy-by-value is inefficient. But if you really want to do it, just cheat:
struct FOO { int piece [4][4]; };
FOO Piece::returnPiece()
{
FOO f;
memcpy( f.piece, pieceArray, sizeof(pieceArray) );
return f;
}
void Grid::InsertArray( const FOO & theFoo )
{
// use theFoo.piece[i][j]
}
Of course, a better, more Object-Oriented solution, would be to have returnPiece() create and return a Piece or Array object. (As Juan suggested...)
I am trying to return an array Data Member from one smaller 2D Array Object, and trying to insert the array into a larger 2D array object. But when attempting this, I came into two problems.
First problem is that I want to return the name of the 2D array, but I do not know how to properly syntax to return 2D Array name.
This is what my 2D Array data member looks like
private:
int pieceArray[4][4];
// 2D Smaller Array
and I want to return this array into a function, but this one causes a compiler error:
int Piece::returnPiece()
{
return pieceArray; //not vaild
// return the 2D array name
}
I tired using this return type and it worked:
int Piece::returnPiece()
{
return pieceArray[4][4];
}
But I am unsure if this is what I want, as I want to return the array and all of it's content.
The other problem is the InsertArray() function, where I would put the returnPiece() function in the InsertArray()'s argument.
The problem with the InsertArray() is the argument, heres the code for it:
void Grid::InsertArray( int arr[4][4] ) //Compiler accepts, but does not work
{
for(int i = 0; i < x_ROWS ; ++i)
{
for (int j = 0; j < y_COLUMNS ; ++j)
{
squares[i][j] = arr[i][j];
}
}
}
The problem with this is that it does not accept my returnPiece(), and if i remove the "[4][4]", my compiler does not accept.
Mostly all these are syntax errors, but how do I solve these problems?
Returning the whole pieceArray in returnPiece()
The correct syntax for the argument in InsertArray()
The argument of InsertArray() accepting the returnPiece()
These 3 are the major problems that I need help with, and had the same problem when I attempt to use the pointer pointer method. Does anyone know how to solve these 3 problems?
When passing your array around, you have to decide whether or not you want to make a copy of the array, or if you just want to return a pointer to the array. For returning arrays, you can't (easily) return a copy - you can only return a pointer (or reference in C++). For example:
// Piece::returnPiece is a function taking no arguments and returning a pointer to a
// 4x4 array of integers
int (*Piece::returnPiece(void))[4][4]
{
// return pointer to the array
return &pieceArray;
}
To use it, call it like so:
int (*arrayPtr)[4][4] = myPiece->returnPiece();
int cell = (*arrayPtr)[i][j]; // cell now stores the contents of the (i,j)th element
Note the similarity between the type declaration and using it - the parentheses, dereferencing operator *, and brackets are in the same places.
Your declaration for Grid::InsertArray is correct - it takes one argument, which is a 4x4 array of integers. This is call-by-value: whenever you call it, you make a copy of your 4x4 array, so any modification you make are not reflected in the array passed in. If you instead wanted to use call-by-reference, you could pass a pointer to an array instead:
// InsertArray takes one argument which is a pointer to a 4x4 array of integers
void Grid::InsertArray(int (*arr)[4][4])
{
for(int i = 0; i < x_ROWS; i++)
{
for(int j = 0; j < y_COLUMNS ; j++)
squares[i][j] = (*arr)[i][j];
}
}
These type declarations with pointers to multidimensional arrays can get really confusing fast. I recommend making a typedef for it like so:
// Declare IntArray4x4Ptr to be a pointer to a 4x4 array of ints
typedef int (*IntArray4x4Ptr)[4][4];
Then you can declare your functions much more readable:
IntArray4x4Ptr Piece::returnPiece(void) { ... }
void Grid::InsertArray(IntArray4x4Ptr arr) { ... }
You can also use the cdecl program to help decipher complicated C/C++ types.
It seems like you need to read up more on pointers in C++ and on pass by reference vs. pass by value.
Your returnPiece method is defined as returning the value of a single cell. Given the index (e.g., [4][4]) you return a copy of the contents of that cell, so you won't be able to change it, or more correctly, changing it would change the copy.
I'm sure someone will give you the correct syntax, but I would really recommend learning this stuff since otherwise you may use the code that you do get incorrectly.
Here is how I would do it:
class Array {
public:
Array() {
for (int i = 0; i < 4; ++i)
{
for (int j = 0; j < 4; ++j)
{
(*this)(i, j) = 0;
}
}
}
int &operator()(int i, int j)
{
return pieceArray[i][j];
}
private:
int pieceArray[4][4];
};
You can then do something like:
Array x; // create 4x4 array
x(1, 2) = 3; // modify element
Trouble with Adam Rosenfield's arrayPtr in that Piece::pieceArray can change out from under you. (Copy-by-reference vs Copy-by-value.)
Copy-by-value is inefficient. But if you really want to do it, just cheat:
struct FOO { int piece [4][4]; };
FOO Piece::returnPiece()
{
FOO f;
memcpy( f.piece, pieceArray, sizeof(pieceArray) );
return f;
}
void Grid::InsertArray( const FOO & theFoo )
{
// use theFoo.piece[i][j]
}
Of course, a better, more Object-Oriented solution, would be to have returnPiece() create and return a Piece or Array object. (As Juan suggested...)