Hello I am dealing with nested structs and arrays in C++, here is some background info:
struct Cells // a collection of data cells lines
cells :: [Cell] // the cells: a location and a value
nCells :: Integer // number of cells in the array
capacity :: Integer // maximum size of the array end
struct Cell
location :: int // a location of data cells lines
value :: int // the value end Cells
The code I have which won't compile (3 files, header, ADT implementation, main)
How am I declaring the nested struct in struct array wrong?
// Defines the cell.h ADT interface
struct Cell;
struct Cells;
struct Cells {
Cell cells[];
int nCells;
int capacity;
};
struct Cell {
int location;
int value;
};
//fill cells with random numbers
void initialize(Cells *rcells);
ADT Implementation
using namespace std;
#include <iostream>
#include <cstdlib>
#include "cell.h"
void initialize(Cells *rcells){
for(int i = 0 ; i < rcells->nCells; i++)
{
rcells->cells[i].location = rand() % 100;
rcells->cells[i].value = rand() % 1000;
}
}
main
using namespace std;
#include <iostream>
#include <cstdlib>
#include "cell.h"
int main(){
Cells *c;
c->cells[0].location=0;
c->cells[0].value=0;
c->cells[1].location=0;
c->cells[1].value=0;
c->nCells = 2;
c->capacity = 2;
initialize(c);
}
Your original declaration fails because in
struct Cells {
Cell cells[];
int nCells;
int capacity;
};
"cells" defined in this way is an array, which should have fixed size (unless it is the last member and you're using C99 standard). You may think it is the same as
Cell* cells
but it won't be converted to pointer type automatically in struct definition.
The C++ way to do such things is
typedef std::vector<Cell> Cells;
Your initialize function could be
void initialize(int ncell, Cells& cells) {
cells.resize(ncell);
for (Cell& cell : cells)
{
cell.location = rand() % 100;
cell.value = rand() % 1000;
}
}
Your main program should change a little bit
int main(){
Cells c;
initialize(2, c);
c[0].location=0;
c[0].value=0;
c[1].location=0;
c[1].value=0;
}
If you want cell count information, you can call
c.size()
There is no need for capacity variable because there is no upper limit on total number of cells.
By the way, this is not the nested struct people usually talk about. When one say nested struct, he often means nested struct definition. There is nothing special about an object containing other objects.
Unlike some other programming languages, when you declare an array in C or C++, it is created where you declare it. For example if you declare one as a function local variable, it will be created on the stack.
In you case Cell cells[]; declares an array that must be created within your class. Thus if you class have an array of four elements, the compiler needs to allocate to each instance 4*sizeof(Cell) bytes for the field so it can fit the array in the instance. If your array have 524 elements, it needs 524*sizeof(Cell) bytes.
You see the problem here : the compiler cannot guess what is the size of your object. Which is problematic to obtain the location of each field in an instance, especially if you declare two array without size. Note that this issue is not restricted to object fields : you cannot declare an array as a local variable in a function without giving a size either, for example. This because array have a fixed size determined upon creation. Thus wherever you create the array, you must provide its size.
When you write Cell array[] as a function argument, you are not creating an array, but only obtaining a pointer to it, so not giving its size is okay.
To solve your issue you must somehow make classes with a constant size. For example you can allocate you array dynamically with new[some_variable] and use pointer Cell *cells; in your class. A pointer has a fixed size, and you array is to be declared on the heap (don't forget to delete[] it).
Remark: instead of a size, giving an array initializer only is valid :
int x[] = {1, 2, 4}; //creates an array of three elements
Related
I am pretty new to this but I am trying to create a class that declares an int array as an attribute.
DataHousing.h
class DataHousing {
private:
// ATTRIBUTES
int fileContents[count];
int count;
DataHousing.cpp
// CLASS METHOD IMPLEMENTATIONS
#include "DataHousing.h"
// CONSTRUCTORS
DataHousing::DataHousing() {
this->fileContents = NULL;
this->count = 0;
}
The array will vary in size depending on the amount of numbers that are contained in a separate file. So, one file will be read in and stored in an array using dynamic memory which may have 500 different numbers. But, another file may be read in that has 100,000 different numbers.
I have a method in the class that will count the numbers in each file and then populate the count variable.
How do I initialize the array if I do not know what the size will be?
I am struggling to figure out how to declare a 2D Array as a global variable so i can use it in all of my methods. So far it is only declared in a single method hence why it cannot be used in other methods.I have figured out how to declare a normal string array by just typing string* array = new string[1] at the start of my code before the methods (i then alter the size of this array later on based of a variable) but i am unsure how to do it with a 2D array:
void WordSearch::ReadSimplePuzzle()
int columns = 9;
int rows = 9;
string **simple2DArray = new string*[columns];
for (int i = 0; i < columns; i++)
simple2DArray[i] = new string[rows];
//code that populates the array too long to post but not relevant.
I then have a method later on where i need to access the simple2DArray but i cannot figure out how to define it at the start of the code any help would be appreciated.
If you columns and rows variables never change, you can do this:
const int columns = 9;
const int rows = 9;
string simple2DArray[columns][rows];
By statically allocating the memory, you now don't have to worry about freeing it.
Since you clarified that the size is not known until run-time, you will not be able to allocate the memory statically. A very simple solution would be:
std::vector<std::vector<std::string>> simple2DArray; // This will have size 0 at start
Then, in your initialization step, just do this:
simple2DArray.resize(rows);
for (auto& row : simple2DArray)
{
row.resize(columns);
}
There are other ways to do this, of course, such as allocating all the memory in one block of size rows*columns and then exposing it as if it were a 2-d matrix but that might be overkill for your purposes.
My suggestion is hide the array behind a functional interface.
std::string const& getElement(size_t m, size_t n);
void setElement(size_t m, size_t n, std::string const& val);
The calling functions have the abstractions of a 2D array but they don't need to know how the it is represented in code.
In the implementation, you have various options:
Use a 1D array. Map the 2D indices to the right index in the 1D array.
Use a std::vector. Still need to map the indices.
Use a 2D array. No mapping of indices needed.
Use a std::vector<std::vector<std::string>>. No mapping of indices needed.
I am struggling to figure out how to declare a 2D Array as a global
variable so i can use it in all of my methods.
As with any global var, you need to declare your pointer in global space:
string **simple2DArray;
and then you can assign to it from inside your method
simple2DArray = new string*[columns];
If you are asking this for making it easier to solve competitive programming problems, then look at the constraints given in the question. For example if the matrix can be an N*N with 1 <= N <= 1000 Then you can globally declare int arr[1000][1000];
Here's some code for a better idea.
//global declarations
int N;
int arr[1000][1000];
int functionA()
{
// some code
}
int functionB()
{
// some code
}
int main()
{
// Get the input of both N and your array arr
// Now you can use them in any where in your code
}
I have a double pointer Array of a structure:
typedef struct Position{
int x;
int y;
} Position;
Position** array = (Position**)malloc(sizeof(Position*)*10); //10 elements
array[0] = (Position*)malloc(sizeof(Position*));
array[0]->x = 10;
array[0]->y = 5;
Can I calculate the length of set array and if so, how?
The normal way for arrays does not work :
int length = sizeof(<array>)/sizeof(<array>[0]);
Once you have dynamically allocated an array, there is no way of finding out the number of elements in it.
I once heard of some hacky way to obtain the size of a memory block, (msize) which would allegedly allow you to infer the size of the data within the block, but I would advice against any such weird tricks, because they are not covered by the standard, they represent compiler-vendor-specific extensions.
So, the only way to know the size of your array is to keep the size of the array around. Declare a struct, put the array and its length in the struct, and use that instead of the naked array.
As you marked the question as C++, I would suggest that you use std::vector, then, after you "allocated some memory" (or requested some memory to allocated by std::vector constructor or by using push_back, or resize), you can simply get the size back using by using std::vector::size.
typedef struct Position{
int x;
int y;
} Position;
std::vector<Position> array(10);
array[0].x = 10;
array[0].y = 5;
size_t size = array.size(); // will be 10
Having only a pointer to some memory block, you cannot defer the size of this memory block. So you cannot defer the number of elements in it.
For arrays of pointers, however, you could infer the number of elements in it under the following conditions:
make sure that every pointer (except the last one) points to a valid object.
for the last pointer in the array, make sure that it is always NULL.
Then you can derive the length by counting until you reach NULL.
Maybe there are some other similar strategies.
Solely from the pointer itself, however, you cannot derive the number of elements in it.
Old question, but in case someone needs it:
#include <stdio.h>
...
int main()
{
char **double_pointer_char;
...
int length_counter = 0;
while(double_pointer_char[length_counter])
length_counter++;
...
return 0;
}
I have a static integer variable Game::numPlayers, which is read in as an input from user. I then have the following class defined as such:
class GridNode
{
private:
/* Members */
static const int nPlayers = Game::numPlayers;
std::vector<Unit> units[nPlayers];
//...
};
This won't compile ("in-class initializer for static data member is not a constant expression").
I obviously cant just assign the array size of Game::numPlayers, and I also tried not initializing it and letting a constructor do the work, but that didn't work either.
I don't understand what I'm doing wrong here and what else I could possibly do to get this to work as intended.
I'm just copying a value, how is that any different from static const int nPlayers = 8 which copies the value 8 into nPlayers and works?
Edit:
To clarify, I choose to have an array of vectors because I want each node to have a quick-access container of units, but one container for each user/player so as to distinguish which units belong to which player within each node (e.g. index 0 of the array = player 1, index 1 = player 2, index 2 = player 3, and so on), otherwise I would just have one vector or a vector of vectors. I thought a map might work, but I thought an array of vectors would be faster to access and push into.
Also, Game::numPlayers is read in as a user input, but only read and assigned once within one game loop, but if I close/restart/play a new game, it needs to read in the user input again and assign it once.
I don't see why you need to use an array of std::vector if the number of elements will be obtained at runtime.
Instead, create a std::vector<std::vector<Units>> and size it appropriately on construction. if you need to reset the size, have a member function resize the vector.
Example:
class GridNode
{
private:
/* Members */
std::vector<std::vector<Unit>> units;
public:
GridNode(int nPlayers=10) : units(nPlayers) {}
std::vector<Unit>& get_units(size_t player)
{ return units[player]; } // gets the units for player n
void set_num_players(int nPlayers)
{ units.resize(nPlayers); } // set the number of players
int get_num_players() const { return units.size(); }
};
int main()
{
int numPlayers;
cin >> numPlayers;
//...
GridNode myGrid(numPlayers); // creates a GridNode with
// numPlayers vectors.
//...
Unit myUnit;
myGrid.get_units(0).push_back(myUnit); // places a Unit in the
// first player
}
Also, it isn't a good idea to have extraneous variables tell you the vector's size. The vector knows its own size already by calling the vector::size() function. Carrying around unnecessary variables that supposedly gives you this information opens yourself up for bugs.
Only integral constant expressions are allowed as array sizes in array declarations in C++. A const int object initailized with something that is not an integral constant expression (your Game::numPlayers is not, since it is read from the user), does not itself qualify as integral constant expression.
The bottom line here is that regardless of how you slice it, it is not possible to sneak in a run-time value into an array declaration in C++. C++11 does support some semblance of C99-style Variable Length Arrays, but your case (a member array) is not covered by it anyway.
If the array size is a run-tuime value, use std::vector. In your case that would become std::vector of std::vectors.
I created a pointer to pointer to a dynamic vector, is called "list".
listaFiguras::listaFiguras(){
numElements = 0;
list = new figuraGeom* [numElements];
}
Here is my class too:
class listaFiguras {
//Atributos
int numElements;
figuraGeom **list;
public :
//Constructor sin parametros
listaFiguras();
//Destructor
~listaFiguras();
//Sets y Gets
void setnumElementos(int);
virtual void setLista(figuraGeom**);
int getnumElementos();
virtual figuraGeom* getLista();
//Vaciar lista
void vaciarLista();
//AƱadir elemento
void anyadirElemento(figuraGeom *);
};
Now I have to create a method called anyadirElemento but do not understand how I can do this:
Take as a parameter a pointer to figuraGeom, and added at the end of the dynamic array pointed to by list.
I got this:
void listaFiguras :: anyadirElemento (figuraGeom * parameter) {
}
Any help will be appreciated, Thanks!
It would be simpler if instead of the dynamically allocated array you would use std::vector<figuraGeom *>
You have to keep the current position in the array that to know where to add a new value. For example let assume that you defined such data member of the class
int position;
and initialized it to zero some way (for example in a constructor of the class)
Then the function could look the following way provided that the array may not be reallocated
void listaFiguras :: anyadirElemento (figuraGeom * parameter)
{
if ( position < numElements ) list[position++] = parameter;
}
So I would define data members of the class as
class listaFiguras {
//Atributos
int numElements;
int position;
figuraGeom **list;
//...
If you are allowed to enlarge the initially allocated array then the function should reallocate it each time if position is equal to numElements where numElements also will be changed or you should keep another variable that will store the current size of the array.
A very simple dynamic array is define as follow:
array size
pointer to array
You need to know how many elements are currently in the array to be able to use them; and when adding/removing an element you simply create another array with one less or one more element (which involves copying the old array into the new).
Note: this is extremely inefficient adding an element is O(N) where N is the number of elements already in the array but it's also very simple, in real code use std::vector<T> which performs addition at the end in amortized O(1).