Im trying to input data from a while into struct but the program is crashing. Can anyone take a look at this

This is stored in a record.txt file:
1
2
3
12 kamil 23 25 45 43
15 saad 56 61 34 76
23 kamilhassaan l231 435 567 12


This is what I wrote:
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
#include <iostream>
#include <fstream>
using namespace std;

struct info{
	double roll_num;
	char name[100];
	double quiz1 , quiz2 , mids , final;
};

int main()
{
	info data[3];
	int index = 0;
	
	ifstream fin("record.txt");
	
	while(!(fin.eof()))
	{
		fin >> data[index].roll_num;
		//cout << data[index].roll_num << endl;
		
		fin.getline(data[index].name , 20 , ' ');
		//cout << data[index].name << endl;
		
		fin >> data[index].roll_num;
		//cout << data[index].roll_num << endl;
		
		fin.getline(data[index].name , 50 , ' ');
		//cout << data[index].name << endl;
		
		fin >> data[index].quiz1;
		//cout << data[index].quiz1 << endl;
		
		fin >> data[index].quiz2;
		//cout << data[index].quiz2 << endl;
		
		fin >> data[index].mids;
		//cout << data[index].mids << endl;
		
		fin >> data[index].final;
		//cout << data[index].final << endl;
		index++;
	}

	for(int i=0; i<3; i++)
	{
		cout << data[i].roll_num << endl;
		cout << data[i].name << endl;
		cout << data[i].quiz1 << endl;
		cout << data[i].quiz2 << endl;
		cout << data[i].mids << endl;
		cout << data[i].final << endl;
		cout << endl;
	}
}

The problem is in line 23. How can I fix that?
This looks really bad. What if there are more lines than 3? Why don't you write it in more generic way?
Why don't you split it into separate functions?
This is stored in a record.txt file:
12 kamil 23 25 45 43
15 saad 56 61 34 76
23 kamilhassaan l231 435 567 12

There's a problem with the data. On the last line, l231 is not a valid number (it contains the alphabetic lower-case 'L').

There are numerous problems with the code.
Line 18. Don't loop on eof(). It doesn't work as you expect and as here, fails to properly handle the input.

Try while (fin) at line 18 instead.
Also the loop should terminate when index reaches the capacity of the array. You might add that test as part of the loop condition too.

Line 43, index++; there is no check whether the file has been read successfully or not, index is always incremented even if the read failed.

Try at line 43
1
2
if (fin)
    index++;



Line 46
 
for(int i=0; i<3; i++)
the loop will always repeat three times, regardless of the number of rows which were read from the file. Use index instead of 3 as the limit.
Last edited on
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
#include <iostream>
#include <fstream>
using namespace std;

struct info{
	double roll_num;
	char name[100];
	double quiz1 , quiz2 , mids , final;
};

int main()
{
	const int size = 3;
	info data[size];
	int index = 0;
	
	ifstream fin("record.txt");
	
	while(fin)
	{
		fin >> data[index].roll_num;
		//cout << data[index].roll_num << endl;
		
		fin.getline(data[index].name , 20 , ' ');
		//cout << data[index].name << endl;

		fin >> data[index].roll_num;
		//cout << data[index].roll_num << endl;
		
		fin.getline(data[index].name , 50 , ' ');
		//cout << data[index].name << endl;
		
		fin >> data[index].quiz1;
		//cout << data[index].quiz1 << endl;
		
		fin >> data[index].quiz2;
		//cout << data[index].quiz2 << endl;
		
		fin >> data[index].mids;
		//cout << data[index].mids << endl;
		
		fin >> data[index].final;
		//cout << data[index].final << endl;
		
		if(fin) index++;
	}
	
	for(int i=0; i<size; i++)
	{
		cout << data[i].roll_num << endl;
		cout << data[i].name << endl;
		cout << data[i].quiz1 << endl;
		cout << data[i].quiz2 << endl;
		cout << data[i].mids << endl;
		cout << data[i].final << endl;
		cout << endl;
	}
}

Is this what you're talking about? There are still problems though.

And I couldn't understand what kind of a check this is if(fin) index++;. Can you please explain this? I've never seen such a check before.

Also if cout at line 21 i get the proper answer. But I don't get the proper answer if i cout at line 25. There is still a problem at line 24.
Last edited on
And I couldn't understand what kind of a check this is if(fin) index++;.

This is the same kind of check as you now have at line 19.

ostream provides an overload for operator bool essentially a shorthand for if (stream.good())
http://www.cplusplus.com/reference/ios/ios/operator_bool/

The reason for the if at line 45 before the increment is that if any of the individual input operations failed, you don't want to increment the index resulting in a bad entry.

But I don't get the proper answer if i cout at line 24. There is still a problem at line 23.

Use a std::string for name instead of a C char array.

Lines 20,26: Why are you inputting rull_num twice?

Lines 24,30: Why are you inputting name twice?

You have only five data fields in your data file, but you're trying to read 8 data fields. You have only 6 data items declared in your struct. Some of your input operations are going to fail.
Last edited on
Actually I didn't understand what you were trying to do with the input statements, where both the roll_num and name are read from the file twice, first at line at line 21, then again at line 27.

I re-wrote that part of the code to just use fin >> for each of the six items, and didn't bother with getline() at all. If you do want to use getline with space as a delimiter, remember that there is a space after the roll_num, which will be considered the end of the string. That means the contents of name will be an empty string. To fix that, you need to skip the leading whitespace.

Either do this (no getline)
1
2
        fin >> data[index].roll_num;       
        fin >> data[index].name;
or this:
1
2
        fin >> data[index].roll_num >> ws;       
        fin.getline(data[index].name, 20, ' '); 

Also, if you wanted to specify the length in the first case, you could do
 
        fin >> setw(20) >> data[index].name;


And I couldn't understand what kind of a check this is if(fin) index++;. Can you please explain this? I've never seen such a check before.


Most newcomers are aware of the end-of-file flag. In fact there are four flags associated with the file stream, good, bad, fail and eof. In general use, the most useful of these is fail. You could test it like this:
 
    if (fin.fail())

See http://www.cplusplus.com/reference/ios/ios/fail/

Because it is so commonly used, there is a convenient shorter syntax, if (fin) or the opposite condition, if (!fin), thus it is a convenient way to check that all is ok, nothing has failed.

if (fin) gives the same result as if (!fin.fail()).
See http://www.cplusplus.com/reference/ios/ios/operator_bool/

Hope that helps.

By the way, line 48 for(int i=0; i<size; i++) is still looping a fixed number of times, rather than the actual number of items which were read from the file. You should use index rather than size here.
Lines 20,26: Why are you inputting rull_num twice?

Lines 24,30: Why are you inputting name twice?

Wow! I didn't see that.

Use a std::string for name instead of a C char array. My teacher hasn't taught string yet and i am not supposed use it.

You have only five data fields in your data file There are 6 fields in the data file not 5.

So I fixed the errors you've stated above but still I'm not getting a proper output
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
#include <iostream>
#include <fstream>
using namespace std;

struct info{
	double roll_num;
	char name[20];
	double quiz1 , quiz2 , mids , final;
};

int main()
{
	const int size = 3;
	info data[size];
	int index = 0;
	
	ifstream fin("record.txt");
	
	while(fin)
	{
		fin >> data[index].roll_num;
		//cout << data[index].roll_num << endl;
			
		fin.getline(data[index].name , 20 , ' ');
		//cout << data[index].name << endl;

		fin >> data[index].quiz1;
		//cout << data[index].quiz1 << endl;
		
		fin >> data[index].quiz2;
		//cout << data[index].quiz2 << endl;
		
		fin >> data[index].mids;
		//cout << data[index].mids << endl;
		
		fin >> data[index].final;
		//cout << data[index].final << endl;
		
		if(fin) index++;
	}
	
	for(int i=0; i<index; i++)
	{
		cout << data[i].roll_num << endl;
		cout << data[i].name << endl;
		cout << data[i].quiz1 << endl;
		cout << data[i].quiz2 << endl;
		cout << data[i].mids << endl;
		cout << data[i].final << endl;
		cout << endl;
	}
}


And is this fin.getline(data[index].name , 20 , ' '); a proper syntax?
Last edited on

So I fixed the errors you've stated above but still I'm not getting a proper output

I guess you didn't notice where I explained this:
chervil wrote:
If you do want to use getline with space as a delimiter, remember that there is a space after the roll_num, which will be considered the end of the string. That means the contents of name will be an empty string. To fix that, you need to skip the leading whitespace.

Sorry Chervil, I didn't notice that part and thank you for your help. It's working now.
So i tried to extend my practice;
1,	kamil hassaan	, 2, 3, 4, 5
2,	saad haider	, 3, 4, 5, 6

I added a tab before and after the names and also a space between the names. You can see that above.

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
#include <iostream>
#include <fstream>
using namespace std;

struct info{
	double roll_num;
	char name[30];
	double quiz1 , quiz2 , mids , final;
};

int main()
{
	ifstream fin("test.txt");
	
	info data[2];
	int null = 0;
	for(int i = 0; i < 2; i++)
	{
		data[i].name[30] = '\0';
	}
	int index = 0;
	char trash = '\0';
	
	while(fin)
	{
		fin >> data[index].roll_num;
		do
		{
			fin >> trash;
		}
		while(trash == ',' || trash == '	' || trash == ' ');
		//cout << data[index].roll_num << " ";
		fin.getline(data[index].name , 30 , ',');
		
		int rev = 29;
		while(data[index].name[rev] == 9 || data[index].name[rev] == 32 || data[index].name[rev] == ',')
		{
			data[index].name[rev] = '\0';
			rev--;
		}
		//cout << data[index].name;
		
		fin >> data[index].quiz1;
		fin >> trash;
		//cout << data[index].quiz1 << " ";
		
		fin >> data[index].quiz2;
		fin >> trash;
		//cout << data[index].quiz2 << " ";
		
		fin >> data[index].mids;
		fin >> trash;
		//cout << data[index].mids << " ";
		
		fin >> data[index].final;
		//cout << data[index].final << endl;
		//break;		
		if(fin) index++;
	}
	cout << index;
	for(int i=0; i<index; i++)
	{
		cout << data[i].roll_num << " ";
		cout << data[i].name;
		cout << data[i].quiz1 << " ";
		cout << data[i].quiz2 << " ";
		cout << data[i].mids << " ";
		cout << data[i].final << " ";
		cout << endl;
	}
}


If I cout inside the while loop the first alphabets of the names are deleted. But there is no output outside of the while loop. I'm not getting a anything outside of the while loop.
Topic archived. No new replies allowed.