Learning Structures, stuck reading in

Pages: 12
Hello again, I am working on my first struct program and I am stuck. I always have issues with reading in. It reads the first and second string then the first ID but doesn't progress to the next name. I have the "goals" commented out as it isn't functioning correctly yet.

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
#include <iostream>
#include <iomanip>
#include <fstream>

using namespace std;

ofstream out("Soccer.out");

const int PLAYERS=12;  //Number of players on the roster
const int MATCHES=7;   //Number of games played

struct Info
{
    string Fname; //Player's Name
    string Lname;
    int ID; //Player's ID
    int goals[MATCHES];//Player's scores
    int total; //total goals scored
};

//Function Prototypes
void Read(Info[]);
void Print();
void Sorted(Info[]);
void TotalGoals(Info[]);
void PlayerGoals(Info[]);
void MostGoals(Info,string&,string&);
void Header();

void Read(Info team[])
{
    ifstream inf("Soccer.in");
    if(!inf)
        cout << "error opening Soccer.in";

    for(int i=0; i<PLAYERS; i++)
    {
        inf >> team[i].Fname >> team[i].Lname
            >> team[i].ID;
        for(int j=0; j<MATCHES; j++)
        {
            inf >> team[i].goals[j];
        }
    }
}
void Header()
{
     out<<setw(10)<<"Name"<<setw(25)<<" Player ID"
        <<setw(35)<<" Total Goals Scored"<<endl
        <<"-------------------------------------"
        <<"------------------------------------\n";
}
void Print(Info team[])
{
    for(int i=0; i<PLAYERS; i++)
    {
        out << setw(10) << team[i].Fname << " "
            << team[i].Lname << " "
            << setw(16) << team[i].ID << " "
           // << setw(28) << team[i].goals[MATCHES]
            << endl;
    }
}
void Sorted(Info team[])
{
    //Unsure how to write a sort for struct.
    //Do I include each element of the struct in the sort?
}
void PlayerGoals(Info team[])
{
    int sum=0;
    for(int i=0;i<PLAYERS;i++)
        for(int j=0;j<MATCHES;j++)
            sum+=team[i].goals[j];
     out << sum;
}

void TotalGoals(Info team[])
{
    int sum=0;
    for(int i=0; i<PLAYERS; i++)
        sum+=team[i].total;
    out << sum;
}

void MostGoals(Info team[], string &MostFName, string &MostLName)
{
    int most = team[0].total;
    for(int i=0; i<PLAYERS; i++)
        if(team[i].total > most)
        {
            most=team[i].total;
            MostFName=team[i].Fname;
            MostLName=team[i].Lname;
        }
    out << most;
}
int main()
{
    string Fname, Lname;
    Info team[PLAYERS];
    Read(team);
    Header();
    Print(team);
    out<< "\nTotal Goals:";//test
    TotalGoals(team);
    out<<"\nMost Goals:";//test
    MostGoals(team,Fname,Lname);
    out<<"\nPlayer Goals:";//test
    PlayerGoals(team);
    cout << "So Far SO GOOD!" << endl;
    return 0;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
OUTPUT:
 Golden Tow             3821 
                     7208100 
                     8806122 
                     8192192 
                           0 
                     7208908 
                   899226470 
                     4406800 
                  1996112083 
                     7208352 
                     7208584 
                     8199440 

Total Goals:-278392796
Most Goals:1995992803
Player Goals:-1111091977
Last edited on
Please post the input file (Soccer.in).
Please show the input file or the first 3 records of it.
the code looks pretty solid ... I don't see anything obvious.

an alternate technique would be to read the file later and hard code the input data to get the rest of the code working and circle back to it -- this idea can let you make progress while waiting on some help if you are stuck and no one is responding.
Last edited on
Apologies. I forgot.

INPUT:
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
Golden Tow
3821
3 5 2 2 4 2
Big Phoot
8224
4 3 5 3 2 1 2
T Threader
7282
3 2 1 4 3 2 2
Lite Foot
7322
4 3 2 1
Twinkle Toes
3824
4 1 1 1 1
Ball Masher
7291
3 4 2 1 4 3
Hop Along
1313
1 3 1 1 2 2 2
Turn Anrun
9211
3 1 1 3
Stopper Topper
8421
3 1 4 3 5 1
Thomas Beesbie
2313
3 2 1 1
Slick Slider
6342
1 1 1 1
Goldie Oldie
5345
3 2 4 2 3 2

ASSIGNMENT:

Write a program to store the information for each player that plays on a soccer team. 12 people on the team. The info you are to collect is the player’s name, id number and the number of points that the player earned in each game. Each player has three lines of input.

The input file format is: Example:
Player’s Name Golden Tow
Player’s ID 12345
a list of points for the season 1 1 3 3 1 // a variable number of input values

Input file is ‘Soccer.txt’

Output: The player’s name, id number and total points scored in sorted order by ‘Name’.
The total points scored by the team.
The person and his score who scored the highest.
Print out in table format with headings and straight columns.

Restrictions: Must use an array of ‘structure’ and only use pointers for the array of structure. No [ ]’s in your code other than the declaration for the initial array.


I know this program must use pointers over arrays, but I am figuring the program out using array's then I will convert to pointers.
Last edited on
42) inf >> team[i].goals[j];
43) cout << team[i].goals[j]; //add this line.
44) }
45 exit(0); //add this too.

you should see
3
5
2
2
4
2
for those and then it should stop running (the exit killed the program to study the partial run).

is that part working?
Last edited on
I wasn't able to place the exit(0); it gave an error:"exit not declared"
WHen I put in the cout, it gave me a lot of garbage.

EDIT: IT does spit out 3 5 2 2 4, but then it turns to garbage.
1
2
3
4
5
6
7
8
3 5 2 2 4 2 0 1998046768 1 239272 2047 1998049663 -172089040 196608 0 
7208200 2344 238752 -2 62 -2344 229544 0 257 8733424 1 8716288 3 1 2 
16777484 238744 212 65 7208052 1998299008 -2097707676 -2 7208248 
1998041135 512 520 520 4957682 769 0 0 7208168 48 183 1998040558 0 0 512 
183 7208312 -788717928 5009444 4221048 7208380 4199040 5644 200288 24 
204016 204040 -111597392 7208520 1995927938 196608 1995927938 196608 0 
204016 -788718124 28 204016 7208604 1996058613 1996374812 7208668 
1996055889 8 1995992829
Last edited on
sorry about that. exit is in <cstdlib> which you don't include and wouldn't know to.

Im home now. Ill see what the malfunction is and get back as soon as I can.
your input file is broken. count the # of scores for the first record.
your code says read 7 no matter what. your file has not 7 on many of the inputs. this causes the data to get scrambled.

what I would do is take the top 3 or 4 records into a copy of the file, give them all 7 scores exactly, and test your code on that. Once it works, go back to deal with a variable # of scores.
Last edited on
Part of the input file specification is:
a list of points for the season 1 1 3 3 1 // a variable number of input values

Your code assumes that each player has exactly 7 scores
So within struct Info, you'll need to store the number of entries in the player's goal array.

You can read the scores like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <string>
#include <sstream>
...
    for(int i=0; i<PLAYERS; i++)
    {
        inf >> team[i].Fname >> team[i].Lname
            >> team[i].ID;
        getline(inf, line);
        istringstream istrm(line);
        int j;
        for(j=0; j<MATCHES; j++)
        {
            istrm >> team[i].goals[j];
        }
        team[i].numGoals = j;
    }

You will need to adjust PlayerGoals() to only count the number of entries in the goals array.
Can I change the number of matches to unknown and let it read to each new line?
@dhayden, what does your line 9 do?
In C++, there are multiple types of "streams".

For example, you do
inf >> team[i].Fname; to fill in the name from the file.
But this is the same syntax you could use for reading in from the standard input stream, cin.
e.g. cin >> team[i].Fname;

stringstreams are similar. When you make a stringstream (line 9), you are filling it with the information contained in (line), and then you're able to treat that text as a stream, as if it were a file stream or cin.

It makes parsing strings easier by converting them back into streams.
Last edited on
Thank you for the explanation. I'm not sure if I could use that in my program or not.

what am I doing wrong using getline?? I keep getting an error and I'm not use to using getline. getline(inf,team[i].goals,'\n');//I am putting this between lines 39 and 40.

I'm thinking with my code as dhayden and jonnin have already said, the reading of the file is causing the issue. I believe I need to use getline in the read function for it read the goals one by one and once a endline is encountered to read the next name. Currently the program doesn't print a second name.

Last edited on
Ugh. Sorry, not enough coffee. This code seems to read a player correctly. Notice the temporary code to print some player data to cout to make sure it's working right. I strongly urge you to always print out the data after you read it to make sure you're reading it correctly. You can delete the printing code once you're sure it works. Otherwise you'll find yourself spending hours trying to figure out why your data isn't printing correctly when all along it's printing fine, but the data itself is junk.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
        inf >> team[i].Fname >> team[i].Lname
            >> team[i].ID;
        getline(inf, line);     // skip the end of line...
        getline(inf, line);     // .. and read the line of scores
        istringstream istrm(line);
        team[i].numGoals=0;
        team[i].total = 0;
        int num;
        while (istrm >> num) {
            team[i].goals[team[i].numGoals] = num;
            team[i].total += num;
            ++team[i].numGoals;
        }
        cout << team[i].Fname << ' ' << team[i].Lname
             << " scored in " << team[i].numGoals << " games.\n";

Also, look at all those team[i] expressions in that code? It would be cleaner to create a read() method and call it:
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
struct Info
{
    string Fname; //Player's Name
    string Lname;
    int ID; //Player's ID
    int numGoals;
    int goals[MATCHES];//Player's scores
    int total; //total goals scored
    bool read(istream &strm);
};
...
void Read(Info team[])
{
    ifstream inf("Soccer.in");
    if(!inf)
        cout << "error opening Soccer.in";

    for(int i=0; team[i].read(inf); i++)
        ;
}

// Read the Info record from the stream
bool Info::read(istream &strm)
{
    string line;
    strm >> Fname >> Lname >> ID;
    getline(strm, line);        // skip the end of line...
    getline(strm, line);        // .. and read the line of scores
    istringstream istrm(line);
    numGoals=0;
    total = 0;
    while (istrm >> goals[numGoals]) {
        total += goals[numGoals];
        ++numGoals;
    }
    cout << Fname << ' ' << Lname
         << " scored in " << numGoals << " games.\n";
    return strm.good();
}


See how much easier it is to read and understand these two methods instead of the one giant Read() method?
I see what you're doing, but I don't think the prof will allow me to turn in a code with a "bool" or anything we haven't covered. Such as the istringstream.

Question, why is the variable "line" a string? Wouldn't it just read the numbers?
I tried to use what you had placed in the first reply. The istringstream is giving me an error. "variable 'std::istringstream istrm' has initializer but incomplete type" error" incomplete types in assignment of 'int' to 'int[2]'"
#include <sstream>

If you don't want to use stringstreams, you can try to re-implement the logic yourself. It's just very tedious.
Your string will contain e.g. "42 7 123 1" and you have to make it so those numbers are converted into ints and put into your goals array. You can manually do this by parsing one character at a time.

variable "line" a string
getline always uses a string as its output. With the operator>>, you can use ints, but the issue is that you don't know how many ints are on the line, which is why the parsing is split up into first reading in the whole line, and then splitting the line into separate ints.
Last edited on
I've finished most of the program. The only issue at the moment that I've found is the "MostGoals" Function is producing the wrong player.
FULL CODE
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
#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>

using namespace std;

ofstream out("Soccer.out");

const int PLAYERS=12;  //Number of players on the roster

struct Info
{
   string name;
   int ID;
   int goals;
};

//Function Prototypes
void Read(Info*, Info *);
void Print(Info*, Info*);
void Sorted(Info*, Info*);
void TotalTeamGoals(Info*, Info*);
Info MostGoals(Info*, Info*);
void Header();

void Read(Info *ptr, Info *spa)
{
    ifstream inf("Soccer.in");
    if(!inf)
    {
        cout << "error opening Soccer.in";
    }
    int n;
    //initializes goals in Soccer struct array
    for (ptr=spa; ptr < (spa+PLAYERS); ptr++)
    {
        (*ptr).goals = 0;
    }
    //reads through file and loads it into array
    for (ptr=spa; ptr < (spa+PLAYERS); ptr++)
    {
        n = 0;
        getline(inf, (*ptr).name);
        inf >> (*ptr).ID;
        inf.ignore(1);
        while (inf.peek() != '\n' && inf.peek() != EOF)
        {
            inf >> n;
            (*ptr).goals += n;
        }
    inf.ignore(1);
    }
    inf.close();
}

void Header()
{
     out<<setw(40)<< "Soccer Statistics\n"
        <<setw(10)<<"Name"
        <<setw(25)<<" Player ID"
        <<setw(35)<<" Total Goals goalsd"<<endl
        <<"-------------------------------------"
        <<"------------------------------------\n";
}

void Print(Info *ptr, Info *spa)
{
    for(ptr=spa; ptr < (spa+PLAYERS); ptr++)
    {
        out << left << setw(14) << (*ptr).name << " "
            << right<< setw(16) << (*ptr).ID << " "
            << right << setw(28) << (*ptr).goals
            << endl;
    }
    out <<"-------------------------------------"
        <<"------------------------------------\n";
}
void Sorted(Info *ptr, Info *spa)
{
    Info temp;
    for (int i = 0; i < PLAYERS; i++)
    {
        ptr=spa;
        for (ptr = spa; ptr < (spa+(PLAYERS - 1)); ptr++)
        {
            if ((*ptr).name > (*(ptr + 1)).name)
            {
                temp = (*(ptr + 1));
                (*(ptr + 1)) = *ptr;
                *ptr = temp;
            }
        }
    }
}

void TotalTeamGoals(Info *ptr, Info *spa)
{
    int sum=0;
    for(ptr=spa; ptr < (spa+PLAYERS); ptr++)
    {
        sum+=(*ptr).goals;
    }
    out << "Total Team Goals: "<< setw(43) << sum << endl;
    out <<"-------------------------------------"
        <<"------------------------------------\n\n";
}

Info MostGoals(Info *ptr, Info *spa)
{
    int most = (*spa).goals; //highest goals
    int MostID = 0; //id of highest scoring player
    string MVP; //name of strongest player
    for (ptr = spa; ptr < (spa+(PLAYERS-1)); ptr++)
    {
        if ((*ptr).goals > (*(ptr + 1)).goals)
        {
            most = (*ptr).goals;
            MostID = (*ptr).ID;
            MVP = (*ptr).name;
        }
    }
    out << left << setw(20) << "MVP" << "ID#"
        << right << setw(19) << "goals" << endl
        <<"---------------------------------------------\n"
        << left << setw(20) << MVP
        << MostID << right << setw(16) << most << endl;
}

int main()
{
    Info *ptr = new Info[PLAYERS];
    Info *spa = ptr;

    Read(ptr,spa);
    Header();
    Sorted(ptr,spa);
    Print(ptr, spa);
    TotalTeamGoals(ptr,spa);
    MostGoals(ptr,spa);
    return 0;
}

OUTPUT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
                      Soccer Statistics
      Name                Player ID                 Total Goals 
Ball Masher                7291                           17
Big Phoot                  8224                           20
Golden Tow                 3821                           18
Goldie Oldie               5345                           16
Hop Along                  1313                           12
Lite Foot                  7322                           10
Slick Slider               6342                            4
Stopper Topper             8421                           17
T Threader                 7282                           17
Thomas Beesbie             2313                            7
Turn Anrun                 9211                            8
Twinkle Toes               3824                            8
-------------------------------------------------------------------------
Total Team Goals:                                         154
-------------------------------------------------------------------------

MVP                 ID#              goals
---------------------------------------------
T Threader          7282              17

AS you can tell Big Phoot needs to be the "MVP"
Last edited on
I'm unsure to why the function isn't seeing the list of numbers. I used cout on line115 and it prints all the total goals for each player. Somewhere in the if it's not selecting the correct person.
Pages: 12