Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 3 years ago.
Improve this question
I wrote a program which should to insert elements in the list compare with their costs, but it doesn't work. I enter one element and then program doesn't work. And I can't understand what's wrong.
here is an exactly the exercise:
Modify the list, so elements on the list are ordered by price. New items added to the list should be inserted into the right place
#include <iostream>
#include <string>
using namespace std;
typedef struct listt
{
string name;
float price;
struct listt *next;
}listt;
typedef listt* listPtr;
void insertt(listPtr *, string, float);
void printList(listPtr);
void instruct();
int main()
{
unsigned int choice;
float costs;
string itemName;
listPtr head = NULL;
instruct();
cin >> choice;
while(choice != 3)
{
switch(choice)
{
case 1:
cout << "Please enter the name of the item:" << endl;
cin >> itemName;
cout << "Please enter the cost of item: " <<endl;
cin >> costs;
insertt(&head, itemName, costs);
break;
case 2:
printList(head);
break;
}
cout<<"Choose the operation\n";
cin >> choice;
}
cout<<"end of operation";
return 0;
}
void instruct(void)
{
cout<<"Choose the operation\n" << "1.Fill the list\n" << "2.Print the list\n" << "3.End operation\n";
}
void insertt(listPtr *itemList, string nm, float cst)
{
listPtr previousPt;
listPtr currentPt;
listPtr newPtr;
if(newPtr != NULL){
newPtr->name = nm;
newPtr->price = cst;
newPtr->next = *itemList;
}
previousPt = NULL;
currentPt = *itemList;
while(currentPt != NULL && cst > currentPt->price )
{
previousPt = currentPt;
currentPt = currentPt->next;
}
if(currentPt == NULL)
{
newPtr->next = *itemList;
*itemList = newPtr;
} else{
previousPt->next = newPtr;
newPtr->next = currentPt;
}
}
void printList(listPtr hh)
{
while(hh->next != NULL)
{
cout << hh->name <<" " << hh->price<< endl;
hh = hh->next;
}
}
in insertt :
void insertt(listPtr *itemList, string nm, float cst)
{
listPtr previousPt;
listPtr currentPt;
listPtr newPtr;
if(newPtr != NULL){
newPtr->name = nm;
newPtr->price = cst;
newPtr->next = *itemList;
}
newPtr is not initialized but you compare its value to NULL then may be modify an unknown block of memory, this is an undefined behavior
replace listPtr newPtr; by listPtr newPtr = new listt;
That comes because of typedef listt* listPtr; hidding the pointer, do not define typedef hiding pointer, this is always a source of problem
Your way to insert the new cell is wrong, for instance if the second insert cell as a lower price than the first you have an illegal memory access. A working solution is :
void insertt(listt ** itemList, string nm, float cst)
{
listt * newCell = new listt;
newCell->name = nm;
newCell->price = cst;
newCell->next = nullptr;
if (*itemList == nullptr)
*itemList = newCell;
else {
for (;;) {
if (cst < (*itemList)->price) {
newCell->next = *itemList;
*itemList = newCell;
return;
}
if ((*itemList)->next == nullptr) {
(*itemList)->next = newCell;
return;
}
itemList = &(*itemList)->next;
}
}
}
Note printList is erroned because the last element is never print, replace
while(hh->next != NULL)
by
while(hh != NULL)
or better
while(hh != nullptr)
Your struct listt is defined like in C
You need also to check your input are valid, your cin >> x; must be if (! (cin >> x)) { ..error management .. }
Related
I tried implementing Linked List using C++ using a structure.
I've included three functions - Size, Insertion and Deletion from the end.
The program compiled successfully. During execution, when I tried to give input for the LLInsert() function, there was just a cursor blinking on my execution window. I don't know if the function returned to main.
Also the LLSize() doesn't return 0 when I try to find the Size of a empty list.
I can't seem to figure out what I'm doing wrong. Here is my code.
#include<iostream>
using namespace std;
struct LL {
LL *next = NULL;
int data;
};
int LLSize(LL *head) {
LL *current = new LL;
current = head;
int count = 0;
while(current != NULL) {
current = current -> next;
count ++;
}
return count;
}
void LLInsert(LL *head,int value) {
LL *current = new LL;
current = head;
LL *Newnode = new LL;
Newnode -> data = value;
Newnode -> next = NULL;
if(head == NULL) {
head = Newnode;
return;
}
while(current->next != NULL) {
current = current->next;
}
current->next = Newnode;
return;
}
int LLDelete(LL *head) {
LL *current = new LL;
current = head;
int deleteddata;
while(current->next->next != NULL) {
current = current->next;
}
current->next->data = deleteddata;
current->next = NULL;
return deleteddata;
}
int main() {
int choice;
LL *A;
while(1) {
cout << "1. Size\n2. Insert\n3. Delete\n4. Exit" << endl;
cout << "Enter a choice : ";
cin >> choice;
switch(choice) {
case 1 : {
cout << "\nLength = " << LLSize(A) << endl;
break;
}
case 2 : {
int value;
cout << "\nEnter the element to insert : ";
cin >> value;
LLInsert(A,value);
break;
}
case 3 : {
cout << LLDelete(A);
break;
}
case 4 : {
exit(0);
}
default : {
cout << "\nInvalid choice. Enter a valid choice " << endl;
break;
}
}
}
}
Don't use using namespace.
Create a type for the list and a type for the nodes
struct LL {
LL* next;
int data;
};
struct L {
LL* head;
};
Use references and don't allocate new memory in each function
int LLSize(L& list) {
LL *current = list.head;
Check if the head of the list is set and use nullptr
if (list.head == nullptr) {
Use an instance of the list and not a pointer
int main() {
int choice;
L A;
Use a debugger like gdb to analyze your program.
Clean up at the end. Delete memory you allocated with new. One delete for each new.
The code bellow inserts nodes correctly but
I have a problem that when try to print the list the program unfortunately stop working.
The error message is : your project has stopped working.
This is my code:
#include <iostream>
#include <string>
using namespace std;
typedef struct st {
string data;
int ISBN;
string Title;
string Author;
int publishedyear;
bool borrow;
st* next;
} NODE;
NODE* add(NODE* head, int isbn)
{
NODE *p1, *p2;
NODE* n;
n = new NODE;
n->ISBN = isbn;
if (head == NULL) {
head = n;
return head;
}
if (n->ISBN < head->ISBN) {
n->next = head;
head = n;
return head;
}
p1 = p2 = head;
while (p2 != NULL) {
if (n->ISBN < p2->ISBN) {
n->next = p2;
p1->next = n;
return head;
}
else {
p1 = p2;
p2 = p2->next;
}
}
n->next = p2;
p1->next = n;
return head;
}
void print(NODE* head)
{
NODE* p;
p = head;
if (head == NULL) {
cout << "empty list" << endl;
}
while (p != NULL) {
cout << "Book ISBN Is : " << p->ISBN << endl;
p = p->next;
}
}
void main()
{
// cout << "hi";
NODE* head;
head = NULL;
string op;
int isbn;
cout << "Enter the opertion in the following format : op , ISBN" << endl;
while (1) {
cin >> op;
if (op == "add") {
cin >> isbn;
if (op == "add") {
head = add(head, isbn);
cout << "book with thie ISBN code " << isbn << " is added successfuly."
<< endl;
}
}
else if (op == "print") {
print(head);
}
else {
cout << "Enter vaild operation! ." << endl;
}
}
}
any suggestions ?
The answer was pointed out, but... I feel awfully unsatisfied by the state of your code, so allow me to give you a few tips.
Note: unless the point is to build a list, do reuse the existing standard containers (vector, in particular) and algorithms (sort) rather than building your own.
Let's start with the basics, this is the year 2016 you should have access to C++11 by now.
C++11 allows to initialize data-members straight at the point of declaration, and I recommend that you do it for all built-in types (integrals, booleans, floating points and pointers) since by default they otherwise contain garbage which is puzzling.
struct Node {
std::string data;
int ISBN = 0;
std::string title;
std::string author;
int publishedyear = 0;
bool borrow = false;
Node* next = nullptr;
};
Note that this alone solves your bug. And it also avoids forgetting it the next time.
Secondly, the add method should NOT be responsible for creating a node. This is mixing concerns, and it also leaves most of the node with default values and no way to access it without looking for it by its ISBN.
There's also a point that the add method does not account for: what if the ISBN is already in the list?
// Adds the new node to the list, maintaining the ordering by ISBN.
//
// Returns the new head of the list, unless an existing node in the list already
// has this ISBN in which case returns `nullptr`.
Node* add(Node* head, Node* node) {
assert(node != nullptr && "Null argument provided");
if (head == nullptr) {
return node;
}
if (node->ISBN < head->ISBN) {
node->next = head;
return node;
}
if (node->ISBN == head->ISBN) {
return nullptr;
}
// Find "current" such that "current->ISBN" < "node->ISBN" and
// "node->ISBN" <= "current->next->ISBN"
Node* current = head;
while (current->next != nullptr && node->ISBN > current->next->ISBN) {
current = current->next;
}
if (node->ISBN == current->next->ISBN) {
return nullptr;
}
node->next = current->next;
current->next = node;
return head;
}
Note: assert requires #include <cassert>.
Your print method is already pretty good, congratz!
Just two nitpicks:
if you know that nothing further will be executed, return immediately, don't wait
don't use endl, it both appends an end of line AND flushes the buffer immediately, which leads to performance issues more often than not
// Prints the list, in order.
void print(Node* head) {
if (head == nullptr) {
std::cout << "empty list\n";
return;
}
for (Node* p = head; p != nullptr; p = p->next) {
std::cout << "Book ISBN: " << p->ISBN << "\n";
}
}
And finally, the modified main.
Note that I expanded the help text a bit, and provided a (clean) quit operation.
The main change, however, is dealing without input error. Dealing with output error is left as an exercise to the reader (hint: make them throw).
It would also be a good exercise to properly deal with the allocated memory.
int main() {
std::cout << "Enter one of the following operations when prompted:\n"
" - add <isbn>\n"
" - print\n"
" - quit\n";
Node* head = nullptr;
while (1) {
std::cout << "> ";
std::string op;
if (!(std::cin >> op)) {
std::cerr << "An error occurred reading the operation, sorry\n";
break;
}
if (op == "quit") {
std::cout << "See you later!\n";
break;
}
if (op == "print") {
print(head);
continue;
}
if (op == "add") {
int isbn = 0;
if (!(std::cin >> isbn)) {
std::cout << "Please provide a correct ISBN!\n";
continue;
}
Node* node = new Node();
node->ISBN = isbn;
Node* h = add(head, node);
if (h == nullptr) {
std::cout << "This ISBN was already provided!\n";
delete node;
continue;
}
head = h;
continue;
}
std::cout << "Please enter a valid operation!\n";
}
// Deal with allocated memory ;)
}
st::next is never set to NULL. This makes testing p!=NULL in print somewhat problematic.
Solution: NULL next when the node is the tail node.
I have been working on a little personal project, and have run into a snag. The purpose of the project is to add to my Github, but I have been staring at my code off and on for the last week and cannot find where it goes wrong. The project is a test of my own ability, and my understanding of Linked Lists in C++. Before I go on, here is my code
#include <iostream>
using namespace std;
struct payload {
int ID;
int x;
int y;
string name;
};
struct node {
node* prev;
node* next;
bool isRoot;
payload data;
};
node* fillStruct(node* tmp);
void print(node* tmp);
int main(void) {
node* temp;
node* list;
node* iterator;
bool done = false;
int count = 0;
char answer;
do {
temp = new node();
temp = fillStruct(temp);
if (count == 0) {
list = new node();
list = temp;
list->prev = NULL;
list->next = NULL;
list->isRoot = true;
} else {
list->next = temp;
temp->prev = list;
list = new node();
list = temp;
}
count++;
cout << "Will more elements be added to the list?\n [Y or N]\n";
cin >> answer;
switch (answer) {
case 'y':
case 'Y':
break;
case 'n':
case 'N':
list->next = NULL;
done = true;
break;
default:
break;
}
} while (!done);
while (list->prev != NULL) {
list = list->prev;
}
int identifier = 100;
while (1) {
list->data.ID = identifier;
identifier++;
if (list->next == NULL)
break;
list = list->next;
}
while (list->prev != NULL) {
list = list->prev;
}
while (1) {
print(list);
if (list->next == NULL)
break;
list = list->next;
}
return 0;
}
node* fillStruct(node* tmp) {
if (!tmp) {
cerr << "Unauthorized access. Terminating program";
return tmp;
}
cout << "Please enter the X value.\n";
cin >> tmp->data.x;
cout << "Please enter the Y value.\n";
cin >> tmp->data.y;
cout << "Please enter the data name\n";
cin >> tmp->data.name;
return tmp;
}
void print(node* tmp) {
cout << "Identifier: " << tmp->data.ID << endl;
cout << " X: " << tmp->data.x << endl;
cout << " Y: " << tmp->data.y << endl;
cout << " Name: " << tmp->data.name << endl;
}
The code compiles and executes fine. The problem I am having is in the printing phase of the code. It cuts off the last element, and I cannot tell why. The second while(1), as I understand it, should terminate after it prints the final element. If anyone can offer guidance, I would greatly appreciate it. Thanks in advance, and as usual, if there's anything I can add to clarify, I will.
Following your code, it would seem better to keep list at the list head, and use a pointer for walking the list.
node* list = NULL;
node* ptr = NULL; // tail
do {
temp = new node();
temp = fillStruct(temp);
temp->prev = ptr;
temp->next = NULL;
if (ptr) {
ptr->next = temp;
}
ptr = temp;
if (!list) {
list = ptr;
}
count++;
cout << "Will more elements be added to the list?\n [Y or N]\n";
cin >> answer;
switch (answer) {
case 'y':
case 'Y':
break;
case 'n':
case 'N':
done = true;
break;
default:
break;
}
} while (!done);
int identifier = 100;
for (ptr = list; ptr; ptr = ptr->next) {
ptr->data.ID = identifier;
identifier++;
}
for (ptr = list; ptr; ptr = ptr->next) {
print(list);
}
im quite a noob at linked list so i would be very grateful if you could help me with this code,so far if written what you can see below my 1st problem is how can i call my void do sort a text document like(see below) i have written the sort void but have no idea how to writte it properly to access the linked list...
***1stName lastname number email bday***
Nikos Nikolas 281085252 niko#hotmail.com 21/10/1995
mary ann 2810258963 mary#hotmail.com 22/10/1995
james bond 2810254789 james#hotmail.com 23/11/2000
luna loop 2810258741 luna#hotmail.com 24/04/1990
#include <iostream>
#include <fstream>
#include <string>
#define TRUE 1
using namespace std;
struct organizer
{
string first_name;
string last_name;
int number;
string email;
string bday;
organizer* next;
};
int main()
{
void sort_by_last(organizer* head_ptr);
char command;
ifstream inFile;
inFile.open("mycontacts.txt");
if (!inFile)
{
cerr << "Unable to open file." << endl;
return 0;
}
organizer* temp = new organizer;
organizer* head_ptr = temp;
while(inFile)
{
inFile >> temp->first_name;
inFile >> temp->last_name;
inFile >> temp->number;
inFile >> temp->email;
inFile >> temp->bday;
temp->next = new organizer;
temp = temp->next;
}
temp->next = NULL;
while (TRUE)
{
cout << "Write 'print' To print mycontacts." << '\n';
cout << "Write 'find' '..'to search myconacts."<< '\n';
cout << "Write 'delete' 'name'to delete a contact."<< '\n';
cout << "Write 'insert' 'details' to add a contact."<< '\n';
cout << "Write 'quit' to exit the programm."<< '\n';
command = getchar();
switch(command)
{
case 'p':
sort_by_last(organizer);
break;
case 'f':
cout << "search and print\n"; break;
case 'd':
cout << "delete\n";break;
case 'i':
cout << "insert\n";break;
case 'q':
cout << "Quitin programm.\n";
return 0;
}
}
return 0;
}
void sort_by_last(organizer* head_ptr)
{
organizer* node = head_ptr;
organizer* temp = NULL;
while (node->next != NULL)
{
if(node->last_name > node->next->last_name)
{
temp = node;
node = node->next;
temp->next = node;
node = temp;
}
}
}
Don't use struct, use class instead.
class Organizer
{
Organizer() { next = NULL; };
string first_name;
string last_name;
int number;
string email;
string bday;
Organizer* next;
bool operator <(const Organizer &other)
{ return last_name.compare(other.last_name) == -1; };
};
I don't think string supports <, so I used compare instead.
Since you only have a single-linked-list, not double-linked (only next variable, not previous as well), sort needs to take a **, or you need to compare ->next and ->next->next and have a blank head item.
Change sort_by_last(organizer); to sort_by_last(&head_ptr);
The sort function will look something like (assuming you want to do insertion sort, which is slow but simple): (untested)
void sort_by_last(Organizer **head_ptr)
{
Organizer **node = head_ptr;
while (*node != NULL)
{
Organizer **temp = head_ptr;
Organizer **next = &(*node)->next;
while (*temp != NULL && **temp < **node)
temp = &(*temp)->next;
if (*temp != NULL && *temp != *node)
{
(*node)->next = *temp;
(*temp)->next = (*node)->next;
*temp = *node; // same as (*temp)->prev->next = *node
*node = NULL; // so we don't point back to earlier in the list
}
node = next;
}
}
I assume you have to use a linked-list, but std::set would be a much simpler solution (it sorts on insert).
#include <set>
std::set<Organizer> theSet;
...
Organizer organizer;
// set up organizer
theSet.insert(organizer);
My linked lists program works, but it wont show all of the list
here is my code
When the user enters a name and contribution it stores it in the list. When i print out the list only the last name that the user entered showed. I think its in my AddToList function is the problem Thanks
#include <string>
using namespace std;
struct PersonRec
{
char aName[20];
//string aName;
int aBribe;
PersonRec* link;
};
class PersonList
{
private:
PersonRec *head;
bool IsEmpty();
public:
PersonList();
~PersonList();
void AddToList();
void ViewList();
};
#include <iostream>
#include <string>
using namespace std;
#include "personlist.h"
PersonList::PersonList()
{
head = NULL;
}
PersonList::~PersonList()
{
PersonRec *current, *temp;
current = head;
temp = head;
while(current != NULL)
{
current = current->link;
delete temp;
temp = current;
}
}
bool PersonList::IsEmpty()
{
//PersonRec *p;
if(head == NULL)//it has no nodes head will poin to NULL
{
return true;
}
else
{
//p = head;
return false;
}
}
void PersonList::AddToList()
{
PersonRec *p;
head = new PersonRec();
//if(head == NULL)
//{
if(!IsEmpty())
{
//head = new PersonRec();
cout<<"Enter the person's name: ";
cin.getline(head->aName, 20);
//cin>>head->aName;
cout<<"Enter the person's contribution: ";
cin>>head->aBribe;
//head->link = NULL;
//}
}
else
{
p = head;
while(p->link != NULL)
p = p->link;
p->link = new PersonRec();
}
}//end function
void PersonList::ViewList()
{
PersonRec *p;
p = head;
if(IsEmpty())
{
cout<<"List is Empty "<<endl;
}
while(p != NULL)
{
cout<<p->aName<<" "<<"$"<<p->aBribe<<endl;
p = p->link;
}
}
#include <iostream>
#include "personlist.h"
using namespace std;
int displayMenu (void);
void processChoice(int, PersonList&);
int main()
{
int num;
PersonList myList;
do
{
num = displayMenu();
if (num != 3)
processChoice(num, myList);
} while (num != 3);
return 0;
}
int displayMenu(void)
{
int choice;
cout << "\nMenu\n";
cout << "==============================\n\n";
cout << "1. Add student to waiting list\n";
cout << "2. View waiting list\n";
cout << "3. Exit program\n\n";
cout << "Please enter choice: ";
cin >> choice;
cin.ignore();
return choice;
}
void processChoice(int choice, PersonList& p)
{
switch(choice)
{
case 1: p.AddToList();
break;
case 2: p.ViewList();
break;
}
}
Think about it: head is a pointer to the first item in your list, and the first thing you do in AddToList() is:
head = new PersonRec();
What do you think is going to happen to the current list when you overwrite head in this manner?
Don't change head until you're ready. The basic pseudo-code would be:
newnode = new PersonRec; # Don't overwrite head yet.
# Populate newnode with payload.
newnode-> next = head # Put current list at end.
head = newnode # Now you can change it.
That's if you wanted the new node at the start of the list. If you want it at the end, it's a little more complicated since you either have to:
traverse the list looking for the last node so you can append the new node to it; or
keep a pointer to the last node as well, to avoid traversal.
But the detail remains the same: don't destroy your head pointer until such time as you have the current list accessible by some other means.
I should mention that, based on your commented out code in AddToList(), you appear to be very close. Setting head should be done in the case where isEmpty() is true. But you appear to have commented that out and moved the head = new ... bit to outside/before the if statement. Not sure exactly what happened there with your thought processes.
It looks like what you tries to do was along the lines of:
if isEmpty:
head = new PersonRec;
p = head
else:
p = head
while p->next != NULL:
p = p->next
p->next = new PersonRec;
p = p->next
# Here, p is a pointer to the new node (head or otherwise)
# and the list is stable
p-> payload/link = whatever/null
That last line is also important, and your code doesn't seem to do it in all cases (ie, other than when you're creating the initial node in the list).
Making that a little less language-agnostic would give you something like (untested):
void PersonList::AddToList() {
PersonRec *p;
if(!IsEmpty()) {
p = head = new PersonRec();
} else {
p = head;
while (p->link != NULL)
p = p->link;
p->link = new PersonRec();
p = p->link;
}
cout << "Enter the person's name: ";
cin.getline (p->aName, 20);
cout << "Enter the person's contribution: ";
cin >> p->aBribe;
p->link = NULL;
}