PPP2 Chapter 17 Exercise 11

Pages: 1... 678910... 16

Please post the "final" complete code so I can verify your outputs for myself, I seem to be getting much different results than what you seem to be getting.

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
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
// Osman Zakir
// 9 / 7 / 2017
// Bjarne Stroustrup: Programming: Principles and Practice Using C++ 2nd Edition
// Chapter 17 Exercises 11-13

#include <iostream>
#include "../../cust_std_lib_facilities.h"

struct God
{
	God(const std::string &name, const std::string &myth, const std::string &vehicle, const std::string &weapon)
		: m_name{ name }, m_myth{ myth }, m_vehicle{ vehicle }, m_weapon{ weapon } { }

	std::string name() const { return m_name; }
	std::string myth() const { return m_myth; }
	std::string vehicle() const { return m_vehicle; }
	std::string weapon() const { return m_weapon; }

	void set_name(const std::string name) { m_name = name; }
	void set_myth(const std::string myth) { m_myth = myth; }
	void set_vehicle(const std::string vehicle) { m_vehicle = vehicle; }
	void set_weapon(const std::string weapon) { m_weapon = weapon; }
private:
	std::string m_name;
	std::string m_myth;
	std::string m_vehicle;
	std::string m_weapon;
};

class Link
{
public:
	Link(const God &god, Link *p = nullptr, Link *s = nullptr)
		: m_god{ god }, m_prev{ p }, m_succ{ s } { }

	Link *insert(Link *n);                              // insert n before this object
	Link *add(Link *n);                                 // insert n after this object
	Link *erase();                                      // remove this object from list
	Link *find(const std::string &name);                // find values in list
	const Link *find(const std::string &name) const;    // find values in const list
	Link *advance(int n) const;                         // advance n positions in list
	Link *add_ordered(Link *n);
	int element_count();

	God god() const { return m_god; }
	Link *next() const { return m_succ; }
	Link *previous() const { return m_prev; }

private:
	God m_god;
	Link *m_prev;
	Link *m_succ;
};

void print_all(Link *p);

int main()
{
	try
	{
		Link *norse_gods = new Link{God{ "Odin", "Norse", 
			"Eight-legged flying horse called Sleipnir", "Spear called Gungnir" } };
		norse_gods = norse_gods->add_ordered(new Link{ God{ "Thor", "Norse", 
			"Chariot pulled by goats Tanngrisnir and Tanngnjostr", "Hammer called Mjolnir" } });
		norse_gods = norse_gods->add_ordered(new Link{ God{ "Frejya", "Norse", 
			"Chariot pulled by two cats", "Magic called seidr" } });
		norse_gods = norse_gods->add_ordered(new Link{ God{"Baldr", "Norse", "Ship called Hringorni", "None"} });
		
		Link *greek_gods = new Link{ God{ "Zeus", "Greek", "A chariot pulled by horses", "Thunderbolt" } };
		greek_gods = greek_gods->add_ordered(new Link{ God{"Ares", "Greek", 
			"War chariot (with his siblings accompanying him)","A spear covered in blood"} });
		greek_gods = greek_gods->add_ordered(new Link{ God{"Hera", "Greek", 
			"Chariot pulled by peacocks", "Her intelligence"} });
		greek_gods = greek_gods->add_ordered(new Link{ God{ "Athena", "Greek", 
			"Many choices, but used none", "Entrusted with Zeus's thunderbolt and Aegis" } });

		print_all(norse_gods);
		std::cout << '\n';
		print_all(greek_gods);
		
		std::cout << "\n\nNumber of nodes in Norse list is: " << norse_gods->element_count() << '\n';
		std::cout << "Number of nodes in Greek list is: " << greek_gods->element_count() << '\n';
	}
	catch (const std::runtime_error &rte)
	{
		std::cerr << "Runtime error: " << rte.what() << '\n';
		keep_window_open();
		return 1;
	}
	catch (const std::exception &e)
	{
		std::cerr << "Exception: " << e.what() << "\n";
		keep_window_open();
		return 2;
	}
	catch (...)
	{
		std::cerr << "An unknown exception occurred\n";
		keep_window_open();
		return 3;
	}

	keep_window_open();
}

Link *Link::insert(Link *n)
{
	if (n == nullptr)
	{
		return this;
	}
	n->m_succ = this;
	if (m_prev)
	{
		m_prev->m_succ = n;
	}
	n->m_prev = m_prev;
	m_prev = n;
	return n;
}

Link *Link::add(Link *n)
{
	if (n == nullptr)
	{
		return this;
	}
	n->m_prev = this;
	if (m_succ)
	{
		m_succ->m_prev = n;
	}
	n->m_succ = m_succ;
	m_succ = n;
	return n;
}

Link *Link::erase()
{
	Link *trav = this;
	if (trav == nullptr)
	{
		return this;
	}
	if (trav->m_succ)
	{
		trav->m_succ->m_prev = trav->m_prev;
	}
	if (trav->m_prev)
	{
		trav->m_prev->m_succ = trav->m_succ;
	}
	return trav->m_succ;
}

Link *Link::find(const std::string &name)
{
	Link *trav = this;
	while (trav != nullptr)
	{
		if (trav->m_god.name() == name)
		{
			return trav;
		}
		trav = trav->m_succ;
	}
	return this;
}

const Link *Link::find(const std::string &name) const
{
	const Link *c_trav = this;                    // const pointer
	Link *nc_trav = const_cast<Link*>(c_trav);    // non-const pointer
	while (c_trav != nullptr && nc_trav != nullptr)
	{
		if (c_trav->m_god.name() == name)
		{
			return c_trav;
		}
		nc_trav = nc_trav->m_succ;
	}
	return this;
}

Link *Link::advance(int n) const
{
	Link *trav = const_cast<Link *>(this);
	if (trav == nullptr)
	{
		return const_cast<Link*>(this);
	}
	if (n > 0)
	{
		while (n--)
		{
			if (trav->m_succ == nullptr)
			{
				return const_cast<Link*>(this);
			}
			trav = trav->m_succ;
		}
	}
	else if (n < 0)
	{
		while (n++)
		{
			if (trav->m_prev == nullptr)
			{
				return const_cast<Link*>(this);
			}
			trav = trav->m_prev;
		}
	}
	return trav;
}

/**
 * This function's specs are as follows:
 * Add a member function add_ordered() that places its new element in its correct lexicographical position.
 * Using the Links with the values of type God, make a list of gods from three mythologies; then move the
 * elements (gods) from that list to three lexicographically ordered lists — one for each mythology.
 */
Link *Link::add_ordered(Link *n)
{
	if (!n)
	{
		return this;
	}

	Link *trav = this;
	if (!trav)
	{
		return this;
	}

	// to make sure we start at head of list
	while (trav->m_prev)
	{
		trav = trav->m_prev;
	}

	std::string key = n->m_god.name();
	if (trav->m_god.name() < key)
	{
		trav = trav->add(n);
	}
	else if (trav->m_god.name() > key)
	{
		trav = trav->insert(n);
	}
	else if (trav->m_god.name() == key)
	{
		error("Name of god to be inserted can't be the same as the name of a god already in the list");
	}

	while (trav->m_god.name() < key && trav->m_succ)
	{
		trav = trav->m_succ;
	}
	return trav;
}

int Link::element_count()
{
	Link *trav = this;
	int size = 0;
	if (trav)
	{
		while (trav->m_prev)
		{
			trav = trav->m_prev;
		}

		while (trav->m_succ)
		{
			size++;
			trav = trav->m_succ;
		}
	}
	return size + 1;
}

void print_all(Link *p)
{
	while (p->previous())
	{
		p = p->previous();
	}

	std::cout << "{\n";
	while (p)
	{
		std::cout << "Name: " << p->god().name()
			<< "; Myth: " << p->god().myth();
		if (p->god().vehicle() != "")
		{
			std::cout << "; Vehicle: " << p->god().vehicle();
		}
		else
		{
			std::cout << "; Vehicle: N/A";
		}
		std::cout << "; Weapon: " << p->god().weapon();
		if ((p = p->next()))
		{
			std::cout << "\n";
		}
	}
	std::cout << "\n}\n";
}
Last edited on
And before I forget, here's the output for that:
{
Name: Baldr; Myth: Norse; Vehicle: Ship called Hringorni; Weapon: None
Name: Frejya; Myth: Norse; Vehicle: Chariot pulled by two cats; Weapon: Magic called seidr
Name: Odin; Myth: Norse; Vehicle: Eight-legged flying horse called Sleipnir; Weapon: Spear called Gungnir
Name: Thor; Myth: Norse; Vehicle: Chariot pulled by goats Tanngrisnir and Tanngnjostr; Weapon: Hammer called Mjolnir
}

{
Name: Ares; Myth: Greek; Vehicle: War chariot (with his siblings accompanying him); Weapon: A spear covered in blood
Name: Athena; Myth: Greek; Vehicle: Many choices, but used none; Weapon: Entrusted with Zeus's thunderbolt and Aegis
Name: Hera; Myth: Greek; Vehicle: Chariot pulled by peacocks; Weapon: Her intelligence
Name: Zeus; Myth: Greek; Vehicle: A chariot pulled by horses; Weapon: Thunderbolt
}


Number of nodes in Norse list is: 4
Number of nodes in Greek list is: 4
Just as I thought you need to more thoroughly test your add_ordered() function. Here is another run with the same gods you used but in a different order.
1
2
3
4
5
6
7
8
9
10
		Link *norse_gods = new Link{God{ "Odin", "Norse",
			"Eight-legged flying horse called Sleipnir", "Spear called Gungnir" } };

        norse_gods = norse_gods->add_ordered(new Link{ God{"Baldr", "Norse", "Ship called Hringorni", "None"} });

		norse_gods = norse_gods->add_ordered(new Link{ God{ "Thor", "Norse",
			"Chariot pulled by goats Tanngrisnir and Tanngnjostr", "Hammer called Mjolnir" } });

		norse_gods = norse_gods->add_ordered(new Link{ God{ "Frejya", "Norse",
			"Chariot pulled by two cats", "Magic called seidr" } });


And the output:

1
2
3
4
5
6
{
Name: Baldr; Myth: Norse; Vehicle: Ship called Hringorni; Weapon: None
Name: Frejya; Myth: Norse; Vehicle: Chariot pulled by two cats; Weapon: Magic called seidr
Name: Thor; Myth: Norse; Vehicle: Chariot pulled by goats Tanngrisnir and Tanngnjostr; Weapon: Hammer called Mjolnir
Name: Odin; Myth: Norse; Vehicle: Eight-legged flying horse called Sleipnir; Weapon: Spear called Gungnir
}


Notice how the output is not in the correct order?



What did TheIdeasMan say before? I'll try it that way. Was it that I have to insert the new node before the next one if it's less than the current node? Or am I remembering it wrong?

And you guys also told me some pretty confusing things. One guy says I won't need two kinds of insert functions and that there's no need for an if-condition. Another guy says I'd need both the add and insert functions, but said nothing about needing an if-condition. It was because of that that I thought that the second loop needed to be used to insert the node. And when I asked if I needed to care about the name of the god to be inserted being greater than that of the current god, I was told something like "no, because everything is based on less than". I tried doing that the way my code is now, and it gave me lists with only two nodes in them.

Please try to be careful with what you say and don't confuse me. And reading misleading advice really isn't helping.

Edit: I could just try to sort the list afterwards if it's still out of order when I exit the second loop. I just need to know a good way to swap nodes and also a way to change the head of the list when trying to swap the current head with another node.
Last edited on
Is the reason it's buggy right now perhaps because there's still something I need to do in in the second loop? Like, for example, swapping nodes that are still out of order?

If so, then I'll also need some tips on how to define a swap() function for the Link class. I know how to define it for built-in types and for pointers to built-in types, but I'm not sure how to do it for a linked list. I'm also scared that I might mess up and lose the whole list by swapping with the head of the list incorrectly.
Is the reason it's buggy right now perhaps because there's still something I need to do in in the second loop? Like, for example, swapping nodes that are still out of order?

No to both. I've already hinted several times as to what you need to do so I won't repeat myself again.

And you guys also told me some pretty confusing things.

Actually I think you may have read some pretty confusing things, but that doesn't mean anyone actually said anything confusing.

One guy says I won't need two kinds of insert functions and that there's no need for an if-condition.

I asked once before, who told you this?

Another guy says I'd need both the add and insert functions, but said nothing about needing an if-condition.

And your point is?

It was because of that that I thought that the second loop needed to be used to insert the node.

This is one of the places you thought wrong.

And when I asked if I needed to care about the name of the god to be inserted being greater than that of the current god, I was told something like "no, because everything is based on less than".

That's right everything is based on less than. If it's not less than then what is it?

I tried doing that the way my code is now, and it gave me lists with only two nodes in them.

That's because your current code is wrong, it has nothing to do with less than or greater than.

Please try to be careful with what you say and don't confuse me.

To this I say you need to be careful that you read everything that was written, not just try to read what you want to read.


Edit: I could just try to sort the list afterwards if it's still out of order when I exit the second loop. I just need to know a good way to swap nodes and also a way to change the head of the list when trying to swap the current head with another node.


And how are you going to sort the list after the fact? Sorting a linked list is not as easy as you're trying to make it sound.

You still don't seem to understand the purpose of the second loop and until you do you will never be able to figure out this problem, especially since you refuse to try to trouble shoot the problems for yourself.

It's not like I refuse to troubleshoot it myself. It's more that I don't understand how to take what's happening when I do. You really think I like reading bad stuff about myself like this? I'm not a masochist.
Okay, I'll have to ask you to point me to the posts where you gave those hints. I'll read them all again.

By the way, is there an online C++ course I can audit that comes with mentors? I've never had a mentor help me with this stuff, and I've heard that having one helps. Even if it's not an actual course, as long as I can just get help with stuff I don't understand about debugging and algorithms, it'd be a great help. Well, that and three of the GUI programming exercises in this book, namely the analog clock, the moving airplane image, and the bar graph class. It seems like I can do most of the other stuff better by having a better grasp of debugging and algorithms. I do know the basics of the language itself, but the problem is practice and a danger of forgetting stuff. But I can't say I know the whole language or the whole standard since I'm stumped on iterators and iterator_traits (for one thing).
Okay, I'll have to ask you to point me to the posts where you gave those hints. I'll read them all again.

Like I said I'm not going to keep repeating myself, the posts are there, you can go back and re-read them for yourself.

I will give you one more hint: It is not necessarily what you're doing that is wrong but when you're doing something that is the problem.

It's more that I don't understand how to take what's happening when I do.

It seems to me that you simply refuse to even try to debug. I have had you define and implement a function that can help you understand what is happening in this program yet you have shown little to no interest in using that function to help you understand what your code is actually doing.


By the way, is there an online C++ course I can audit that comes with mentors? I've never had a mentor help me with this stuff, and I've heard that having one helps.

I can't really recommend an online C++ course for you. I really suggest you see about finding either a class at local university or find someone local that can mentor you so you can get the more individualized attention you seem to need. If that is not possible then I would recommend you try a different book as this book doesn't seem to fit with your way of thinking.

Even if it's not an actual course, as long as I can just get help with stuff I don't understand about debugging and algorithms, it'd be a great help.

Perhaps you need to re-read Chapter 5 (and redoing all the "Try this" and all the drills and exercises) paying particular attention to the sections on debugging and testing. And possibly Chapter 6 as well, again doing all of the drills and exercises.

But I can't say I know the whole language or the whole standard since I'm stumped on iterators and iterator_traits (for one thing).

Unless the version of the book I have is a great deal different than the version of the book you seem to be using, it doesn't cover iterators for another few chapters. So unless you're jumping ahead of yourself you shouldn't be concerned about them as of yet and if your are jumping ahead of yourself I suggest you jump backwards instead.

I do know the basics of the language itself,

I will say that you have some understanding of the basics of the language, but I will also say that you still have a long way to go before you can say you have a total understanding of the basics of the language. I will also say that you're not alone, one of your biggest stumbling blocks is pointers which is understandable, pointers tend to get tricky quickly.
But I can't say I know the whole language or the whole standard

That is good, I would say that there are only a very few people (if any) that might even suggest that they know the whole language.

I need to define a move iterator for the custom vector class. This code won't compile without it (it keeps saying either that there's no suitable operator+ (until I define one), or that there's no type named "iterator_category" in std::iterator_traits<vector>"; the problem is that I don't know how to specialize it in such a way that it'll have that):
1
2
3
4
5
6
vector::vector(const vector &arg)
	: sz{arg.size()},
	  elem{new double[arg.sz]}
{
	std::copy(arg, arg + sz, elem);
}


I'm not jumping ahead of myself, this is in Chapter 18. It just won't compile without a move iterator if I understand correctly.

I did try to use that function, and I even tried to manually put calls to cout in add_ordered(). But like I said, I don't understand how to use the output I get from that to debug the code. That's why I'm having a hard time here. It's not like I didn't try it at all. I mean, yeah, I can see if a pointer is pointing at nullptr or if it's pointing at one of the nodes (and see what node is being pointed at), but how do I know what to do with that information so I can debug the code?

I heard there are three people on this site who do mentoring for free? Who are they? I could try asking one of them.
Last edited on
I need to define a move iterator for the custom vector class.

No you don't, you need to define and implement your own copy() member function not try to use std::copy, but this is jumping ahead of yourself. Until you understand the problems with this program it really doesn't make sense to move to the next chapter since the next chapter is building upon this chapter.


I did try to use that function, and I even tried to manually put calls to cout in add_ordered().

You only showed code using that function, and the modifications to main() once. You never showed any code using the function inside your problem functions nor ask questions based on the output of that function anywhere, anytime.

But like I said, I don't understand how to use the output I get from that to debug the code.

What exactly don't you understand?

You have a bunch of pointers you need to follow the pointers. That function was designed to let you see the values of those pointers at the time of the call to that function. The modifications to main() were to allow you to see the values of those pointers before and after calls that are modifying those pointers so that perhaps you can see what is happening.

I mean, yeah, I can see if a pointer is pointing at nullptr or if it's pointing at one of the nodes (and see what node is being pointed at), but how do I know what to do with that information so I can debug the code?

This is probably because you don't really understand what needs to happen in those functions. And it is this lack of understanding that you must solve. For example I don't really think you fully comprehend the difference between your insert() and add() functions when it comes to the pointers involved.

And I doubt that you have stepped away from your code and used manual methods to emulate the operations of the program, as suggested by TheIdeasMan, which should also help you visualize the problem. You also seem unable to throw away your current methods and start totally over, again as suggested by TheIdeasMan, which is also important because your current implementation is flawed.

I also doubt that you have gone back and re-read and worked the exercises for those previous chapters that I suggested in my last post. It never hurts to go back and re-read and redo the exercises from earlier chapters. You may find it rewarding because your understanding should have improved since you initially read those chapters and you may even find something "new" that helps you better understand the problems you are currently having.

One of the problems you're currently encountering with this program is not your lack of understanding of how to program, but your lack of understanding how to design the program. Which is being caused by your lack of understanding the problem.

These understandings must happen before you even try to write any code.

I did try to use that function, and I even tried to manually put calls to cout in add_ordered(). But like I said, I don't understand how to use the output I get from that to debug the code. That's why I'm having a hard time here. It's not like I didn't try it at all. I mean, yeah, I can see if a pointer is pointing at nullptr or if it's pointing at one of the nodes (and see what node is being pointed at), but how do I know what to do with that information so I can debug the code?


I already gave you some advice about that last Wed (on page 7 of this thread).

(The advice was for using the debugger, but it applies just as much to debugging-by-print. Of course, the debugger would give you much more powerful tools to help you.)
Last edited on
That post was assuming I haven't used the debugger at all, though. But I'm saying I have, and that I just don't understand how to interpret the results in order to debug my program.

I can tell, for example, that when it comes to the current node being Odin's and the node to insert being Thor's, for some reason it inserts the node before the current node instead of after.

I thought I may have been using add() or insert() at the wrong place with the wrong condition, but no matter how I change it or what I do, it's still wrong.

I think I might have to keep going backward as long as the previous pointer is not pointing at nullptr, while comparing the name string in the current node to the one I want to insert. If I find the right place before a node in the list (while checking if the name string in the node to insert is less than the one in the node being compared to), insert the node. When the node to insert is greater and the next pointer is not pointing at nullptr, keep traversing the next pointer(s) in the list while comparing the name strings until a place is found to insert the node.

But currently, either the node is not inserted at all or inserts it in the wrong order.

This is my code right now:
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
Link *Link::add_ordered(Link *n)
{
	if (!n)
	{
		return this;
	}

	Link *trav = this;
	if (!trav)
	{
		return this;
	}

	// to make sure we start at head of list
	while (trav->m_prev)
	{
		trav = trav->m_prev;
	}

	std::string key = n->m_god.name();
	if (!(trav->m_god.name() < key))
	{
		trav = trav->insert(n);
	}
	else if (trav->m_god.name() == key)
	{
		error("Name of god to be inserted can't be the same as the name of a god already in the list");
	}

	while (trav->m_god.name() < key && trav->m_succ)
	{
		trav = trav->add(n);
		trav = trav->m_succ;
	}
	return trav;
}


Again. My problem isn't that I haven't used my debugger at all. It's that I don't understand what to do with the information I see in it.
Last edited on
It's that I don't understand what to do with the information I see in it.

That's because you don't really understand the problem. And all you're doing by throwing more code at the problem is confusing yourself.

Start over, and when you start over don't worry about either of the pointers being a nullptr. If they are there is nothing that you can do to solve the problems so just let the program crash. I recommend starting with this:

1
2
3
4
5
6
7
8
9
Link *Link::add_ordered(Link *n)
{
	// to make sure we start at head of list
	while (trav->m_prev)
	{
		trav = trav->m_prev;
	}
        return this;
}


Your main() should just be adding the first element and calling this function two or three times. Make sure you note the order in which you add the gods in main().


Now do something so that you can easily follow what is happening in that loop. Don't forget to record the values so you can explain what happened and why after you are finished with the run.

Ie. what are the values of all the pointers and names of the two gods prior to the loop?

Next inside the loop what is the name of the god and the pointers at the beginning of the loop and at the end of the loop.

Finally what is the name of the god and the values of the pointers after the loop has completed.


Did all of the steps match your expectations?

If so explain step by step what happened ad why.

If not show where the program failed your expectations and try to explain why your expectations didn't match the results.





Last edited on
Okay, I'll try doing that.

Current main():
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
int main()
{
	try
	{
		Link *norse_gods = new Link{{ "Odin", "Norse", 
			"Eight-legged flying horse called Sleipnir", "Spear called Gungnir" } };
		norse_gods = norse_gods->add_ordered(new Link{ { "Baldr", "Norse", "Ship called Hringorni", "None" } });
		norse_gods = norse_gods->add_ordered(new Link{ { "Thor", "Norse", 
			"Chariot pulled by goats Tanngrisnir and Tanngnjostr", "Hammer called Mjolnir" } });
		norse_gods = norse_gods->add_ordered(new Link{ { "Frejya", "Norse", 
			"Chariot pulled by two cats", "Magic called seidr" } });
	}
	catch (const std::runtime_error &rte)
	{
		std::cerr << "Runtime error: " << rte.what() << '\n';
		keep_window_open();
		return 1;
	}
	catch (const std::exception &e)
	{
		std::cerr << "Exception: " << e.what() << "\n";
		keep_window_open();
		return 2;
	}
	catch (...)
	{
		std::cerr << "An unknown exception occurred\n";
		keep_window_open();
		return 3;
	}

	keep_window_open();
}


add_ordered():
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
Link *Link::add_ordered(Link *n)
{
	Link *trav = this;

	std::cout << "Before loop:\n";
	std::cout << "*this: " << this << '\n';
	std::cout << m_god.name() << '\n';
	std::cout << m_prev << '\n';
	std::cout << m_succ << '\n';

	std::cout << "*n: " << n << '\n';
	std::cout << n->m_god.name() << '\n';
	std::cout << n->m_prev << '\n';
	std::cout << n->m_succ << '\n';

	// to make sure to start at head of the list
	while (trav->m_prev)
	{
		std::cout << "\nInside loop (before \"trav = trav->m_prev\":\n";
		std::cout << "*this: " << this << '\n';
		std::cout << m_god.name() << '\n';
		std::cout << m_prev << '\n';
		std::cout << m_succ << '\n';

		std::cout << "*n: " << n << '\n';
		std::cout << n->m_god.name() << '\n';
		std::cout << n->m_prev << '\n';
		std::cout << n->m_succ << '\n';
		trav = trav->m_prev;
		std::cout << "\nInside loop (after \"trav = trav->m_prev\":\n";
		std::cout << "*this: " << this << '\n';
		std::cout << m_god.name() << '\n';
		std::cout << m_prev << '\n';
		std::cout << m_succ << '\n';

		std::cout << "*n: " << n << '\n';
		std::cout << n->m_god.name() << '\n';
		std::cout << n->m_prev << '\n';
		std::cout << n->m_succ << '\n';
	}

	std::cout << "\nAfter loop:\n";
	std::cout << "*this: " << this << '\n';
	std::cout << m_god.name() << '\n';
	std::cout << m_prev << '\n';
	std::cout << m_succ << '\n';

	std::cout << "*n: " << n << '\n';
	std::cout << n->m_god.name() << '\n';
	std::cout << n->m_prev << '\n';
	std::cout << n->m_succ << '\n';

	return this;
}


output:

Before loop:
*this: 014A1088
Odin
00000000
00000000
*n: 014A1130
Baldr
00000000
00000000

After loop:
*this: 014A1088
Odin
00000000
00000000
*n: 014A1130
Baldr
00000000
00000000
Before loop:
*this: 014A1088
Odin
00000000
00000000
*n: 014A11D8
Thor
00000000
00000000

After loop:
*this: 014A1088
Odin
00000000
00000000
*n: 014A11D8
Thor
00000000
00000000
Before loop:
*this: 014A1088
Odin
00000000
00000000
*n: 014A1280
Frejya
00000000
00000000

After loop:
*this: 014A1088
Odin
00000000
00000000
*n: 014A1280
Frejya
00000000
00000000


So the order is currently: Odin, Bladr, Thor, Frejya.

The loop didn't run because the previous pointer is pointing at nullptr. So for now I'll focus on what happened before and after the loop.

Before:
The current node is Odin's. Its previous and next pointers are both pointing at nullptr, as expected (because it's currently the only node in the list).

The node to insert is Baldr's. Its previous and next pointers are also both pointing at nulptr, which as expected. Its pointers were initialized to nullptr when it was created and until it's been added to the list, its previous pointer will be pointing at nullptr.

Then, after the loop:
Same as above, since the loop didn't run; only now while the current node is still Odin's, the node it's trying to add is Thor's. Then while the previous and next pointers are still pointing at nullptr, it is trying to add Frejya next.

So far, there's no surprise. It's as expected. The node with Odin in it is currently the only one in the list, so the previous pointer is pointing at nullptr. The printing code inside the loop didn't run because the loop didn't get to run. So the condition after the loop is almost the same except what n's name string and address are.
Last edited on
That post was assuming I haven't used the debugger at all, though. But I'm saying I have, and that I just don't understand how to interpret the results in order to debug my program.

No. Nothing I said was about the mechanics of how to use the debugger to get information. It was telling you how to use the information you're getting, to further investigate the problem. It doesn't matter whether you get that information from the debugger, or from print statements.

I can tell, for example, that when it comes to the current node being Odin's and the node to insert being Thor's, for some reason it inserts the node before the current node instead of after.

OK, that's a starting point. So, you use your knowledge and understanding of the code you wrote, to determine exactly what data you would need to see, in order to understand the problem. Then, you use your debugger - or printed output - to look at that data, and see what that tells you.

Think about what data you would need to see to be certain what is going on, and why. At what points is your list modified? What is the data before that modification? What is it afterwards? Examine those changes to see whether the changes you expect to see, are the ones you actually see.

If not, look at your code at that specific point, and see if you can see why the behaviour is differing from what you expect. Look at the points where decisions are taken. Look at the data that is used to make those decisions. Is the data there what you expected it to be? Are the decisions being made the ones you would expect to be made from that data?

Stop using your fingers to type, and start using your brain to think, and analyse, and work things out.

I thought I may have been using add() or insert() at the wrong place with the wrong condition, but no matter how I change it or what I do, it's still wrong.

What made you think that? What information did you have that clearly and exactly pinpointed that as your problem?

All along, people have been telling you that you need to stop making random changes to your code in the hope that it works, and to slow down and think.

Work out exactly what your code is supposed to do - using pen and paper, perhaps.

Work out exactly what your code is actually doing.

Work out how you need to change it do what you want it to do.

Don't write any code until you are certain of those things.

And if all that sounds like hard work, and less fun than you were expecting, then... welcome to programming.

EDIT: I wrote that before your last post.
Last edited on
So far, there's no surprise. It's as expected. The node with Odin in it is currently the only one in the list, so the previous pointer is pointing at nullptr. The printing code inside the loop didn't run because the loop didn't get to run. So the condition after the loop is almost the same except what n's name string and address are.

Very good.

So now what do you think you need to add?

Where?

Why?

I'm not asking you to add or change anything at this time just tell me the what, where, and why.

I think I need to add an if-statement to check if the name string in the node I want to add is less than the one in the current node. Why I think so is because it's part of what I need to do and because once there's another node in the list, the loop I have in there can run at least once depending on where I start in the list.

I'll add it after the loop. Before the print statements after the loop.

You said before that I still hadn't figured out the purpose for the second loop. But you'd also said that I'd gotten closer to the intended solution for this function, before I'd added code to the second loop to insert in a node if the while loop's condition is true.

When we get there, I'd like to know how close I was that time.

You said before that I still hadn't figured out the purpose for the second loop. But you'd also said that I'd gotten closer to the intended solution for this function, before I'd added code to the second loop to insert in a node if the while loop's condition is true.

That was so many changes ago, which is why you're basically starting over.

I'll add it after the loop. Before the print statements after the loop.

Well I'm recommending that you add it to the function after the present code. Don't remove anything that you had in your last post, and be sure to add a print statement after your new code.

I'm sure glad that you enjoy typing all of those lines instead of just calling a simple function multiple times.

Pages: 1... 678910... 16