C++ std::list with struct containing list with struct - c++

I'm new to C++ (I did C before but never C++) I believe I have syntax problem.
I want to sort some orders by price level into a list.
So my list has positions with inside:
the price level
another std::list with all orders at that price. (Orders)
An Order is a struct with:
userid
quantity
So I ended with :
#include<iostream>
#include<list>
using namespace std;
typedef struct Order {
int userid;
int qty;
} Order;
typedef struct Bid {
int price;
list<Order> Orders;
} Bid;
typedef list<Bid> bids;
int main(void)
{
bids list;
Order order_to_insert;
list.begin();
list.front().price = 13000;
order_to_insert.userid = 3;
order_to_insert.qty = 20;
list.front().Orders.begin();
list.front().Orders.front().userid =3;
list.front().Orders.front().qty = 20;
// list.front().Orders.front() = order_to_insert; // compiles even if i uncomment this.
cout << "Liste : " << list.front().price << endl;
cout << list.front().Orders.front().qty << endl;
return 0;
}
The most intuitive way initially was to use the commented line, it compiles but gives seg fault.
I commented to assign values to fields directly and it seg fault also.
What is the proper way to do that?

First of all this line list.begin(); and that line list.front().Orders.begin(); don't do anything. Remove them.
Now the main problem. Elements in lists don't appear automagically. Lists are empty when created. Have a look at this line:
list.front().price = 13000;
At that point your list is empty, there is no .front(). So its an undefined behaviour, probably the cause of the segfault.
This will do:
Bid bid;
list.push_back(bid);
list.front().price = 13000;
// or if C++11
list.emplace_back();
list.front().price = 13000;
The same goes for list.front().Orders.front() and every other line using .front().
Side note: You may want to use list.emplace_back instead of push_back. Also you may want to use std::vector instead of std::list. There are several performance advantages over a list and it should be used by default unless you really know that you need lists.

Calling front() on an empty list has undefined behavior. An empty list doesn't have a first item, so you shouldn't be trying to access it.
You can use push_back() eg. to add an item into the list, which you can then access and modify.
list.push_back(Bid());

You do not insert elements into your list. std::list::front will return the first element of the list if it is non-empty, but behaviour is undefined if the list is empty.
std::list::begin returns an iterator to the first element, if the list is non-empty or the past-the-end iterator if the list is empty.
Use std::list::push_back to insert new elements into your list.

Thanks guys for clear explanations and advises.
I ended with the following working code :
#include <iostream>
#include <list>
using namespace std
typedef struct Order {
int userid;
int qty;
} Order;
typedef struct Bid {
int price;
list<Order> Orders;
} Bid;
typedef list<Bid> bids;
int main(void)
{
Bid bid;
bids bidList;
Order order_to_insert;
bidList.push_back(bid);
bidList.front().price =13000;
order_to_insert.userid = 3;
order_to_insert.qty = 20;
bidList.front().Orders.push_back(order_to_insert);
bidList.front().Orders.front() = order_to_insert;
cout << "Liste : " << bidList.front().price << endl;
cout << bidList.front().Orders.front().move << endl;
return 0;
}

Related

How to access member elements of a std::queue data structure? [duplicate]

This question already has answers here:
Compilation Error: void value not ignored as it ought to be in std::queue::pop() [duplicate]
(2 answers)
Invalid use of void expression with a Queue and .pop()
(2 answers)
Why doesn't std::queue::pop return value.?
(6 answers)
Closed 2 years ago.
Coding in C+, using Visual Studio 2019, I have a structure defined. I am creating a queue of that data structure and have pushed 2 elements into the queue. Now the question is how to access the members of the structure elements inside the queue?? Any guidance is appreciated!
#include <iostream>
#include <sstream>
#include <cstdlib>
#include <queue>
typedef struct _myqueuestruct
{
string name;
int citypin;
int employeeId;
}myqueuestruct;
int main()
{
queue<myqueuestruct> myQ;
myqueuestruct myQelement;
myQelement.name = "Harry";
myQelement.citypin = "Ohio";
myQelement.employeeId = "345";
// Insert some elements into the queue
myQ.push(myQelement);
myQelement.name = "John";
myQelement.citypin = "Jaipur";
myQelement.employeeId = "223";
// Insert some elements into the queue
myQ.push(evtSvcElement);
//myQ.size();
//queue<myqueuestruct>::iterator it = myQ.begin();
for (int i = 0; i < myQ.size(); i++)
{
cout << myQ.front();
myQ.pop(); //???? How do I access the member values of the elements of the queue?
}
while (1);
return 0;
}
Well, front returns a reference to the first element, so like this:
std::cout << myQ.front().name; // and similarly for other elements
Or, for example, make a referenence yourself:
auto& ref = myQ.front();
ref.name = "foo";
ref.citypin = 42;
// etc.
I have modified your code to get it compiling and working: (Note: I have used C++17 standard using g++ to compile this code but it should work for visual studio 2019
#include <iostream>
#include <queue>
typedef struct _myqueuestruct
{
std::string name;
std::string citypin;
int employeeId;
}myqueuestruct;
int main()
{
std::queue<myqueuestruct> myQ;
myqueuestruct myQelement;
myQelement.name = "Harry";
myQelement.citypin = "Ohio";
myQelement.employeeId = 345;
// Insert some elements into the queue
myQ.push(myQelement);
myQelement.name = "John";
myQelement.citypin = "Jaipur";
myQelement.employeeId = 223;
// Insert some elements into the queue
myQ.push(myQelement);
while (myQ.size() > 0)
{
auto & e = myQ.front();
std::cout << "Name: " << e.name
<< " CityPin: " << e.citypin
<< " EmployeeId: " << e.employeeId << std::endl;
myQ.pop();
}
return 0;
}
I would like to point out a few changes I have to make in your above code:
in your struct definition you used int datatype but you assigned char string to the same. I have modified the datatype to be std::string.
using while loop for iterating through all the elements and using myQ.size() every time instead of using for loop.
std::cout - holding the element reference in a local variable inside the loop and printing all member variables.
Improvements you can make to above code:
There are multiple transient copies of the object being created when you push the object into the queue. I would suggest refer std::queue documentation here: http://www.cplusplus.com/reference/queue/queue/ and try to enhance above code with
emplace_back
overload operator<< for your class for printing class members, this would help you learn about operator overloading.

computer lab with pointers

I have this assignment with managing computer labs. Specifically, there are 4 labs, each has a different number of computers. Hence, I want to create a 2D array with pointers, but after trying different stuff, I count on you for this error (please!!!). Below is a part of my programme, up to where the annoying bug comes up.
I got a run-time error after 1 run (terminate called after throwing an instance of std::bad_array_new_length what(): std::bad_array_new_length) when I leave the line with comment //PROBLEM HERE as such.
Add a & in front of lab room, the compiler gave me the error: lvalue required as left operand of assignment.
Newbie in C++, first time with pointers, I'd appreciate any help.
#include <iostream>
using namespace std;
//Global variables
const int SIZE = 4;
typedef int* Stations;
Stations *labroom;
//Function declaration:
void numberOfComputers();//Receive number of computers in each lab
int menu();//Display menu options for users
void menu_processor(int option);//process user's option
int main()
{
numberOfComputers();
menu();
menu_processor(menu());
return 0;
}
void numberOfComputers ()
{ char ans;
for (int i=0;i<SIZE;i++)
{
cout<<"Enter the number of computer stations in lab "<<i+1<<": ";
do
{
cin.get(ans);
} while (ans!='\n');
labroom [i] = new int [ans-'0'];//PROBLEM HERE
cout<<"\n";
}
}
That's not c++ code, it's just (ugly) C.
In C++ we have array for static arrays and vector for dynamic arrays.
First of all, choose the name of your variables or function in a smart way: prefer getNumberOfComputersFromUser instead of numberOfComputers. What numberOfComputers means? A function name must describe what it is doing.
Here a simplified snippet:
#include <vector>
#include <array>
#include <iostream>
using namespace std;
using Station = int;
using LabRooms = array<vector<Station>, 4>;
LabRooms getNumberOfComputersFromUser()
{
LabRooms labRooms;
int roomIndex = 0;
for(auto& computersInLab : labRooms)
{
cout << "Enter the number of computer stations in lab " << ++roomIndex << ": ";
auto computerCount = 0;
cin >> computerCount;
computersInLab.resize(computerCount);
}
return labRooms;
}
Explain
array requires two template arguments: the type and the size. Elements are statically allocated, no need to new because we already know how many rooms we have. The list of computers in each room is not know so we use vector that can dynamically increase or decrease.
using LabRooms = array<vector<Station>, 4>; it's the same of typedef array<vector<Station>, 4> LabRooms but it's clearer I think
for( auto& computersInLab : labRooms) iterate over labRooms and get a reference to its elements (in this case a reference to a vector of Station. This is the same of:
for(int i = 0; i < labRooms.size(); ++i)
{
auto& computersInLab = labRooms[i];
...
}
computersInLab.resize(computerCount); resize the list of computers with the value specified from the user.
Now, labRooms is an array of 4 elements, each element is a list of Station.

c++ String copying error to struct pointer data fields

I'm currently writing a program that uses a binary search tree to store names and phone numbers (phonebook basically). I've done this before with an AVL tree, and it works fine. I have decided to switch my methods up for this implementation and not just copy/paste the logic and format of the last one. In doing so I've run into a weird error and I have no idea why it's happening. At first I thought my problem was in the way I returned a struct pointer, but it is actually in my string copying.
I've written a very basic program that only shows the copy function that returns the structure, which are then used to recursively fill the BST with the data (which is read in from a file).
Here is the shortened example:
#include <iostream>
#include <string>
using namespace std;
struct Node
{
std::string first;
std::string last;
std::string phone;
};
Node* copyfunc(std::string first, std::string last, std::string phone)
{
Node* temp = NULL;
temp->first = first;
temp->last = last;
temp->phone = phone;
return temp;
}
int main()
{
std::string first, last, phone;
first = "Jenny";
last = "Something";
phone = "8675309";
Node* newStruct = NULL;
newStruct = copyfunc(first, last, phone);
cout << newStruct->first << endl;
cout << newStruct->last << endl;
cout << newStruct->phone << endl;
cout << "Never to be seen again..." << endl;
return 0;
}
Now, I've tried using VS2013 debugger to find out where the issue is, and it happens on the first copy: "temp->first = first;". It breaks with an access violation warning and then opens the xstrings (header?) and points to the section: (line 2245)
if (this->_Myres < _Newsize)
_Copy(_Newsize, this->_Mysize); // reallocate to grow"
I'm just guessing, but from what I can gather it seems to me that it's failing in creating the new string to fit the old strings length.
The program (both the example and real one) will compile, they just hang at the point of reaching the copy function.
All input is appreciated, thanks!
EDIT: The reason I use pointers for my structures is due to the way the algorithms I'm using are written. The functions that actually link the nodes together in the BST accept a Node* type rather than a Node object.
Ex: recursiveInsert(Node* root, Node* newNodeToAdd);
You are not initializing temp to anything useful before you attempt to use it.
Node* temp = NULL;
temp->first = first; // oops! temp is NULL!
It would be easier to drop the pointers entirely:
Node copyfunc(std::string first, std::string last, std::string phone)
{
Node temp = {first, last, phone};
return temp;
}
You should also consider passing the parameters by const reference instead of value. Or just drop the function completely and initialize the Node where needed:
Node newStruct = {first, last, phone};
cout << newStruct.first << endl;

Accessibility for Vectors of Singly Linked Lists (or possibly a Linked List of Linked Lists)

Been wracking my mind all day trying to hammer out the underlying data structures for a challenge assignment in one of my programming classes.
The problem is as follows:
Given an assortment of objects (each of which includes an identifier and a weight) and a supply of containers (which have a fixed weight capacity), pack all the items using as few containers as possible without overloading any of them.
I have the logic aspects hammered out using a hodgepodge of arrays, but the dynamic nature of this assignment has me wanting to optimize things by using vectors and/or linked lists.
#include <iostream>
#include <fstream>
#include <iomanip>
#include <cstdlib>
#include <math.h>
#include <time.h>
#include <conio.h>
#include <vector>
#include <algorithm>
using namespace std;
struct Item
{
int number;
double weight;
bool operator < (const Item& str) const
{
return (weight < str.weight);
}
};
class Node
{
int number;
double weight;
Node* next;
public:
Node()
{};
void SetID(int iNum)
{
number = iNum;
};
void SetWeight(double iWeight)
{
weight = iWeight;
};
void SetNext(Node* iNext)
{
next = iNext;
}
int GetID()
{
return number;
};
double GetWeight()
{
return weight;
};
Node* Next()
{
return next;
};
};
class List
{
Node* head;
double weight;
public:
List()
{
head = NULL;
weight = 0;
};
int Size()
{
Node* tmp;
int count = 0;
for (tmp = head; tmp != NULL; tmp = tmp->Next())
{
count++;
}
return count;
};
double Weight()
{
return weight;
};
void Print()
{
Node *tmp = head;
if ( tmp == NULL )
{
cout << " E M P T Y" << endl;
return;
}
do
{
cout << setw(8) << tmp->GetID() << " | " << setw(8) << tmp->GetWeight() << endl;
tmp = tmp->Next();
} while ( tmp != NULL );
};
void Append(int iNum, double iWeight)
{
Node* newNode = new Node();
newNode->SetID(iNum);
newNode->SetWeight(iWeight);
newNode->SetNext(NULL);
Node *tmp = head;
if ( tmp != NULL )
{
while ( tmp->Next() != NULL )
{
tmp = tmp->Next();
}
tmp->SetNext(newNode);
}
else
{
head = newNode;
}
weight += iWeight;
};
};
double ItemWeights(vector<Item> iVect)
{
double total = 0;
for(int i = 0; i < iVect.size(); i++)
{
total += iVect[i].weight;
}
return total;
}
int main()
{
const double MAX_WEIGHT = 20;
vector< Item > source;
//
// Segment of code which propagates the vector data
// works fine, but is excluded for the sake of brevity
//
double totalWeight = ItemWeights(source);
// Duplicate vector of items
vector< Item > items(source);
for(int i = 0; i < items.size(); i++)
{
cout << setw(8) << items[i].number << setw(8) << items[i].weight << endl;
}
cout << "\n Total weight = " << totalWeight << endl;
cout << "\n\n Press any key to continue... ";
getch();
// Solution A-Original
// vector< vector< Item > > boxesAO( vector< Item >);
// boxesAO[0].push_back({items[items.size()].number, items[items.size()].weight});
vector< List > boxesAO;
// boxesAO[0].Append(items[items.size()].number, items[items.size()].weight);
return 0;
}
I've left some of the methods I've tried in the code (commented out) - none of which worked. As I mentioned above, I've got it working with arrays of linked lists and with 2D arrays, but the vast range of potential input makes these problematic at best. Either a bunch of empty lists taking up space or, worse, not having enough.
I'm thinking that vector< List > is my best option, but I can't figure out how I'm supposed to access any of the List functionality.
If someone would be so helpful as to offer a suggestion for how to create a "dynamic 2D array" as well as a code example of how to access it, I would be most greatly appreciative. My deepest thanks in advance.
EDIT:
#jaredad7 ~ That's what I've been trying, but it keeps causing the program to crash.
List box;
box.Append(items[items.size()].number, items[items.size()].weight);
This works just fine - no problems whatsoever.
The earlier code propagates a 1D vector of Item structs, which also works properly.
vector< List > boxes;
boxes[0].Append(items[items.size()].number, items[items.size()].weight);
This compiles fine but crashes during execution, no matter what index is used. (I'm also using couts for debugging, and the issue most definitely lies with trying to access the List functions.)
I'm suspecting that .push_back or somesuch may be needed, but I haven't been able to find much information concerning vectors of List objects.
If you can, my first suggestion would be to go with the vector (if that is allowed). As for accessing functions/attributes of a member of a vector, it's done the same way as an array, that is:
vectorname[i].functionname(a,b,c);
The best way to do this without vectors would be to use your nodes as the item container (a struct), and handle node-creation, deletion, etc. in your list class. Then, you would only really need one container for as many objects of one type as you need. You can make the type dynamic (although it appears you only need doubles for this project) by adding a class template (use google if you are unfamiliar with templates in C++). This will allow your user to make a container for each type of data (much like a vector).

Linked list issue with insert

The problem appears with the insert function that I wrote.
3 conditions must work, I tested b/w 1 and 2, b/w 2 and 3 and as last element, they worked.
EDIT;
It was my own problem. I did not realize I put MAXINPUT = 3 (instead of 4). I do appreciate all the efforts to help me becoming a better programmer, using more advance and more concise features of C++.
Basically, the problem has been solved.
Efficiency is not my concern here (not yet). Please guide me through this debug process.
Thank you very much.
#include<iostream>
#include<string>
using namespace std;
struct List // we create a structure called List
{
string name;
string tele;
List *nextAddr;
};
void populate(List *);
void display(List *);
void insert(List *);
int main()
{
const int MAXINPUT = 3;
char ans;
List * data, * current, * point; // create two pointers
data = new List;
current = data;
for (int i = 0; i < (MAXINPUT - 1); i++)
{
populate(current);
current->nextAddr = new List;
current = current->nextAddr;
}
// last record we want to do it sepeartely
populate(current);
current->nextAddr = NULL;
cout << "The current list consists of the following data records: " << endl;
display(data);
// now ask whether user wants to insert new record or not
cout << "Do you want to add a new record (Y/N)?";
cin >> ans;
if (ans == 'Y' || ans == 'y')
{
/*
To insert b/w first and second, use point as parameter
between second and third uses point->nextAddr
between third and fourth uses point->nextAddr->nextAddr
and insert as last element, uses current instead
*/
point = data;
insert(());
display(data);
}
return 0;
}
void populate(List *data)
{
cout << "Enter a name: ";
cin >> data->name;
cout << "Enter a phone number: ";
cin >> data->tele;
return;
}
void display(List *content)
{
while (content != NULL)
{
cout << content->name << " " << content->tele;
content = content->nextAddr;
cout << endl; // we skip to next line
}
return;
}
void insert(List *last)
{
List * temp = last->nextAddr; //save the next address to temp
last->nextAddr = new List; // now modify the address pointed to new allocation
last = last->nextAddr;
populate(last);
last->nextAddr = temp; // now link all three together, eg 1-NEW-2
return;
}
Your code works fine on my machine (once the insert(()) statement is "filled in" properly as explained in the code comment). The insertion works in all positions.
Something else, though: I initially had a look at your insert function. I thought I'd give you a hint on how to make it a little shorter and easier to understand what's going on:
void insert(List *last)
{
// create a new item and populate it:
List* new_item = new List;
populate(new_item);
// insert it between 'last' and the item succeeding 'last':
new_item->nextAddr = last->nextAddr;
last->nextAddr = new_item;
}
This would be preferable because it first creates a new, separate item, prepare it for insertion, and only then, when this has worked successfully, will the function "mess" with the linked list. That is, the linked list is not affected except in the very last statement, making your function "safer". Contrast this with your version of insert, where you mix code for constructing the new item with the actual insertion. If something goes wrong inside this function, chances are far higher that the linked list is messed up, too.
(What's still missing btw. is a initial check whether the passed argument last is actually valid, ie. not a null pointer.)
P.S.: Of course you could just use a standard C++ std::list container instead of building your own linked list, but seeing that you tagged your question beginner, I assume you want to learn how it actually works.
step one should be to make the list into an object instead of just keeping a bunch of pointers around in main(). you want an object called List that knows about it's own first (and maybe last) elements. it should also have methods like List.append() and List.insert().
your current code is nigh unreadable.
Use a std::list, unless this is homework, in which case it needs tagging as such.
In my experience, I have learned to start small and test, then build up. I'll guide you through these steps.
BTW, a linked list is a container of nodes. So we'll start with the node class first.
Minimally, a node must have a pointer to another node:
#include <iostream>
#include <cstdlib> // for EXIT_SUCCESS
#include <string>
using std::cout;
using std::endl;
using std::cerr;
using std::cin;
using std::string;
struct Node
{
// Add a default constructor to set pointer to null.
Node()
: p_next(NULL)
{ ; }
Node * p_next;
};
// And the testing framework
int main(void)
{
Node * p_list_start(NULL);
// Allocate first node.
p_list_start = new Node;
// Test the allocation.
// ALWAYS test dynamic allocation for success.
if (!p_list_start)
{
cerr << "Error allocating memory for first node." << endl;
return EXIT_FAILURE;
}
// Validate the constructor
ASSERT(p_list_start->p_next == 0);
// Announce to user that test is successful.
cout << "Test successful." << endl;
// Delete the allocated object.
delete p_list_start;
// Pause if necessary.
cin.ignore(100000, '\n'); // Ignore input chars until limit of 100,000 or '\n'
return EXIT_SUCCESS;
}
Compile, and run this simple test. Fix errors until it runs correctly.
Next, modify the tester to link two nodes:
int main(void)
{
Node * p_list_start(NULL);
Node * p_node(NULL); // <-- This is a new statement for the 2nd node.
//...
// Validate the constructor
ASSERT(p_list_start->p_next == 0);
// Allocate a second node.
p_node = new Node;
if (!p_node)
{
cerr << "Error allocating memory for 2nd node." << endl;
// Remember to delete the previously allocated objects here.
delete p_list start;
return EXIT_FAILURE;
}
// Link the first node to the second.
p_list_start->Link_To(p_node);
// Test the link
ASSERT(p_list_start.p_next == &p_node);
//...
// Delete the allocated object(s)
delete p_list_start;
delete p_node;
//...
}
Compile with the modifications.
It failed to compile, undefined method: Node::Link_To
Not to worry, this is expected. Show us the compiler is working. :-)
Add the Link_To method to the Node structure:
struct Node
{
// ...
void Link_To(const Node& n)
{
p_next = &n;
return;
}
//...
};
Compile and run. Test should pass.
At this point the linking process has been validated. Onto adding content to the node.
Since the Node object has been tested, we don't want to touch it. So let's inherit from it to create a node with content:
struct Name_Node
: public Node // Inherit from the tested object.
{
std::string name;
std::string phone;
};
If you haven't learned inheritance yet, you can append to the existing node:
struct Node
{
//...
std::string name;
std::string phone;
}
At this point you can add functions for setting and displaying content. Add the testing statements. Run and validate.
The next step would be to create two content nodes and link them together. As you build up, keep the testing code. Also, if stuff works you may want to put the functionality into separate functions.
For more information on this process, check out Test Driven Development.