Creating a Array of Nodes - c++

When we create a array of integers we do it like this:
int main() {
int x;
cout << "Enter size of array"
cin >> x;
int* myArray;
myArray = new int[x]
}
we assign the asterisks next to array, we are assigning it as a array of pointers right?
If I make a array of nodes where:
struct Node {
string Name;
int Age;
}
I ran some code to experiment with it and understand it more and I tried to do just like the array sample but create a array with nodes.
int main() {
Node* sumShit[5];
Node* America = new Node();
America->age = 16;
America->Name = "America";
sumShit[0] = America;
Node* Japan = new Node();
Japan->age = 15;
Japan->Name = "Japan";
sumShit[1] = Japan;
cout << "[" << sumShit[1]->Name << ", " << sumShit[1]->age << "]";
}
Everything printed out fine with pointers but then I did it also without pointers, where I just stored node properties in the Node:
Node myNodeShit[5];
Node Poop;
Poop.age = 16;
Poop.Name = "Poop";
myNodeShit[0] = Poop;
sortArrayName(myNodeShit, 5);
printArray(myNodeShit, 5);
And this also worked, however whats the advantages to using pointers and just storing it within the node. When it comes to algorithms, sorting and using memory, is there a preferred way. Im trying to figure why it would be better to have it as a array of pointers to nodes vs a array of nodes.

Using pointers allows for greater flexibility in updating / modifying existing data because the data is only declared once in memory. From here, you can use pointers to make changes from anywhere in your code.
Additionally, using pointers conserves memory whereas creating the actual nodes will make copies of said node. This becomes apparent when you're passing the array into a function. In this case the array of nodes (without pointers) becomes a local copy pushed onto the call stack. When the function returns, you'll lose any modification you made to the node. Conversely, using pointers will save the node's state.
When in doubt, try to use pointers where you can.

Related

Appending struct by reference to an array in C++

How can I implement a function in C++ that appends a struct instance to an array by reference? So that after appending a struct stored in a variable to the array, this variable can be used further to change the instance of array.
pseudocode:
struct St{
int x
}
St* arr;
St a = {0};
append a to arr;
a.x = 1;
//expecting arr[0].x = 1
Here is the C++ code with the film example (see comments describing the problem):
struct Film{
int id;
char* name;
};
void add_film(Film *&films, int &size, Film &film){
if (size == 0)
films = new Film[1];
else
{
Film *tmp = new Film[size + 1];
for (int i = 0; i < size; ++i)
{
tmp[i] = films[i];
}
delete[]films;
films = tmp;
}
films[size] = film;
film = films[size]; //how to reassign passed film object to a new object in array?
size++;
}
int main(){
Film *films = nullptr;
int size = 0;
Film film = {1, "Name1"};
add_film(films, size, film);
film.name = "Name2";
std::cout << films[0].name; //output: "Name1", expected: "Name2"
}
Appending struct by reference to an array in C++
There are two problems with this:
There cannot be arrays of references in C++.
There is no way to append to an array. The size of an array is a constant. There is no way to add or remove elements.
An issue with your attempted solution is that you have an array of Films, and not an array of references. This isn't very surprising, as problem 1 described above states there are no such thing as arrays of references. The solution is simple however: Use pointers instead of references. Technically, you could use a reference wrapper instead, but a pointer is often simpler.
You've basically figured out the solution to 2. already. What you're doing is creating a new array, copying the old elements from the old array into the new one, and destroying the old array. That's a good approach in general, but there are a number of problems with this trivial implementation:
Bare owning pointers are unsafe and hard to use.
Reallocating and copying the entire array on every append is very expensive.
Former can be solved by using the RAII idiom, and latter can be solved by separating the storage of the objects from the creation of the objects, and by growing the storage by a constant factor i.e. geometrically. There is no need to implement such RAII container though, since the standard library has you covered. It's called std::vector.
In conclusion: You can use std::vector<Film*>.

Private array of adjacent node addresses in C++

////EDIT #2: Deleted all the previous info and just post the working code now. Previous question became too lengthy:
#include <iostream>
#include <vector>
using namespace std;
template<class T>
class Node{
T data;
vector<Node<T>*> adjacent;
friend class Graph;
public:
int n;
Node(T initData) : data(initData), n(0){}
void addAdjacent(Node<T>& other){
adjacent.push_back(&other);
n++;
}
T getData(){
return data;
}
Node<T>* getEdge(int edgeNum){
return adjacent[edgeNum];
}
};
template<class T>
class GraphCl{
int n;
vector<Node<T>*> nodes;
T input;
public:
GraphCl(int size): n(size){
for (int i=0;i<n;i++){
cout << "Enter data for node " << i << ": ";
cin >> input;
nodes.push_back(new Node<T>(input)) ;
}
}
void addEdge(int baseNode, int edgeNode){
nodes[baseNode]->addAdjacent(*nodes[edgeNode]);
}
void printGraph(){
for (int i=0;i<n;i++){
Node<T> *base = nodes[i];
cout << "Data of node " << i <<": "<< base->getData() <<endl;
for (int j=0;j<base->n;j++){
cout << "Edge #"<< j+1 << " of node " << i << ": " << base->getEdge(j) <<endl;
}
}
}
};
int main(){
GraphCl<int> *myGraph = new GraphCl<int>(5);
myGraph->addEdge(0,1);
myGraph->addEdge(0,2);
myGraph->addEdge(0,3);
myGraph->addEdge(0,4);
myGraph->addEdge(3,1);
myGraph->addEdge(3,0);
myGraph->printGraph();
return 0;
}
Output:
Enter data for node 0: -34
Enter data for node 1: 12
Enter data for node 2: 56
Enter data for node 3: 3
Enter data for node 4: 23
Data of node 0: -34
Edge #1 of node 0: 0x7fbeebd00040
Edge #2 of node 0: 0x7fbeebd00080
Edge #3 of node 0: 0x7fbeebe00000
Edge #4 of node 0: 0x7fbeebd000d0
Data of node 1: 12
Data of node 2: 56
Data of node 3: 3
Edge #1 of node 3: 0x7fbeebd00040
Edge #2 of node 3: 0x7fbeebd00000
Data of node 4: 23
As you can see this simple implementation is working. I decided to just cut out all the complicated stuff and keep it simple with dynamically changing vectors. Obviously less efficient but I can work from here on. Since I am new with C++ the previous implementation just got my head spinning 360 degrees thinking about where all the pointers to pointers went, without even thinking about memory allocation. The above code basically is a directed graph that is very sensitive to input errors, so I got to work on it still.
Thanks for all the help!
Accessibility
Regarding the accessibility of the array to the Graph, the closest thing to the current implementation is to declare declare Graph as a friend of Node. Simply add:
friend Graph;
To the end of the Node class declaration.
That said, making a class as a friend is sometimes a sign that the API you defined isn't exactly right if classes need to know too much about each others' implementation details. You can alternatively provide an interface for Node such as:
void AddAdjacent(Node* other);
Managing Adjacent Nodes
If you want your adjacent pointer array to be growable, then you are basically re-creating std::vector, so I would suggest using std::vector<Node*>. Initializing a vector with the default (empty) constructor would take care of it, and a nodes[baseNode]->adjacent.push_back(...) would be all you need in addEdges.
If memory is not a consideration and you have a maximal number of nodes in the graph, you can instantiate a constant-sized array.
If you really don't want to use std::vector, but you actually want a growable array of pointers, then you'll have to manage your own malloc and free calls. I'll write something up to that effect, but my advice is to just go ahead with vector.
In case you are curious, the array approach would look something like:
template<class T>
class Node : public Graph{
Node **adjacent; //pointer to array of POINTERS TO adjacent Nodes
int n;
size_t capacity;
T data;
friend Graph;
public:
Node(T initData) : data(initData), capacity(8) {
n = 0;
adjacent = reinterpret_cast<Node**>(malloc(capacity * sizeof(Node**)));
}
~Node() {
free(adjacent);
}
void Grow() {
size_t new_cap = base.capacity * 2;
Node<int> **copy = reinterpret_cast<Node<int>**>(malloc(new_cap * sizeof(Node**)));
memcpy(copy, base.adjacent, base.capacity); // copy and adjacent are non-overlapping, we can use memcpy
free(base.adjacent);
base.adjacent = copy;
base.capacity = new_cap;
}
};
And the insertion:
Node<T>& base = nodes[baseNode];
Node<T>* edge = &(nodes[edgeNode]);
if (base.capacity == base.n) base.Grow();
base.adjacent[base.n++] = edge;
Answering the updated question
There are a few issues with putting Nodes directly in a std::vector in your case.
Using a std::vector is great for many things, but if you are doing that, you should make sure not to take pointers to vectors. Remember, pointers refer to exact addresses in memory of where an object is stored. A vector is a growable container of elements. To store elements contiguously, the vector allocates a bunch of memory, puts objects there, and if it has to grow, it will allocate more memory and move the objects around. It is essentially doing something similar to what you are doing in your Node and grow (except, in its case, its explicitly destroying the objects before freeing the old memory).
Notice that your Grow function allocates new memory and copies the pointers. Simlarly, vectors can allocate new memory and copy the data over. This means that holding pointers to data in a vector is bad. The only guarantee a vector gives you is that its data will continue to be accessible using array-style indexing, find, iteration, etc., not that the data will exist in the same memory location forever.
Explaining the exact bug you are seeing
The vector is invoking a copy constructor. The default copy constructor copies every field one-by-one. This is not what you want in the case of Node, because then you have two vectors that think they own the Node** adjacent memory location. When the first node (the old copy) is being destroyed, it will free its adjacent nodes (which is the same as the copy's adjacent node). When the new copy is being destroyed, it will attempt to free that same memory location, but it is already freed. You also have the problem here that, if you attempted to access the memory after it has been destroyed in the first node, you'll be in trouble.
Why was this bug showing up when you were only adding nodes?
When a vector grows to a certain amount, it needs to resize. In most implementation, the process is roughly:
Allocate a bunch more memory (usually twice the old capacity)
Invoke the copy constructor to copy elements from the old location to the new location
Destroy the elements in the old location (say, by explicitly calling the destructor)
Insert the new element in the new location
Your bug is showing up because of steps 2 and 3, basically.
Fixing this particular bug
For your case, the default copy constructor is no good because copying a node should meet a deep copy of all of the data. A regular copy in C++ will copy all of the data on the class or struct itself. If the data is a pointer, then the pointer is copied, not the thing its pointing to.
Override the copy constructor and assignment operator:
Node(const Node<T>& other) : data(other.data), capacity(other.capacity), n(other.n) {
adjacent = reinterpret_cast<Node**>(malloc(capacity * sizeof(Node**)));
memcpy(adjacent, other.adjacent, capacity * sizeof(Node**));
}
Node<T>& operator= (const Node<T>& other) {
data = other.data;
capacity = other.capacity;
n = other.n;
adjacent = reinterpret_cast<Node**>(malloc(capacity * sizeof(Node**)));
memcpy(adjacent, other.adjacent, capacity * sizeof(Node**));
}
A Bigger Problem
A bigger problem with your code is that the use of an std::vector and pointers to its elements. Choose one of:
Use a fixed-sized array (which is stable in memory), and point to these objects
Forget about pointers altogether, and make your adjacent list a list of indices into the vector (its less performant as you need to go through the vector each time, but that likely won't be your bottleneck for now)

Linked Lists with vectors

I am trying to perform certain operations through linked lists on vectors.
We have been given a struct type vector
typedef struct{
int *array; // a pointer to vector's storage
int size; // the current number of elements in the vector
int cap; // the current capacity of the vector;
int init_cap; // the initial capacity the vector was initialised with.
} vector;
Now, I want to make a function that takes in a pointer to the vector struct, and initialises it with the given capacity. All the fields are to be initialised. I want to do this using linked list.
Here is my code
#include <iostream>
using namespace std;
typedef struct node {
int *array; // a pointer to the vector's storage
int size; // the current number of elements in the vector
int cap; // the current capacity of the vector
int init_cap; // the initial capacity the vector was initialised with
node *next;
} vector;
node *head = NULL;
Can I make nodes from a vector struct, like I have attempted in the code written above?
void vector_init(vector *v, int capacity){
//initialising the vector with the given capacity
v->size = capacity;
v->cap = capacity;
v->init_cap = capacity;
//linked list with nodes created and values initialised
node *temp, temp2;
temp = head;
temp = new node;
temp->size = capacity;
temp->cap = capacity;
temp->init_cap = capacity;
temp->next = temp2
temp2 = new node;
temp2->size = capacity;
temp2->cap = capacity;
temp2->init_cap = capacity;
temp2->next = NULL;
}
Have I made the linked list, and initialised the values correctly? If we do not create temporary points temp and temp2, and just use v->size etc to initialise the fields, would that make it a linked list?
You have many problems with your code.
Don't use the name vector - there is a structure called std::vector and it is easy to get confused.
If you want to initialize the values of the structure, don't create an external, separate function for that - it's not c++'ish. Create a struct constructor initializing all the values instead.
You don't initialize the array variable anywhere in your code. You should allocate space for it depending on the capacity given in the constructor.
Don't use the name 'array' for the variable. There is a structure called std::array in C++, and it might be confusing.
Your implementaion makes very little sense to me. You have a linked list of arrays right now; if you would like to functionally replace an array of ints with a linked list of ints, each node should contain one int value.
If, for some reason, you would want to stick to this implementation, you also need some kind of update function that would automatically update size and cap variables while adding or removing elements from array. Otherwise you are sure to end up forgetting about it and you're gonna have mess in your structure. Make this function a part of the structure - it shouldn't be an external function.
That typedef struct node doesn't make sense even after changing the word vector to something else - you don't use it anyway in your code.
You are using the same name for two different structures; vector is at first defined as having 4 fields, and in the next lines as having 5 fields.
Technically yes, this is a linked list, but your vector_init() function does not work as it should. Apart from what I've written above:
You should avoid making functions depend on the global variable, in this case head. It could be passed as a parameter.
These two lines:
temp = head;
temp = new node;
don't make sense. The first one makes the variable temp point to head; the second one tells temp to start pointing to the new variable as you're using operator new, which allocates space and return a pointer to the newly created variable. As a result, you don't operate on the variable head, when you do further operations, but on another variable that will be lost after the temp pointer gets invalidated.
You don't need temp and temp2 variables at all. They only bloat the code.
These two lines:
temp->next = temp2;
temp2 = new node;
should switch places since now you assign a pointer that hasn't been yet initialised.
After writing all this stuff I've realised that the function is incorrect in general. For some reason, you first work on the parameter v, and then do something unrelated to it.
Also, your instructor is just not right saying that you can solve all types of problems with the use of linked lists. It may solve some problems in certain situations, or create new problems, depending on the context.
I don't want to be rude, but there seems to be something fundamentally wrong with the concept of the task you have been given itself. I guess someone really hasn't thought it through.

Cannot Dereference Class Object Pointers Inserted Into a Vector

struct Tree_Node
{
typedef int node_value_type;
Tree_Node(node_value_type key) : value(key) {}
public:
node_value_type value = 0;
Tree_Node* right = nullptr;
Tree_Node* left = nullptr;
};
After inserting pointers to the above class into a vector, trying to pop an element and dereference it gives me an ``Access Violation Reading Location'' exception in Visual C++.
vector<Tree_Node*> node_list(2);
Tree_Node* node1 = new Tree_Node(5);
node_list.push_back(node1);
cout << node_list.front()->value;
However, the following works fine:
Tree_Node* node2 = node1;
cout << node2->value << endl;
What am I missing out on here?
Please note that I am adding and accessing the vector elements inside the same scope. Additionally, I am also aware of possible memory leaks and cleaning up. I just wish to know why the above code isn't working
vector<Tree_Node*> node_list(2);
it creates a vector with two null pointers.
node_list.push_back(node1);
it inserts a third element
cout << node_list.front()->value;
it tries to access the first, which is a null pointer
To reserve space without inserting elements use:
vector<Tree_Node*> node_list;
node_list.reserve(2);
But I'm almost sure that the default ctor reserves place for more than 2 elements.
You can also update the two allocated elements:
vector<Tree_Node*> node_list(2);
node_list[0] = node1;
node_list[1] = node2;
And if you want to make sure that your container contains only two elements use an std::pair or (if you can use C++11) an std::array.

How to allocate memory for specific number of strings?

I was given the task to program something like a dictionary, and the way I am allocating memory for the meanings is just to allocate for 100 meanings in the constructor, which works perfectly fine.
However, the professor didn't approve that and he asked me to rewrite the code in a way that I allocate memory for a relevant number of meanings. I basically have no idea how to do that, how the constructor will know in advance how many meanings I will have?
What would you guys suggest? I post just part of the code, which is relevant for the problem.
#include"expression.h"
//---------------------METHODS-------------------------------------------
Expression::Expression(int m_ctr)
{
count_meanings = m_ctr; // Set the counter to 0
meanings = new char * [100]; // Allocate memory for 100 meanings
}
Expression::~Expression()
{
delete [] meanings; // Free the allocated memory
delete [] word_with_several_meanings; // Free the allocated memory
}
void Expression::word(char *p2c)
{
word_with_several_meanings = new char[strlen(p2c)+1];
strcpy(word_with_several_meanings, p2c); // copy the string, method: DEEP copy
}
void Expression::add_meaning(char *p2c)
{
meanings[count_meanings] = new char[strlen(p2c)+1];
strcpy(meanings[count_meanings++], p2c); // copy the string, method: DEEP copy
}
char * Expression::get_word()
{
return word_with_several_meanings;
}
char * Expression::get_meaning(int n_meaning)
{
return * (meanings + n_meaning);
}
int Expression::get_total_number_of_meanings()
{
return count_meanings;
}
int main(void)
{
Expression expr;
expr.word("bank");
expr.add_meaning("a place to get money from");
expr.add_meaning("a place to sit");
cout << expr.get_word() << endl;
for(int i = 0; i<expr.get_total_number_of_meanings(); i++)
cout << " " << expr.get_meaning(i) << endl;
The C++ way of doing that is to use:
std::string to store a single string (instead of raw char* C-like strings)
std::vector to store a sequence of strings (like the "meanings" in your dictionary)
So, you can have a vector<string> data member inside your class, and you can dynamically add meanings (i.e. strings) to it, using vector::push_back().
If you - for some reason - want to stay at the raw C level, you could use a linked list data structure, storing a raw C string pointer inside each node, and when you add a new meaning, you can create a new node pointing to that string, and add that node to the linked list. A singly-linked list having a node definition like this may suffice:
struct MeaningListNode
{
char * Meaning; // Meaning raw C string
struct MeaningListNode* Next; // Pointer to next meaning node, or nullptr for last
};
But, frankly speaking, the vector<string>> approach seems much simpler and better to me.