I'm trying to access the variable name of the Reservation struct like this hotel[SomeIndex].reservations[AnotherIndex].name but it's not working.
How can I access those variables to fill the structure?
PS: It compiles,but it shows in debugger Segmentation Fault.
struct Reservation{
string name;
};
struct Hotel {
string name;
Reservation *reservations;
};
int main()
{
struct Hotel *hotel;
hotel = new Hotel[20];
hotel->reservations=new Reservation[10];
hotel[9].name="Olympus Plaza";
hotel[9].reservations[5].name="John Doe";
cout<<"Hotel: "<<hotel[9].name<<" Name: "<<hotel[9].reservations[5].name<<endl;
return 0;
}
You do not correctly initialize the reservations. Doing this correctly with raw pointers is hard and error-prone, and absolutely not recommended in C++.
First of all, use an std::vector<Hotel> instead of a raw array Hotel *. Vectors are the normal C++ "array" objects.
You can then replace the raw Reservation * pointer inside the Hotel struct with a std::vector<Reservation> as well.
This makes it much easier to fix the actual error: The missing initialization.
What you did was create 20 hotels, then create 10 reservations for the first hotel! Then you try to access reservations for the 9th hotel, where there is an uninitialized pointer which points to random data. This means the behaviour is undefined: In this case, a segmentation fault is the way that your system shows you that you are accessing data which doesn't belong to you.
You need a loop to create reservations for each of the hotels, or if you just want to create reservations in the 9th hotel, you need to specify its index.
Using std::vector is very simple:
#include <vector>
struct Reservation {
string name;
};
struct Hotel {
string name;
vector<Reservation> reservations;
// if you have no "using namespace std", then it's "std::vector".
};
And then you can just create reservations for the correct hotel:
int main()
{
vector<Hotel> hotel(20);
hotel[9].reservations.resize(10);
hotel[9].name="Olympus Plaza";
hotel[9].reservations[5].name="John Doe";
cout<<"Hotel: "<<hotel[9].name<<" Name: "<<hotel[9].reservations[5].name<<endl;
return 0;
}
hotel->reservations=new Reservation[10]; is equivalent to hotel[0].reservations=new Reservation[10];. You've initialised hotel[0] but none of the other elements of hotel - specifically not hotel[9].
It looks like what you need is to define constructors for Hotel and Reservation that initialise all their members to well-defined values.
And I would strongly suggest you use std::vector rather than raw arrays; arrays are an advanced feature and very easy to go wrong with.
Related
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++.
I'm currently working on a C++ project that involves players, each player will need information stored about him on the server in order to determine what he's doing or how it should respond. The server can have up to 1000 slots, and I don't want to leave unused memory just allocated to the program and not created and destroyed when the player connects or joins.
I understand that I can allocate memory dynamically like this:
int *Pointer = new int Example[10];
This would allow me to store 10 integers which I could hold some information on that player. However what I don't know and why I'm asking this question:
How can I use this, or something with a similar function to store information on the player. Like a struct or a class made specifically to hold that players data. Then delete it once he leaves?
An example of what I would need it to hold would be a mixed range of values:
double Pos[3];
int Mode;
string Name;
In other words I need it hold a mixed type of variables, and be able to link this directly back to the player ID it relates to?
Thanks.
You can define a Player class to store information for a player.
class Player {
public:
double Pos[3];
int Mode;
string Name;
};
Then you can define a map to associate the player ID with the Player object.
map<int, Player*> playerList;
When connecting a player, you can allocate memory like this:
Player *p = new Player();
int playerID = xxx;
playerList[xxx] = p; //store the <playerID, p> relationship in the map
Then you can access the fields as you want:
p->Pos[i] = xxx;
p->Mode = xxx;
p->Name = xxx;
When the player leaves, you can deallocate memory like this:
int playerID = xxx;
Player *p = playerList[playerID];
delete p; //deallocate the Player class
playerList.erase(playerID); //deallocate the map entry that stores the <playerID, p> pair
For more advanced uses of class, you can refer to this tutorial on classes.
You can also refer to this to learn about how map can be used.
I have two classes, PersonnelLists and Employee. I create an instance of PersonnelLists in my main, like so:
int main() {
PersonnelLists example; //Make a personnel list
...
}
PersonnelLists uses a constructor with member initialisation of a list of employees, the number of employees, and the size of the array:
PersonnelLists::PersonnelLists(): List(new Employee[SIZE]), numEmployees(0), arraySize(SIZE){
}
This results in some null empty employees being created (I think?):
Employee::Employee(): employeeNumber(0), name(NULL), department(NULL) {
}
It is at this line that I get an invalid null pointer error.
I am new with C++, fresh off the boat from Java programming. I'm still a novice with pointers, so I'm not quite sure what I'm doing wrong here.
UPDATE:
As requested, here is the class definition of Employee:
#include <iostream>
class Employee {
public:
Employee(); //constructor
Employee(std::string name, std::string deparment);
void Print() const; //Print this employee's details
void setEmployeeNo(int employeeNum);
private:
int employeeNumber;
std::string name;
std::string department;
};
In Java, new Employee[SIZE] creates an array of null references.
In C++, new Employee[SIZE] creates an array of default-constructed instances of Employee. Your default constructor tries to set name and department to NULL. Attempting to initialize a std::string to NULL would give the error you describe.
There's no "null" string in C++, but you could default-construct name and department, which would set them to empty strings:
Employee::Employee(): employeeNumber(0), name(), department() {
Finally, if List can contain a variable number of elements, I would recommend that you use std::vector<Employee> (which is similar to ArrayList<Employee> in Java).
If name and department are std::strings (or a similar string type), then initializing them with NULL (a null character pointer) is invalid.
If I guessed right, you should default-initialize them instead, as:
Employee::Employee(): employeeNumber(0), name(), department() {
}
But we really can't tell without seeing the class definition of Employee.
As others have pointed out, you should use a std::vector instead of an array. That allows you to only
have valid Employee objects in your "list".
I don't know what the actual definitions of your classes are, so it's kind of hard to identify your problem.
But an option in modern C++ of doing that is to use a std::vector<Employee> data member inside PersonnelList class. std::vector can grow dynamically at runtime, using its push_back() method, e.g.
#include <vector> // for std::vector
class Employee
{
....
};
class PersonnelList
{
public:
PersonnelList()
{
// Nothing to do - vector is initialized empty
}
// Get current employee count
size_t Count() const
{
return m_employees.size();
}
// Add a new employee to the personnel
void AddEmployee(const Employee& newEmployee)
{
m_employees.push_back(newEmployee);
}
private:
std::vector<Employee> m_employees;
};
No need to use raw pointers or something similar: robust RAII STL container classes make your code simpler.
I have a structure as
struct Employee
{
char uName [255];
struct Employee * next;
struct Employee * prev;
};
All i want to allocate memory of 100 stucture objects at a time and then use them one by one i making a linked list.If the memory is consumed fully then again i want to allocate 100 object memory
I am doing the allocation as
struct Employee * chunk=new struct Employee[100];
Now when i want to add a new node to a linked list i want to take objects from this already allocated memory.Can somebody tell how to achieve this
Employee * pEmployeeData=NULL;
for(long int i=1;i<=100;i++)
{
pEmployeeData=EmployeePool+i;
pEmployeeData->next=NULL;
pEmployeeData->prev=NULL;
InsertAtEnd(pEmployeeData);
}
where InsertAtEnd inserts the node at the end of the linked list.Please tell how to achieve this
I would strongly suggest that you don't try to reinvent the wheel by writing your own linked list, instead have a look at the C++ standard library which contains ready-made container types available for you to use. (for example std::vector and std::list).
Container types exist in the C++ standard library, and are used for storing collections of data/objects. for example, you could do something along the lines of
#include <iostream>
#include <vector>
#include <string>
struct Employee
{
std::string name;
int id;
};
int main()
{
std::vector<Employee> my_employees;
Employee fred = { "Fred", 1 };
Employee bob = { "Bob", 2 };
my_employees.push_back( fred );
my_employees.push_back( bob );
std::cout << my_employees[0].id << " " << my_employees[0].name << "\n"
<< my_employees[1].id << " " << my_employees[1].name << std::endl;
}
The standard containers are easy to use and to learn (You'll find plenty of internet resources which describe how to use them - and your book should also tell you!); If you're new to C++, then it's highly advisable to start out by figuring out how to use these before attempting to create your own.
You'd override the new and delete operators for your class.
new would have to look at any existing pools and see if there were any free objects, and if there weren't, it would then need to allocate a pool. Then, it would return memory allocated from it.
delete would need to check the pool that the provided object was allocated in. If ANY object is still allocated in it, the pool stays, otherwise, it can be deleted.
Also, since you're using C++, consider using a full blown class (though there is very little difference)
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.