Cannot copy struct's items into another struct - c++

I have struct Node and struct UniqueInstructor. Both are singly-linked lists. I have already filled struct Node with some values. Now what I need to do is fill the second UniqueInstructor struct with Node's struct specific value (std::string instructor).
This is how my structs look like:
// main struct that I already filled with data
struct Node {
Node* pNext;
std::string data1;
std::string data2;
std::string day;
std::string group;
std::string instructor; // these are the items I want to copy
// into the UniqueInstructor struct
std::string course;
};
// my 'target' struct, also linked list
struct UniqueInstructor {
UniqueInstructor* pNext;
std::string instructor;
};
For now, all I need to do is copy all the std::string instructor values from Node into UniqueInstructor.
I have tried bunch of things, such as:
void DuplicateInstructor(Node *&pHead)
{
pHead = new UniqueInstructor { pHead, pHead->instructor };
}
but I am getting errors. In this case:
cannot convert 'Node*' to 'UniqueInstructor*' in initialization
My problem probably lies somewhere in passing struct into that function. Please be forgiving, I am fresh-new to structs and pointers. Thank you for help.

You just need to copy the Node::instructor field into the UniqueInstructor::instructor field. Both fields are std::string so that is no problem.
void like_this(Node& n, UniqueInstructor& i)
{
i.instructor = n.instructor;
}
Now it's not very clear what you actually trying to achieve and what your program structure is so I can't tell you where or how you get the Instructor object. In the example above both objects exist. Also you can't link a Node with an UniqueInstructor. Simply Node::pNext and UniqueInstructor::pNext are of completely different types, so I don't know what you are trying to do here.
Moreover explicit new / delete calls are a very bad practice. They have absolutely no place in C++ (outside of library implementations). Too much headache and more importantly too much room for bugs (memory leaks on exceptions). Please read about RAII and smart pointers in C++.

Related

Can we store the class object and not just the pointer to that object

I was trying to store the class object in a file but as the class contains a vector of pointers which is causing a trouble because next time I am accessing the class I am able to fetch everything but this vector.
typedef vector<pair<int, MBR *>> vppint;
class Node{
private:
int id;
int parentID;
int total_children;
MBR *mbr;
vppint children;
public:
vppint fetchChildren(){
return return this->children;
}
int totalChildren(){
return this->total_children;
}
};
MBR is some class.
after storing this Node class in the file and then reading it. the fetchChildren function throws segmentation fault with the obvious reason. is there any way to store the object and not just the pointer.
In C++ you can work with Constructors and Destructors if you would want to create / destroy an instance of a class (I believe those are not needed but it could help you understand how it works).
You can do so by declaring a public constructor in your node class. And then declare the function. Node::Node() {} which in our case will be empty.
class Node{
private:
int id;
int parentID;
int total_children;
MBR *mbr;
vppint children;
public:
Node();
vppint fetchChildren(){
return return this->children;
}
int totalChildren(){
return this->total_children;
}
};
When you have a constructor which will initialize values (or if you prefer to not use a constructor) you can simply store the class object alike:
Node savedObject = Node(); // Creates an instance of the Node class.
If this is what you want to achieve I would suggest you read something as: https://www.w3schools.com/cpp/cpp_constructors.asp for more information.
That's C++. Until now you have to write your own serialization logic which handles pointers correctly. You can take a look at boost::serialization, what provides a lot of helper functions. Note that boost::serialization makes your serialization tool output platform dependet. If you want crossplatform serialization, you have to either put some more effort into your seriaization logic or make use of something like protobuf.

Creating a non-binary tree structure in C++

I need help creating a non-binary tree structure. This structure must contain a class node with as many pointers to node as a the node needs. This is where I get confused.
Here is my class node:
class nodo{
public:
int id;
char info[255];
nodo **son,*father;
nodo()
{
strcpy(info,"");
son=(nodo*)malloc(sizeof(nodo));
}
};
As far as I understand, each time I need a new son pointer I must do the following code:
son=(nodo*)realloc(sizeof(nodo)*t)
t being the number of nodes I want to add plus 1. I canĀ“t seem to understand how to access the pointers. For example, I've already added 2 sons and I want to access the second one, how should I do it?
Is there any other approach to the problem?
Any help will be thanked.
You're writing C++, not C. Don't try to re-implement your own dynamic array from the ground up. The standard library already has std::vector to handle that for you.
class nodo{
public:
int id;
std::string info;
nodo *parent;
std:::vector<nodo *> children;
nodo(nodo *parent) : parent(parent)
{
}
void add_child(nodo *child) { children.push_back(child); }
};
You're trying to dynamically create an array of child pointers for each node. This approach is fine as long as you know how many children the node will have beforehand.
Your constructor should look something like this:
nodo(int numsons) {
son = new nodo*[numsons];
}
This will allocate an array of child nodes, which you will need to delete in the deconstructor.
If you don't know how many children the node will have beforehand (when you call the constructor), you should use a vector.

Linked List using Void* pointers

I want to create a generic linked list in C/C++ (without using templates of C++).
I have written following simple program and it works fine as of now -
typedef struct node
{
void *data;
node *next;
}node;
int main()
{
node *head = new node();
int *intdata = new int();
double *doubledata = new double();
char *str = "a";
*doubledata = 44.55;
*intdata = 10;
head->data = intdata;
node *node2 = new node();
node2->data = doubledata;
head->next = node2;
node *node3 = new node();
node3->data = str;
node3->next = NULL;
node2->next = node3;
node *temp = head;
if(temp != NULL)
{
cout<<*(int *)(temp->data)<<"\t";
temp = temp->next;
}
if(temp != NULL)
{
cout<<*(double *)(temp->data)<<"\t";
temp = temp->next;
}
if(temp != NULL)
{
cout<<*(char *)(temp->data)<<"\t";
temp = temp->next;
}
return 0;
}
My question is -
I need to know the data type of the data I am printing in the code above.
For example - first node is int so i wrote -
*(int *)(temp->data)
second is double and so on...
Instead, is there any generic way of simply displaying the data without worrying about the data type?
I know you can achieve this with templates, but what if I have to do this in C only ?
Thanks,
Kedar
The whole point of a generic list is that you can store anything in it. But you have to be realistic... You still need to know what you are putting in it. So if you are going to put mixed types in the list, then you should look at using a Variant pattern. That is, a type that provides multiple types. Here's a simple variant:
typedef struct Variant
{
enum VariantType
{
t_string,
t_int,
t_double
} type;
union VariantData
{
char* strVal;
int intVal;
double doubleVal;
} data;
} Variant;
You can then tell yourself "I'm storing pointers to Variants in my void* list. This is how you would do it in C. I assume when you say "C/C++" you mean that you're trying to write C code but are using a C++ compiler. Don't forget that C and C++ are two different languages that have some overlap. Try not to put them together in one word as if they're one language.
In C, the only way to achieve generics is using a void*, as you are already doing. Unfortunately, this means that there is no easy way to retrieve the type of an element of your linked list. You simply need to know them.
The way of interpreting data in memory is completely different for different data type.
Say a 32 bit memory block has some data. It will show different values when you typecast it as int or float as both are stored with different protocols. When saving some data in memory pointed by variable of type void*, it does not know how to interpret the data in its memory block. So you need to typecast it to specify the type in which you want to read the data.
This is a little bit like sticking all the cutlery in a drawer, but instead of putting knifes in one slot, forks in another slot, and spoons in a third slot, and teaspoons in the little slot in the middle, we just stick them all in wherever they happen to land when chucking them in, and then wondering why when you just stick your hand in and pick something up, you can't know what you are going to get.
The WHOLE POINT of C++ is that it allows you to declare templates and classes that "do things with arbitrary content". Since the above code uses new, it won't compile as C. So there's no point in making it hold an non-descriptive pointer (or even storing the data as a pointer in the first place).
template<typename T> struct node
{
T data;
node<T> *next;
node() : next(0) {};
};
Unfortunately, it still gets messier if you want to store a set of data that is different types within the same list. If you want to do that, you will need something in the node itself that indicates what it is you have stored.
I have done that in lists a few times since I started working (and probably a couple of times before I got a job) with computers in 1985. Many more times, I've done some sort of "I'll store arbitrary data" in a something like a std::map, where a name is connected to some "content". Every time I've used this sort of feature, it's because I'm writing something similar to a programming language (e.g. a configuration script, Basic interpreter, LisP interpreter, etc), using it to store "variables" that can have different types (int, double, string) or similar. I have seen similar things in other places, such as OpenGL has some places where the data returned is different types depending on what you ask for, and the internal storage has to "know" what the type is.
But 99% of all linked lists, binary trees, hash-tables, etc, that I have worked on contain one thing and one thing only. Storing "arbitrary" things in a single list is usually not that useful.
The answer below is targeting at C++ and not C. C++ allows for what you want, just not in the way that you want to do it. The way I would implement your problem would be using the built-in functionality of the virtual keyword.
Here's a stand-alone code sample that prints out different values no matter the actual derived type:
#include <iostream>
#include <list>
class Base
{
public:
virtual void Print() = 0;
};
class Derived1 : public Base
{
public:
virtual void Print()
{
std::cout << 1 << std::endl; // Integer
}
};
class Derived2 : public Base
{
public:
virtual void Print()
{
std::cout << 2.345 << std::endl; // Double
}
};
class Derived3 : public Base
{
public:
virtual void Print()
{
std::cout << "String" << std::endl; // String
}
};
int main(void)
{
// Make a "generic list" by storing pointers to a base interface
std::list<Base*> GenericList;
GenericList.push_back(new Derived1());
GenericList.push_back(new Derived2());
GenericList.push_back(new Derived3());
std::list<Base*>::iterator Iter = GenericList.begin();
while(Iter != GenericList.end())
{
(*Iter)->Print();
++Iter;
}
// Don't forget to delete the pointers allocated with new above. Omitted in example
return 0;
}
Also notice that this way you don't need to implement your own linked list. The standard list works just fine here. However, if you still want to use your own list, instead of storing a void *data;, store a Base *data;. Of course, this could be templated, but then you'd just end up with the standard again.
Read up on polymorphism to learn more.

c++ store items into an array

I have this code that in my mind, it recieved an item called Vehicle and it has to store it in an array called Node. This is the code related to this part of the program:
void Table::process(Vehicle v, int cont) {
char a='A'+cont;
putVehicle(a,v);
Node.a_v[cont]=v;
if(cont==0) a_surt=v.rowVehicle();
}
This is how I have the array on the private part of Table.h:
struct Node{
Vehicle a_v;
};
The error I get is:
error: expected primary-expression before '.' token
I have the includes I need, but everytime I type this: Node.a_v It gives me that error.
Any advice?
If you want to use a struct, you need to declare a Node before using it. Also, the struct needs to contain an array (or better, look into vectors for more flexibility).
struct Node {
Vehicle[10] a_v; // 10 is max number of Vehicles in array
};
Node myNode;
myNode.a_v[cont] = v;
Remember that if you want to keep this Node around and put more things in it, it needs to be declared in the right scope. For example, to have your process function add a Vehicle to a Node that exists outside of the function process, you could something like this:
void Table::process(Node n, Vehicle v, int cont) {
char a = 'A'+cont;
putVehicle(a,v);
if (cont < 10) {
n.a_v[cont] = v;
}
if (cont == 0) a_surt = v.rowVehicle();
}
It kind of looks like you're just trying to use an array. In that case you're looking for something like this:
// This would go somewhere in your program. Again, 10 is just an example.
Vehicle vehicleArray[10];
// Send this array to this function
void Table::process(Vehicle[] vArray, Vehicle v, int cont) {
char a = 'A'+cont;
putVehicle(a,v);
if (cont < 10) { // In a real program, don't hard-code array limits.
vArray[cont] = v;
}
if (cont == 0) a_surt = v.rowVehicle();
}
You should use Node object to get access to the a_v variable. This line
Node.a_v[cont]=v;
Is incorrect. You should do something like that:
Node n;
n.a_v[cont]=v;
everytime I type this: Node.a_v It gives me that error.
Node is a type; types define the structure of a objects, but they do not have fields of their own (except the static fields, which belong to all instances at once; they are accessed differently anyway).
In order to use a . or -> operator, you need an instance of a Node, like this:
Node x;
x.a_v = ...
It is not clear in your case from where the Node instances should be coming, though. In order to access them, you would need to either pass them in as parameters, or make them available statically/globally (not recommended).
Okay, so Node is NOT the name of your array. It's the name of a user-defined type that is supposed to contain an array. Your Node, however, does not contain an array. It contains one Vehicle, named a_v. I assume a_v is supposed to represent an Array of Vehicles. Therefore, you need to allocate the array. Something like this:
struct Node {
Vehicle a_v[AMOUNT];
};
If you don't know at compile-time how large you want your arrays to be, then they must be dynamically allocated, like this:
struct Node {
Vehicle* a_v;
Node() {
a_v = new Vehicle[AMOUNT];
}
};
If it's dynamically allocated, then it must also be deallocated:
struct Node {
Vehicle* a_v;
Node() {
a_v = new Vehicle[AMOUNT];
}
~Node() {
delete[] a_v;
}
};
AND if it's dynamically allocated, you need to add provisions for copying or disable copying:
struct Node {
Vehicle* a_v;
Node() {
a_v = new Vehicle[AMOUNT];
}
~Node() {
delete[] a_v;
}
// Disable copies (with C++11 support):
Node(const Node&) = delete;
Node& operator=(const Node&) = delete;
// Disable copies (without C++11 support) by making them private and not defining them.
private:
Node(const Node&);
Node& operator=(const Node&);
};
Then to access one of the Vehicles, you'd need to do so like this:
Node n; // Declare a node, which contains an array of Vehicles
n.a_v[cont] = v; // Copy a Vehicle into the array of Vehicles
Note, however, that if you declare the Node instance in this function, then it is local and it will go out of scope as soon as your function ends. You need to declare the Node instance as a member of your Table if you want it to persist past the function call.
class Table
{
private:
Node n;
};
Lastly, as others have suggested, I'd highly recommend that you read a C++ book to learn C++. My personal recommendation is this book (5th edition, don't buy 6th or 7th - the author of those editions is terrible).

c++ push_back doesn't work as it is supposed

I have a class symbol_table that has a vector of objects of another class row_st.also I have an enter method where inserts objects of row_st with a passed name into the vector of desired symbol_table.but when I call the enter to enter objects with name :
a;b;c;Iwill get the following result: a,b,c;b,c;c.the first element of vector gets the name of all the entered objects. and the second element also gets the name of the later entries.
class row_st
{
public:
char* name;
type_u type;//int:0,flaot:1;char:2,bool:3,array:
int offset;
symbol_table *next;
symbol_table *current;
};
class symbol_table
{
public:
vector <row_st *> row;
int type;
int header;
int starting_stmt;
int index;
int i;
symbol_table *previous;
symbol_table(){ header=0;
previous=0; index=0;i=0;starting_stmt=0;}
};
and here it is the enter method:
int enter(symbol_table *table,char* name,type_u type){
row_st *t=new row_st;
t->name=name;
t->type=type;
t->offset=table->index;
t->current=table;
table->index++;
t->next=0;
table->row.push_back(t);
table->header +=1;
return table->row.size()-1;
}
the push_backed elements all points to the same address.the new call makes the same row_st every time it is called.what should I do?
You can't use character pointers like that - you need to allocate storage to them. But as you are using C++, you should remove them and replace them with instances of the std::string class, which will manage storage for you.
As Neil Butterworth's answer suggest, the trouble is probably not with this code, but the place where you call it. Using character pointers does not make it impossible to make things work, just harder.
The problem in this case is definitely not with push_back. If you posted the method where you call this code it might be possible to see exactly what goes wrong.