Linked list display issue

So, I'm curious on this. This was my programming midterm, more or less a B/C on since it's incomplete. The goal of the program, is to make an address book, using linked lists and classes. The only problem I have run into however, is when it tries to display.

This is the display section. What happens is the user chooses to add a person's info to the linked list, then display the info. It will display the first node, then an exception/break happens, but it points the error into the string header file, instead of the main program itself. And on the exe file, it displays the info, then seems like it is trying to go to the next node, even though it shouldn't.

No matter what I try and change the loop to, or check it against, I'm always getting the error, and even though it won't affect my grade, I'm extremely curious why it was happening and if there is a solution. Thank you all

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void AddressBook::display() const
{
	ListNode *nodePtr = head;
	while (nodePtr != NULL)
	{
		//Print info
		cout << "Name is " << nodePtr->name << "." << endl;
		cout << "Address is " << nodePtr->address << "." << endl;
		cout << "Phone number is " << nodePtr->number << "." << endl;
		cout << "Date of birth is " << nodePtr->date << "." << endl;
		//Move on to next node
		nodePtr = nodePtr->next;
	}

}



Full program
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
  /*Using classes, design an address book to keep track of the names, addresses, phone numbers, and
dates of birth of family members.
The class should have the appropiate functions to access and view certain data from each object.
Using linked lists, your program should have the following operations:
a. Add or delete a new entry to the address book.
b. View the data in the address book.*/

#include <iostream>
#include <string>
using namespace std;

class AddressBook
{
protected:
	struct ListNode
	{
		ListNode *next;
		string name;
		string address;
		string number;
		string date;
		ListNode(string name1, string address1, string number1, string date1, ListNode *next1 = NULL)
		{
			name = name1;
			address = address1;
			number = number1;
			date = date1;
		}
	};
	ListNode *head;
public:
	AddressBook() { head = NULL; }
	void add(string name, string address, string number, string date);
	void remove(string name, string address, string number, string date);
	void display() const;
};

void AddressBook::add(string name, string address, string number, string date)
{
	if (head == NULL)
	{
		head = new ListNode(name, address, number, date);
	}
	else
	{
		ListNode *nodePtr = head;
		while (nodePtr->next != NULL)
		{
			nodePtr = nodePtr->next;
		}
		nodePtr->next = new ListNode(name, address, number, date);
	}
}

void AddressBook::remove(string name, string address, string number, string date)
{
	ListNode *nodePtr = new ListNode(name, address, number, date);
	ListNode *previous = new ListNode(name, address, number, date);

	//If list is empty, do nothing
	if (!head) return;

	//Determine if the first node is the one to delete
	if (head->name == name, head->address == address, head->number == number, head->date == date)
	{
		nodePtr = head;
		head = head->next;
		delete nodePtr;
	}
	else
	{
		//Initialize nodePtr to the head of the list
		nodePtr = head;

		//Skip nodes whose value member is not matching
		while (nodePtr != NULL && nodePtr->name != name, nodePtr->address != address, nodePtr->number != number, nodePtr->date != date)
		{
			previous = nodePtr;
			nodePtr = nodePtr->next;
		}
		//Link previous node to the node after nodePtr, then delete nodePtr
		if (nodePtr)
		{
			previous->next = nodePtr->next;
			delete nodePtr;
		}
	}
}

void AddressBook::display() const
{
	ListNode *nodePtr = head;
	while (nodePtr != NULL)
	{
		//Print info
		cout << "Name is " << nodePtr->name << "." << endl;
		cout << "Address is " << nodePtr->address << "." << endl;
		cout << "Phone number is " << nodePtr->number << "." << endl;
		cout << "Date of birth is " << nodePtr->date << "." << endl;
		//Move on to next node
		nodePtr = nodePtr->next;
	}

}

int main()
{
	AddressBook book;
	string name;
	string address;
	string number;
	string date;

	int choice;
	char again;

	do
	{
		cout << "   Your address book." << endl;
		cout << endl;
		cout << "1. Add someone." << endl;
		cout << "2. Remove someone." << endl;
		cout << "3. Print." << endl;
		cout << "4. Quit." << endl;
		cin >> choice;
		cin.ignore();


		if (choice == 1)
		{
			cout << "Enter the persons name." << endl;
			getline(cin, name);
			cout << endl;
			cout << "Enter " << name << "'s address." << endl;
			getline(cin, address);
			cout << endl;
			cout << "Enter " << name << "'s phone number." << endl;
			getline(cin, number);
			cout << endl;
			cout << "Enter " << name << "'s date of birth." << endl;
			getline(cin, date);
			cout << endl;
			book.add(name, address, number, date);
		}
		else if (choice == 2)
		{
			cout << "Enter the persons name you would like to remove." << endl;
			getline(cin, name);
			cout << endl;
			cout << "Enter " << name << "'s address." << endl;
			getline(cin, address);
			cout << endl;
			cout << "Enter " << name << "'s phone number." << endl;
			getline(cin, number);
			cout << endl;
			cout << "Enter " << name << "'s date of birth." << endl;
			getline(cin, date);
			cout << endl;
			book.remove(name, address, number, date);
		}
		else if (choice == 3)
		{
			cout << "Printing the list." << endl;
			book.display();
		}
		else if (choice != 4)
		{
			cout << "Valid choices are 1-4" << endl;
			cout << "Please enter a number 1-4." << endl;
		}

		cout << endl;
		cout << "Run the program again?" << endl;
		cin >> again;
		cin.ignore();
	} while (again == 'Y' || again == 'y');

	system("pause");
	return 0;
}
Hi,

A compiler warning, using cpp.sh.

In file included from /usr/include/_G_config.h:15:0,
from /usr/include/libio.h:31, from /usr/include/stdio.h:74,
from /usr/include/c++/4.9/cstdio:42,
from /usr/include/c++/4.9/ext/string_conversions.h:43,
from /usr/include/c++/4.9/bits/basic_string.h:2850,
from /usr/include/c++/4.9/string:52,
from /usr/include/c++/4.9/bits/locale_classes.h:40,
from /usr/include/c++/4.9/bits/ios_base.h:41,
from /usr/include/c++/4.9/ios:42,
from /usr/include/c++/4.9/ostream:38,
from /usr/include/c++/4.9/iostream:39,
from 8: 22:91: warning: unused parameter 'next1' [-Wunused-parameter]


Even though it's only an unused variable warning, because of all those system header files it make me think this is about the use of using namespace std; Now might be a good time to bite the bullet and not do that. The easiest way is to put std:: before each std thing. That is what all the experts do.

Apart from that, consider using a debugger - it will save you days of staring at code. Hopefully there is a GUI one in your IDE.

Some other things I notice:

Don't use NULL with pointers, c++11 has nullptr for this purpose.

LIne 64: The comma's don't do what you think they do. Use the && operator instead.

You shouldn't be using new and delete, use smart pointers instead. Research std::unique_ptr

Line 76: I have a pathological hatred of conditions like that. Consider having a bool function that returns whether it is a match or not. Can you give your nodes a unique number, so as to avoid having to compare every field?

Line 166: you 4 options in the menu but this line doesn't allow option 4. Consider doing this instead, it avoids the do loop as well:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
bool Quit = false;
while (!Quit) {
   // show menu
   // get menu choice
   switch (choice) {
      // the options as you have them
      // ...
      // ...
      case 4:
          Quit = true;
           break;
      default:  // catch bad input
          std::cout << "Bad Input Try Again\n";
          break;
   } 
}


I copied that code from another post, but hopefully you get the idea. You could do the same thing with an else statement to catch the bad input, the else is analogous to default:

1
2
3
4
5
6
7
8
9
10
11
12
bool Quit = false;
while (!Quit) {
// ...
// ...
   else if (choice == 4) { // user wants to quit
      Quit = true;
      break;
   }
   else { // bad input
      std::cout << "Bad input - try again \n";
   }
}


The code for options 1 and 2 is nearly identical, you should have a function to get that input.

Good Luck !!
Topic archived. No new replies allowed.