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).
Related
Not exactly sure how to word the title but I'll explain as best I can.
I have a program that originally used a 2D array of a set size and so it was defined as:
typedef char Map[Row][Col];
I'm now trying to dynamically allocate memory for it and it has now also become of variable size based on input. It's now defined as:
typedef char** Map;
In my main method, I originally had:
Map map;
readUserInput(map);
Basically readUserInput takes the map array as a parameter, and assigns values to it based on user input. The map then contains values and is used in other functions.
I've updated the readUserInput function so that it dynamically sizes the array and it allocates/deallocates memory for it. This works fine, but the problem comes from the fact that now in the main method, map is not being updated. The above code in main now looks like:
Map map = nullptr;
readUserInput(map);
but after running the readUserInput function, map is still null. Inside of the function, map is updated fine, so I'm not understanding the difference made between the changes.
What you pass to function is a pointer to array and fuction can't change it. But replacing array with pointer to pointer is incorrect in most case.Pointer to pointer suggest that have a 1D array of pointers. Which may (or may not) point to other arrays. Such data organization sometimes referred to as jagged arrays, because it allows each row to be of separate length. But on practtice jagged arrays and their subclass, sparse matrices, usually implemented as 1D array to avoid re-allocation.
To avoid decaying and to actually store a monolithic array in memory, you should use 1d array and, preferably, encapsulation for pointer arithmetic and reallocation, and then pass reference to object that stores all required states. Reference ensures that object is mutable by function ( a smart-pointer-less version for an example):
class Map
{
int rows, cols;
char *data;
public:
Map() : rows(), cols(), data(nullptr) {}
Map(int r, int c) : rows(r), cols(c), data(new char[r*c]()) {}
~Map() { delete[] data; }
void resize(int r, int c) {
if(rows == r && cols == c) return;
char* tmp = new char[r*c]();
if(data)
{
// copy old data here if required
delete[] data;
}
row = r; col = c;
data = tmp;
}
char& operator() (int r, int c) { return data[r*cols + c]; }
char operator() (int r, int c) const { return data[r*cols + c]; }
};
NB: this class requires a copy and move operations to be implemented if any copy must be allowed.
The function prototype would be:
void readUserInput(Map& map);
With such class you can do dynamic resizing, store its size, and address element as simple as this:
int main()
{
Map test(4, 5); // declaring and allocating memory
test.resize(3,3); // reallocating
test(1,1) = 3; // writing
//reading
std::cout << +test(1,1) << std::endl;
}
The function should accept the array by reference in the C terms like
readUserInput( &map );
when the function is declared like
void readUserInput( Map *map );
or in the C++ terms when the function is declared like for example
void readUserInput( Map &map );
and called like
readUserInput(map);
Instead of allocating dynamically arrays you could use the container std::vector<std::string>.
The code you have used is a pure C-style code, and is prone to many mistakes:
You use typedef instead of: using Map = char**;
You use a function which gets a pointer and fills it, which is more common in C than in C++.
You use raw pointer instead of smart pointers (added in C++11), which may cause a memory leak in the end.
I've updated the readUserInput function so that it dynamically sizes the array and it allocates/deallocates memory for it.
This means that now it should be a class named Map, since it should be able to allocate/deallocate, insert and remove values, and is a valid container. Actually, you are creating a type of std::vector here, and if you don't create it for you own learning process, I strongly suggest you to use the std containers!
It is possible to pass both pointer and references in C++, notice that:
You can pass a reference only if the value isn't nullptr.
When there should be a value, reference is recommended.
In this case, your function should look like
void readUserInput(Map* map);
and should be called using:
readUserInput(&map);
The scope of the program is to create a Container object which stores in a vector Class objects. Then I want to print, starting from a precise Class object of the vector all its predecessors.
class Class{
public:
Class(){
for (int i = 0; i < 10; ++i) {
Class c;
c.setName(i);
if (i > 0) {
c.setNext(_vec,i-1);
}
_vec.push_back(c);
}
}
};
~Class();
void setName(const int& n);
void setNext( vector<Class>& vec, const int& pos);
Class* getNext();
string getName();
void printAllNext(){ //print all next Class objects including himself
cout << _name <<endl;
if (_next != nullptr) {
(*_next).printAllNext();
}
}
private:
Class* _next;
string _name;
};
class Container{
public:
Container(){
for (int i = 0; i < 10; ++i) {
Class c;
c.setName(i);
if (i > 0) {
c.setNext(_vec,i-1);
}
_vec.push_back(c);
};
~Container();
void printFromVec(const int& n){//print all objects of _vec starting from n;
_vec[n].printAllNext();
};
private:
vector<Class> _vec;
};
int main() {
Container c;
c.printFromVec(5);
}
The problem is that all _next pointers of Class objects are undefined or random.
I think the problem is with this part of code:
class Container{
public:
Container(){
for (int i = 0; i < 10; ++i) {
Class c;
c.setName(i);
if (i > 0) {
c.setNext(_vec,i-1);
}
_vec.push_back(c);
};
Debugging I noticed that pointers of already created objects change their values.
What is the problem? How can I make it work?
Although there is really error in the code (likely wrong copypaste), the problem is really following: std::vector maintains inside dynamically allocated array of objects. It starts with certain initial size. When you push to vector, it fills entries of array. When all entries are filled but you attempt pushing more elements, vector allocates bigger chunk of memory and moves or copies (whichever you element data type supports) objects to a new memory location. That's why address of object changes.
Now some words on what to do.
Solution 1. Use std::list instead of std::vector. std::list is double linked list, and element, once added to list, will be part of list item and will not change its address, there is no reallocation.
Solution 2. Use vector of shared pointers. In this case you will need to allocate each object dynamically and put address into shared pointer object, you can do both at once by using function std::make_shared(). Then you push shared pointer to vector, and store std::weak_ptr as pointer to previous/next one.
Solution 3. If you know maximum number of elements in vector you may ever have, you can leave all as is, but do one extra thing before pushing very first time - call reserve() on vector with max number of elements as parameters. Vector will allocate array of that size and keep it until it is filled and more space needed. But since you allocated maximum possible size you expect to ever have, reallocation should never happen, and so addresses of objects will remain same.
Choose whichever solution you think fits most for your needs.
#ivan.ukr Offered a number of solutions for keeping the pointers stable. However, I believe that is the wrong problem to solve.
Why do we need stable pointers? So that Class objects can point to the previous object in a container.
Why do we need the pointers to previous? So we can iterate backwards.
That’s the real problem: iterating backwards from a point in the container. The _next pointer is an incomplete solution to the real problem which is iteration.
If you want to iterate a vector, use iterators. You can read about them on the cppreference page for std::vector. I don’t want to write the code for you but I’ll give you some hints.
To get an iterator referring to the ith element, use auto iter = _vec.begin() + i;.
To print the object that this iterator refers to, use iter->print() (you’ll have to rename printAllNext to print and have it just print this object).
To move an iterator backwards, use --iter.
To check if an iterator refers to the first element, use iter == _vec.begin().
You could improve this further by using reverse iterators but I’ll leave that up to you.
I'm learning C++ from a course on Udacity.
Can you explain to me why setGrades() was defined as a pass-by-pointer-to-value function? Why is there an error with passing by value? In the code below, I omitted the definition for printGrades() and setID().
#include<iostream>
using namespace std;
const int SIZE = 5;
template <class T>
class StudentRecord
{
private:
const int size = SIZE;
T grades[SIZE];
int studentId;
public:
StudentRecord(T defaultInput);
void setGrades(T* input);
void setId(int idIn);
void printGrades();
};
template<class T>
StudentRecord<T>::StudentRecord(T defaultInput)
{
for(int i=0; i<SIZE; ++i)
grades[i] = defaultInput;
}
template<class T>
void StudentRecord<T>::setGrades(T* input)
{
for(int i=0; i<SIZE;++i)
{
grades[i] = input[i];
}
}
int main()
{
StudentRecord<int> srInt(-1);
srInt.setId(111111);
int arrayInt[SIZE]={4,3,2,1,4};
srInt.setGrades(arrayInt);
srInt.printGrades();
return 0;
}
The output is supposed to be:
ID# 111111: 4
3
2
1
4
C++ does not allow passing builtin C-style arrays by value. One can pass an array by reference or pass a pointer to the first element of the array. Given such pointer, the entire array can be accessed.
Passing-by-pointer is not a usual term in the literature but people keep coining similar terms time and again, which shows some kind of genuine need. The idea behind the term is as follows: one passes a pointer by value but the goal is to let the function access the pointed-to object as an lvalue (which is normally achieved by passing that object by reference).
That's simply because it is an array you want to give to setGrades because you want to set all SIZE values of the array 'grades'.
As you know perhaps, the name of an array can be used like a pointer to the first value of that array.
For example you could write *arrayInt as a term which is equivalent to arrayInt[0].
So when you pass an pointer to the first element of the array to setGrades, the function can get the other elements of that array with arrayName[i] where i is in between 0 and SIZE.
You want to pass an array to setGrades, you can also define it like this:
void StudentRecord<T>::setGrades(T input[])
However the compiler will convert it to a T* pointer automatically.
Functions will always make its own copy of all parameters you gave during compilation (see: call by value). Right here it's an array, but the compiler can't assign an array to another immediately. The only way to do array assignment is to assign its element one by one (or copy the entire memory chunk of the array), and compiler won't do that. The compiler do know that you can access the entire array if you got a pointer of type T pointed to the first element of the array. It's the alternative way of passing the entire array.
And that is the most common way to pass an array to a function.
So I'm creating a closed-hashing hash table for a class and I have a structure
struct Example {
string key;
string data;
Example() { key = "000"; }
};
and a class which contains a member that points to a vector of structures, a constructor, and a function I'll be using to illustrate the problem.
class hash_table {
private:
vector<Example>* hash;
public:
hash_table(int size);
void dummy_method();
};
It is meant to dynamically allocate the number of structures in the vector based on user/file input.
hash_table :: hash_table ( int size=10 )
{
//initialize vector
vector<Example> * hash = new vector<Example>(size);
//test objects
for(int i=0;i<size;i++)
cout<<(*hash)[i].key<<endl;
}
the above code appears to initialize the 10 members, as it prints out "000"
ten times.
however, once I try this by calling dummy_method-
void hash_table::dummy_method() {
cout<<(*hash)[0].key<<endl;
}
I get a segmentation fault
I'm pretty sure this isn't even the correct way to do this, but I've been looking/tinkering forever and I can't seem to find a solution. I absolutely have to use a pointer to a vector of structures however, and I'm pretty sure I'm supposed to be dynamically allocating each of those structures as well (somehow). Thanks for any help.
(also, yes, we actually HAVE to use namespace, thus no std anywhere)
vector<Example> * hash = new vector<Example>(size); expression will initialize a local variable with name hash, not a hash_table::hash member (which is left uninitialized).
Hello I'm trying to create a genetic algorithm with C++ and I tried to use vector as the container the problem is I didn't know how to set the size of the vector because the vector have a class argument like this
class population
{
friend class chromosome;
private:
int population_number;
int best_index[2];
vector <chromosome *> chromosome_population;
public:
population(int numberOfPopulation);
population(int numberOfPopulation,int numberOfSynapse);
~population();
int worst_chromosome();
void mating();
void crossover(int parent_1,int parent_2);
};
this is the population class and here's the chromosome class
class chromosome
{
friend class population;
private:
int chromosome_id;
float fitness;
vector <gen *> gen_chromosome;
public:
chromosome();
~chromosome();
void fitness_function();
void mutation_translocation();
int get_chromosome_size();
};
how can I set the vector length in the population class constructor? I've tried to use vector.pushback and vector.resize but both will give me error because the argument doesn't match. Actually I'm understand why it become error but I didn't know how to match the argument inside the vector pushback here's my population constructor
population::population(int numberOfPopulation)
{
srand (time(NULL));
population_number = numberOfPopulation;
for(int a=0;a<population_number;a++)
{
chromosome_population.push_back();
}
cout<<chromosome_population.size();
for(int i=0;i<population_number;i++)
{
chromosome_population[i]->chromosome_id = i;
int chromosome_length = rand() % 10 + 1;
for(int j=0;j<chromosome_length;j++)
{
chromosome_population[i]->gen_chromosome[j]->basa_biner = rand()%1;
chromosome_population[i]->fitness = (rand()%99)+1;
}
}
}
If is there any other information you want you can tell me in the comment and I'll add the information you needed. Thanks before.
std::vector has several constructors and one of the variants accepts the initial number of elements to be stored in the vector.
Specify the size of the vector in the population constructor's initializer list:
population::population(int numberOfPopulation) :
population_number(numberOfPopulation),
chromosome_population(numberOfPopulation)
{
}
Give this approach, the population_number member variable is unnecessary as it can be obtained by chromosome_population.size().
Specifying an initial size on the vector will mean that it contains numberOfPopulation null pointers. Before accessing elements in the vector you need to create objects, in this case using new. If the elements are copyable and polymorphic behaviour is not required then recommend using vector<chromosome> instead. If you must use dynamically allocated elements in the vector then you must allocate first:
chromosome_population[i] = new chromosome();
and remember to delete when no longer required.
It also desirable to use a form of smart pointer instead of raw pointers. An advantage of using the smart pointer is that when the vector<unique_ptr<chromosome>> goes out of scope the elements will be destructed for you, without having to explicitly call delete on each of the elements. See What C++ Smart Pointer Implementations are available? for a useful listing of the available smart pointers.
Note that vector::push_back() accepts an argument, with same type as its element. So the correct invocation of push_back() is:
chromosome_population.push_back(new chromosome());
If you specify an initial size of the vector at construction, calling push_back() will add elements after the initial (null pointers in this case) elements in the vector.