Don't spaces count as symbols?

I got this exercise and i'am trying to read all the data from file, but it fails and throws junk values.

This is the data I'am trying to read:
7
Petras A. Petraitis 120 15 20 0
Jurgis Jurgutis 222 16 12 22
Rimas Jonas 138 15 15 59
Bei Lin Sin Mun 23 15 0 0
Zigmas Nosis 256 16 23 9
Romas Senasis 111 15 15 15
Jurgis Statys Lydeka199 16 13 9

First line is the amount of athletes starting 1 <= n <= 30.
in the next n amount of lines are the data about athletes.
First 20 positions are athletes names. Then his identification number. And then his starting time: Hours, minutes and seconds.

And this is the code 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
//Uzduotis: Slidininkai
#include <fstream>
#include <iostream>

using namespace std;

struct slidininkai{
    char name[20]; // athlete names
    int startNumb; // athletes identification numbers
    int timeHours; // starting time: hours
    int timeMin; // starting time: minutes
    int timeSec;// starting time: seconds
};

int main()
{
    slidininkai athletes[30];
    fstream duom ("U2.txt");
    int n; // starting athletes
    duom >> n;
    for (int i=0; i<n; i++){
        for (int j=0; j<20; j++){
            duom >> athletes[i].name[j];
        }
        duom >> athletes[i].startNumb;
        duom >> athletes[i].timeHours;
        duom >> athletes[i].timeMin;
        duom >> athletes[i].timeSec;
    }




    //cout << n << endl;
    for (int i=0; i<n; i++){
        for (int j=0; j<20; j++){
            cout << athletes[i].name[j];
        }
        cout << " " << endl;
        cout << athletes[i].startNumb << " ";
        cout << athletes[i].timeHours << " ";
        cout << athletes[i].timeMin << " ";
        cout <<athletes[i].timeSec << endl;
    }
    return 0;
}

What wrong am I doing again?
What wrong am I doing again?

Several things.

Probably the worst is that your C-string only has room for 19 characters and at least one of the strings has 20 characters. (Wait a minute, you're not dealing with C-strings but just an array of char. Be careful here, remember never to use any of the C-string functions on these arrays of char).

Also when trying to retrieve your strings you always try to retrieve 20 characters, even if the string has more or less characters.

If you have control of your file you should consider using something to delimit the end of each element of your array. For example using a comma to delimit the fields.

1
2
3
7
Petras A. Petraitis,120,15,20,0
Jurgis Jurgutis,222,16,12,22


Then to retrieve your string (By the way why aren't you using C++ std::string?) use getline() with setting the optional delimiter to a comma. Then read your number/comma one at time.

Last edited on
First 20 positions are athletes names.
In that case 'Rimas Jonas 138 15 1' (without quotes) would be the name of the 3rd entry.
Unless there are multiple spaces that have been "removed" because the OP didn't place the file contents within code tags to preserve the formatting.

std cin looks at the data like this:

7 Petras A. Petraitis 120 15 20 0 Jurgis Jurgutis 222 16 12 22 Rimas Jonas 138 15 15 59 Bei Lin Sin Mun 23 15 0 0 Zigmas Nosis 256 16 23 9 Romas Senasis 111 15 15 15 Jurgis Statys Lydeka199 16 13 9


new lines and spaces are transparent from each other.

The reason why you get garbage is because for every >> you move the cursor, it doesn't read spaces (its not hard to make a test to find out), and you don't error check if( stream >> i)/*or*/ if( stream).

You can just check if the first letter of the string is a number, and just start reading the 4 numbers from there. But you need to callstd::cin.unget(); for every letter in the string to read it again as a int (or use .get() before choosing string or int).
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 <iomanip>
#include <sstream>
#include <fstream>
#include <string>
using namespace std;

struct slidininkai
{
   string name;             // athlete name
   int startNumb;           // athletes identification numbers
   int timeHours;           // starting time: hours
   int timeMin;             // starting time: minutes
   int timeSec;             // starting time: seconds
};


istream &operator >> ( istream &in, slidininkai &s )
{
   string line;
   getline( in, line );
   s.name = line.substr( 0, 20 );
   stringstream( line.substr( 20 ) ) >> s.startNumb >> s.timeHours >> s.timeMin >> s.timeSec;
   return in;
}


ostream &operator << ( ostream &out, const slidininkai &s )
{
   return out << setw( 20 ) << s.name      << ' '
              << setw( 4  ) << s.startNumb << ' '
              << setfill( '0' ) 
              << setw( 2  ) << s.timeHours << ':' 
              << setw( 2  ) << s.timeMin   << ':'
              << setw( 2  ) << s.timeSec   << setfill( ' ' );
}


int main()
{
   slidininkai athletes[30];
// fstream duom( "U2.txt" );
   stringstream duom( "7                               \n"
                      "Petras A. Petraitis 120 15 20 0 \n"
                      "Jurgis Jurgutis     222 16 12 22\n"
                      "Rimas Jonas         138 15 15 59\n"
                      "Bei Lin Sin Mun      23 15 0  0 \n"
                      "Zigmas Nosis        256 16 23 9 \n"
                      "Romas Senasis       111 15 15 15\n"
                      "Jurgis Statys Lydeka199 16 13 9 \n" );

   int n;
   duom >> n >> ws;
   for ( int i = 0; i < n; i++ ) duom >> athletes[i];

   cout << n << '\n';
   for ( int i = 0; i < n; i++ ) cout << athletes[i] << '\n';
}


7
Petras A. Petraitis   120 15:20:00
Jurgis Jurgutis       222 16:12:22
Rimas Jonas           138 15:15:59
Bei Lin Sin Mun        23 15:00:00
Zigmas Nosis          256 16:23:09
Romas Senasis         111 15:15:15
Jurgis Statys Lydeka  199 16:13:09
jlb is right. I'am an idiot and the data file was posted wrong. In the line where there is a name if the name isn't 20 symbols there is just a ton of spaces

And no, I have 0 control of the data file. The way its written is no choice thing.
Last edited on
Okay then you can use getline() to retrieve your C-string but since there can be 20 characters in the string you need a size of at least 21 for the C-string.

1
2
3
4
5
6
7
8
9
10
    int n; // starting athletes
    duom >> n;  // Make sure you validate this to insure n is less than the siz of your array.
    for (int i=0; i<n; i++){
        duom >> ws;
    getline(atheletes[i].name, 20); // Get the C-string.
        duom >> athletes[i].startNumb;
        duom >> athletes[i].timeHours;
        duom >> athletes[i].timeMin;
        duom >> athletes[i].timeSec;
    }


Thanks, now if I wanted these names to be sorted alphabetically, how would I do it?
Are you allowed to use things like std::sort or do you need to do it the hard way?

Nothing really forbids me from using sort, except that I wasn't taught anything like that.
Well then either look up the documentation for std::sort or look up information on basic sorts that you can implement yourself. If you get stuck (after finding and reading some documentation), show what you've tried and ask more specific questions.

Note: You may want to start a little simpler if this is the first time you've tried sorting. Start with just a vector/array of names and try to sort that. Once you figure out how to do basic sorting sorting your structure will be much easier.

Here's my take on it.
- I didn't use << and >> operators in case you haven't studied them yet.
- Use istream::ignore() to skip the newlines
- trim trailing spaces on the name

In a real-world program, I'd store the name with an std::string and I'd store the starting time as total elapsed seconds (hours*3600 + minutes*60 + seconds). It's usually a good idea to store your data in a form that's convenient to the computer, which might be different from the form that's used in the file.
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
//Uzduotis: Slidininkai
#include <fstream>
#include <iostream>
#include <algorithm>
using namespace std;

struct slidininkai{
    char name[21]; // athlete names, plus room for null terminator
    int startNumb; // athletes identification numbers
    int timeHours; // starting time: hours
    int timeMin; // starting time: minutes
    int timeSec;// starting time: seconds
};

int main()
{
    slidininkai athletes[30];
    fstream duom ("U2.txt");
    int n; // starting athletes
    duom >> n;
    duom.ignore(numeric_limits<streamsize>::max(), '\n');

    for (int i=0; i<n; i++){
	duom.read(athletes[i].name, 20);

	// Find the last non-space... 
	int j;
	for (j=19; j >= 0; --j) {
	    if (!isspace(athletes[i].name[j])) break;
	}
	// ...and null-terminate after it
	athletes[i].name[j+1] = 0;

        duom >> athletes[i].startNumb;
        duom >> athletes[i].timeHours;
        duom >> athletes[i].timeMin;
        duom >> athletes[i].timeSec;
	duom.ignore(numeric_limits<streamsize>::max(), '\n');
    }

    for (int i=0; i<n; i++){
	cout.width(20);
	cout << left << athletes[i].name;
        cout << athletes[i].startNumb << " ";
        cout << athletes[i].timeHours << " ";
        cout << athletes[i].timeMin << " ";
        cout <<athletes[i].timeSec << endl;
    }
    return 0;
}

jlb okay
dhayden actually this is just a the start of the program, there is alot more to be done. But I couldn't get it to correctly read the data
Sorting the names as you have them stored now will sort on the first character. I doubt that is what you want. Usually names are sorted by last name, last name, middle name in that order

It looks like the name format is something like first name <space> (optional) middle name(s)/initial <space> last name.

You are going to have to create a custom sort predicator to parse out the parts of the full name and sort by that.
Actually exercise is asking me to sort them by the first character
But I couldn't get it to correctly read the data
Garbage in / garbage out! It's always best to verify the I/O part first.

You might want to create functions to read and write one record. That will make the code neater.
Topic archived. No new replies allowed.