Problem with this list

So, I tried doing this exercise, I compiled it and there were no errors nor warnings so it seemed fine to me.
This is the exercise:

1° Part
Create a list of entries made but the couple (key, info) represented with a vector of records. The record then creates the type entry which is made by "key" (integer) and "info" (C string dynamically allocated). For this type we have the following functions:
- read(e) // Let us insert and entry with the keyboard.
- write(e) // Let us print the entry on the screen.
- copy(e1,e2) // Copies e2 in e1.
- equal(e1, e2) // Let us know if the entries are equals.
- greater_than(e1, e2) // Let us know if the entry e1 is greater than entry e2.
Hypotesis: Two entries are equal only if both the values "key" and "info" are equal.
An entry is greater than another if the integer "key" of the first entry is greater than the integer "key" of the second entry.
The list is represented with a vector of elements of a set max dimension.
With this data struct we have the following functions:
- read(l,dim) // Let us initialize the list and insert the elements with the keyboard.
- write(l,dim) // Let us print the list on the screen.
- in(l,dim,x,pos) // Let us know if the element "x" exist in the list. If yes "pos" let us know the position of the first occurrence.
- sort(l,dim) // Sort the list (ascending order).

2° Part
Add to the list the following functions:
- full(l,dim) // Let us know if the list is full.
- empty(l,dim) // Let us know if the list is empty.
- insert(l,dim,e) // Let us insert an element in the list in the first free position.
- insert_sort(l,dim,e) // Applied to a sorted list. Let us insert the element "e" respecting the order.
- remove(l,dim,e) // Let us delete the entry "e" from the list if it exists.
- is_sorted(l,dim) // Let us know if the list is sorted (ascending order).

Skip the 2° part for now.
This is my code(I put everything in a project):

Entry.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>
#include <cstring>

using namespace std;

struct Entry {
	int Key;
	char *Info;
};

void create_Entry (Entry &);
void destroy_Entry (Entry &);
void read_Entry (Entry &);
void write_Entry (const Entry &);
void copy_Entry (Entry &, const Entry &);
bool equal_Entry (const Entry &, const Entry &);
bool greater_than_Entry (const Entry &, const Entry &);


Entry.cpp
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
#include "Entry.h"

void create_Entry (Entry &E) {
	E.Key = 0;
	E.Info = new char[0];
}

void destroy_Entry (Entry &E) {
	delete [] E.Info;
	E.Key = 0;
}

void read_Entry (Entry &E) {
	char buffer[100];
	
	cout << "Enter the key(must be a integer): ";
	cin >> E.Key;
	cout << "Enter the info: ";
	cin.getline(buffer, 100);
	if(E.Info) {
		delete [] E.Info;
	}
	E.Info = new char[strlen(buffer)+1];
	strcpy(E.Info, buffer);
}

void write_Entry (const Entry &E) {
	cout << "Key: " << E.Key << "\nInfo: " << E.Info << "\n";
}

void copy_Entry (Entry &E1, const Entry &E2) {
	if (strlen(E1.Info) != strlen(E2.Info)) {
		delete [] E1.Info;
		E1.Info = new char[strlen(E2.Info)+1];
	}
	strcpy(E1.Info, E2.Info);
	E1.Key = E2.Key;
}

bool equal_Entry (const Entry &E1, const Entry &E2) {
	return(E1.Key == E2.Key && (!strcmp(E1.Info, E2.Info)));
}

bool greater_than_Entry (const Entry &E1, const Entry &E2) {
	return(E1.Key > E2.Key);
}


List.h
1
2
3
4
5
6
7
8
9
10
11
12
13
#include "Entry.h"

const int SIZE = 10;

typedef Entry T;
typedef T List[SIZE];

void read_List(List &, int &);
void write_List(const List &, const int);
bool in_List(const List &, const int, const T &, int &);
void sort_List(List &, const int);
void swap(T &, T &);
void destroy_List(List &, int &);


List.cpp
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
#include "List.h"

void read_List(List &L, int &n) {
	cin >> n;
	for (int i = 0; i < n; i++) {
		create_Entry(L[i]);
		read_Entry(L[i]);
	}
}

void write_List(const List &L, const int n) {
	for (int i = 0; i < n; i++) {
		write_Entry(L[i]);
		cout << "\n";
	}
}

bool in_List(const List &L, const int n, const T &x, int &pos) {
	bool found = false;
	
	for (int i = 0; i < n; i++) {
		if(equal_Entry(L[i], x)) {
			found = true;
			pos = i;
			break;
		}
	}
	return found;
}

void swap(T &x, T &y) {
	T temp;
	
	copy_Entry(temp, x);
	copy_Entry(x, y);
	copy_Entry(y, temp);
}

void sort_List(List &L, const int n) {
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < (n - i - 1); j++) {
			if (greater_than_Entry(L[j], L[j+1])) {
				swap(L[j], L[j+1]);
			}
		}
	}
}

void destroy_List(List &L, int &n) {
	for (int i = 0; i < n; i++) {
		destroy_Entry(L[i]);
	}
}


main.cpp
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
#include "List.h"

int main(int argc, char** argv) {
	List L;
	Entry E;
	int dim = 0, pos = 0;
	
	create_Entry(E);
	cout << "Insert the number of elements and the entries:\n";
	read_List(L, dim);
	
	cout << "List:\n";
	write_List(L, dim);
	
	cout << "Insert the element to search:\n";
	if (in_List(L, dim, E, pos)) {
		cout << "The element exist. The first occurence is in position " << pos << "\n";
	}
	else {
		cout << "The element does not exist.\n";
	}
	
	cout << "Sorted list:\n";
	sort_List(L, dim);
	write_List(L, dim);
	
	cout << "Destroying the list...\n";
	destroy_List(L, dim);
	
	cout << "Printing the list...\n";
	write_List(L, dim);
	
	return 0;
}


So, the program starts correctly but when I have inserted the first "key" of the firt "entry" instead of letting me insert the "info" it skips it and makes me insert the second "key" of the second "entry". Did I do wrong the allocation? To me it seems okay.
P.S. Sorry for the wall of code but I need you to know everything I did so that you can help me in this. Thank you!
Last edited on
when you input you press <Return> and `getline()' would read precisely to a line break.
So line 19 cin.getline(buffer, 100); would put an empty string on `buffer'.

To avoid that you need to discard that line-break character
You may std::cin.ignore(); before the getline(), or you may do (cin>>ws).getline(buffer, 100); to discard any whitespace (careful, if your string starts with spaces those will be discarded)


You shouldn't use error prone methods like `create()' and `destroy()'. Instead use the constructor and destructor, that will be called automagically.
1
2
3
4
5
6
7
void swap(T &x, T &y) {
	T temp; //uninitialised
	
	copy_Entry(temp, x);
	copy_Entry(x, y);
	copy_Entry(y, temp);
}
Last edited on
Oh yeah! I totally forgot about that. Now it works. And I forgot to add read_Entry(E); before the function in_List(L, dim, E, pos);. Just noticed by running the program. Anyway, there is another problem. It crashes if I put the key numbers in different order.
In my first try I put 4 entries a put like "Key of the first entry is 1", "Key of the second entry is 2", etc. It went good until the part where it has to sort the List. In that point the program crashes. I don't get why, the for loop is okay in order to understand which one is bigger.

Another thing is this:
In the last part of my main
1
2
3
4
5
6
7
cout << "Destroying the list...\n";
	destroy_List(L, dim);
	
	cout << "Printing the list...\n";
	write_List(L, dim);
	
	return 0;

when it prints it on the screen, when there is the integer "key" it writes "0" but when there is "info" it writes random letters, like for example "èà&" and stuff like that. All this only for the first two entries, the others have the same "info" I wrote on the keyboard but all the "key" are put to "0". Why does it happens?

I don't get the last part you talked about.
You shouldn't use error prone methods like `create()' and `destroy()'. Instead use the constructor and destructor, that will be called automagically.

What do you mean by "error prone methods"? What are "constructor" and "destuctor"?
> It crashes if I put the key numbers in different order.
debugger, backtrace
¿did you fix the uninitialised variable in the `swap()' function?


> In the last part of my main
You've just destroyed the list, anything that you do with it will be invalid.


> What do you mean by "error prone methods"?
easy to make mistakes (like the one in `swap()')

> What are "constructor" and "destuctor"?
http://www.cplusplus.com/doc/tutorial/classes/
http://www.cplusplus.com/doc/tutorial/classes2/
did you fix the uninitialized variable in the `swap()' function?

Not yet because... how should I initialize it? Something like this?
T temp = 0;
But it's a struct, so I should initialize the two part of it, right?
So it should be like this:
temp.Key = 0;
temp.Info = new char[0];

Which is like the fuction create_Entry.

You've just destroyed the list, anything that you do with it will be invalid.

Exactly! But why when I print the vector again only the first two entries are invalid while the rest of them have all "info" the same as I previously wrote on keyboard?
Let's say I put 5 entries. It comes out like this:
Key: 1
Info: qwe
Key: 2
Info: wer
Key: 3
Info: ert
Key: 4
Info: rty
Key: 5
Info: tyu

After it destroys the list it comes out like this:
Key: 0
Info: (random characters)
Key: 0
Info: (random characters)
Key: 0
Info: ert
Key: 0
Info: rty
Key: 0
Info: tyu

As you can see, only the first two entries are actually destroyed. I don't get why.

easy to make mistakes (like the one in `swap()')

Oh, I got it. Unfortunately the professor started like that. She gave us some possible functions and the "swap()" was one of them so I used it.

http://www.cplusplus.com/doc/tutorial/classes/
http://www.cplusplus.com/doc/tutorial/classes2/

So you are telling me I should use classes?
> Which is like the fuction create_Entry.
Call `create_Entry()' then.
And don't forget to `destroy_Entry()' when you are done
(¿see how is it error-prone?)

> But why when I print the vector again only the first two entries are invalid
¿why do you think that `ert' is more valid than `áßðkxjc'?

> As you can see, only the first two entries are actually destroyed. I don't get why.
http://stackoverflow.com/a/6445794


> So you are telling me I should use classes?
No, I'm telling you to read those links to answer your questions about what are the constructor and destructor.
Calling the two function actually took out the problem about the key not in order and the first two info having random letters.

why do you think that `ert' is more valid than `áßðkxjc'?

It's because the first two info were random letters while the others were exactly the info I wrote, so I was kinda confused on why it was like that. It seemed like I've never written there and so it thought it was uninitialized and put random letters.

This helped me understand more: http://stackoverflow.com/a/6445794
Thank you!

No, I'm telling you to read those links to answer your questions about what are the constructor and destructor.

Yeah, sorry!

Anyway, using the constructors and destructors, will it be like this:
1
2
3
4
Entry::Entry(int x, char * c) {
	Key = x;
	Info = c;
}

and
1
2
3
~Entry () {
	delete Info;
}

Is it okay?
The constructor should be equivalent to `create_Entry()'
1
2
3
4
Entry::Entry() {
	this->Key = 0;
	this->Info = new char[0];
}
and the destructor to `destroy_Entry()'
1
2
3
4
Entry::~Entry (){
	delete [] this->Info;
	this->Key = 0; //not actually needed
}


Then
1
2
3
4
5
6
7
void swap(T &x, T &y) {
	T temp; //the constructor would take care of initialization
	
	copy_Entry(temp, x);
	copy_Entry(x, y);
	copy_Entry(y, temp);
} //the destructor would avoid leaks 
would work as is.
Sorry for the late replay...
Anyway, what does "this" do? There are pointers after them too. What does it mean?
Sorry for all these questions...
Topic archived. No new replies allowed.