C++ without Fear (2nd Ed) Exercise 15.2.2. Help Please.

Hello,

I'm working through the above book and I've become stuck at this exercise (spent a few hours so far).

The example code given performs the 'Towers of Hanoi' using classes.

The exercise asks to convert the rings array into a pointer of type int* and to use the new keyword.

I've learned a lot so far (with lots of help from this forum) but I think my non-perfect knowledge of pointers, classes and the new keyword have combined and made it impossible for me to even work out what's wrong. I get several different error messages depending upon what I do.

The original exercise question and code are both given below.

Thanks in advance.


Exercise 15.2.2. Instead of implementing rings as an array inside each object, implement it as a pointer of type int*. Then use new, within the populate and clear member functions, to allocate a series of integers. Can you use the delete keyword to efficiently prevent memory leaks in this situation?

-------
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
#include <iostream>
using namespace std;
#define MAX_LEVELS 10

// Declare three pole positions, or rather, stacks.
// Each stack is an object containing ring values.
// stacks[3] is an array three of these objects.
class mystack {
public:
	int rings[MAX_LEVELS]; // Array of ring values.
	int tos; // Top-of-stack index.
	void populate(int size); // Initialize stack.
	void clear(int size); // Clear the stack.
	void push(int n);
	int pop(void);
} stacks[3];

void mystack::populate(int size) {
	for (int i = 0; i < size; i++)
		rings[i] = i + 1;
	tos = -1;
}
void mystack::clear(int size) {
	for (int i = 0; i < size; i++)
		rings[i] = 0;
	tos = size - 1;
}
void mystack::push(int n) {
	rings[tos--] = n;
}
int mystack::pop(void) {
	int n = rings[++tos];
	rings[tos] = 0;
	return n;
}
void move_stacks(int src, int dest, int other, int n);
void move_a_ring(int source, int dest);
void print_stacks(void);
void pr_chars(int ch, int n);
int stack_size = 7;


int main() {
	stacks[0].populate(stack_size);
	stacks[1].clear(stack_size);
	stacks[2].clear(stack_size);
	print_stacks();
	move_stacks(stack_size, 0, 2, 1);
	return 0;
}
// Move stacks: solve problem recursively...
// move N stacks by assuming problem solved for N-1.
// src = source stack, dest = destination stack.
//
void move_stacks(int n, int src, int dest, int other){
	if (n == 1)
		move_a_ring(src, dest);
	else {
		move_stacks(n-1, src, other, dest);
		move_a_ring(src, dest);
		move_stacks(n-1, other, dest, src);
	}
}
// Move a Ring: Pop off a ring from source (src) stack,
// place it on destination stack, and print new state.
//
void move_a_ring(int source, int dest) {
	int n = stacks[source].pop(); // Pop off source.
	stacks[dest].push(n); // Push onto dest.
	print_stacks(); // Show new state.
}
// Print Stacks: For each physical level, print the
// ring for each of the three stacks.
//
void print_stacks(void) {
int n = 0;

	for (int i = 0; i < stack_size; i++) {
		for (int j = 0; j < 3; j++) {
			n = stacks[j].rings[i];
			pr_chars(' ', 12 - n);
			pr_chars('*', 2 * n);
			pr_chars(' ', 12 - n);
		}
		cout << endl;
	}
	system("PAUSE");
}
void pr_chars(int ch, int n) {
	for (int i = 0; i < n; i++)
		cout << (char) ch;
}


Last edited on
[code] "Please use code tags" [/code]
So, ¿what did you do?
Sorry, very new to this forum, I assumed there must be someway of writing code. I've updated it.

This is my last attempt, which also failed. In particular, Xcode highlights line 38.

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


#include <iostream>
using namespace std;
#define MAX_LEVELS 10

// Declare three pole positions, or rather, stacks.
// Each stack is an object containing ring values.
// stacks[3] is an array three of these objects.
class mystack {
public:
	//int rings[MAX_LEVELS]; // Array of ring values.
	
	int *rings;
	
	int tos; // Top-of-stack index.
	void populate(int size); // Initialize stack.
	void clear(int size); // Clear the stack.
	void push(int n);
	int pop(void);
	
	~mystack(){cout <<"\nDeleting *rings \n"; delete [] rings;}
	
} stacks[3];
void mystack::populate(int size) {
	delete [] rings;
	rings = new int[size];
	int i = 1;
	while(size-- > 0){
		*(rings++) = i++;
	}
	
	tos = -1;
}
void mystack::clear(int size) {

	while(size-- > 1){
		*(rings) = 0;
		rings++;
	}
	
	tos = size - 1;
}
void mystack::push(int n) {
	
//	rings[tos--] = n;
	rings + tos--;
	*rings = n;
}
int mystack::pop(void) {
//	int n = rings[++tos];
	//rings[tos] = 0;
	++tos;
	rings + tos;
	int n = *rings;
	*rings = 0;
	
	return n;
}
void move_stacks(int src, int dest, int other, int n);
void move_a_ring(int source, int dest);
void print_stacks(void);
void pr_chars(int ch, int n);


int stack_size = 4;
int main() {
	stacks[0].populate(stack_size);
	stacks[1].clear(stack_size);
	stacks[2].clear(stack_size);
	print_stacks();
	move_stacks(stack_size, 0, 2, 1);
	return 0;
}
// Move stacks: solve problem recursively...
// move N stacks by assuming problem solved for N-1.
// src = source stack, dest = destination stack.
//
void move_stacks(int n, int src, int dest, int other){
	if (n == 1)
		move_a_ring(src, dest);
	else {
		move_stacks(n-1, src, other, dest);
		move_a_ring(src, dest);
		move_stacks(n-1, other, dest, src);
	}
}
// Move a Ring: Pop off a ring from source (src) stack,
// place it on destination stack, and print new state.
//
void move_a_ring(int source, int dest) {
	int n = stacks[source].pop(); // Pop off source.
	stacks[dest].push(n); // Push onto dest.
	print_stacks(); // Show new state.
}
// Print Stacks: For each physical level, print the
// ring for each of the three stacks.
//
void print_stacks(void) {
int *n = 0;

	for (int i = 0; i < stack_size; i++) {
		for (int j = 0; j < 3; j++) {
//			n = stacks[j].rings[i];
			n = stacks[j].rings+i;
			pr_chars(' ', 12 - *n);
			pr_chars('*', 2 * *n);
			pr_chars(' ', 12 - *n);
		}
		cout << endl;
	}
	
	cin.get();
	
//	system("PAUSE");
}
void pr_chars(int ch, int n) {
	for (int i = 0; i < n; i++)
		cout << (char) ch;
}

Last edited on
bump
Invariants. Make sure that the pointer points to a dynamic allocated memory, or to NULL.
That has to be done starting at the constructor
1
2
3
4
5
6
void mystack::populate(int size) {
	delete [] rings; //deleting an invalid pointer
//...
void mystack::clear(int size) {
	while(size-- > 1){
		*(rings) = 0; //dereferencing an invalid pointer 
I'm sorry, I'm not following?

how should the constructor look? I assumed I was just using the default constructor?

Thanks
That is the problem. The default constructor is not good because it does not initialise the pointer.
closed account (DSLq5Di1)
As a general rule.. do not modify a pointer returned from new, delete will not know what to do with it. If you need to do some pointer voodoo, make a copy.

1
2
3
4
5
6
7
8
...
    mystack() : rings(0) {} // initialize rings to 0.
    ~mystack(){cout <<"\nDeleting *rings \n"; delete [] rings;}
private:
    void create(int size) { // inline helper function for populate() and clear().
        delete[] rings;
        rings = new int[size];
    }

1
2
3
4
5
6
7
8
9
void mystack::populate(int size) {
    create(size);
    int i = 1, *p = rings;

    while (size-- > 1) // loop will end when size is 0.
        *p++ = i++;

    tos = -1;
}

1
2
3
4
5
6
7
8
9
10
11
void mystack::clear(int size) {
    create(size);
    int *p = rings;

    tos = size - 1; // moved, see below.

    while (size--)
        *p++ = 0;

    tos = size - 1; // size is 0..  either move this line above or make a copy of size to use in your loop.
}

1
2
3
4
5
void mystack::push(int n) {
    rings + tos--; // perhaps you meant "rings = rings + tos--"?, dont modify rings!
    *rings = n;
    *(rings + tos--) = n;
}

1
2
3
4
5
6
7
8
9
10
int mystack::pop(void) {
    ++tos;
    rings + tos;
    int n = *rings;
    *rings = 0;
    int *p = rings + (++tos), n = *p;
    *p = 0;

    return n;
}
Thank-you very much! There's just one last question,

I didn't understand this line

mystack() : rings(0){}

I don't think I've come across the single use of the colon yet, what is it doing?

Thanks very much!
closed account (DSLq5Di1)
The colon signifies an initialization list for the constructor, see:-
http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.6
Topic archived. No new replies allowed.