Opened csv and added functions, but unsure how to incorporate them into the code

Pages: 123
Just because it compiles with one compiler doesn't always mean that it is correct. The g++ compiler also finds fault with line 66, this part in particular:

for (auto delimPosition = s.find(delim), tokenStart = 0U;
The auto is deducing the type as an unsigned long (size_t/std::string::size_type), but the second assignment is trying to assign an unsigned int to tokenStart.

This is one of the hazards of trying to cram so much code into a single line/statement. Another hazard is it also makes reading the code much harder.

Mines 2017 too, but i tried using ur code with 3 headers total and got all the errors,

Without seeing your code and the resultant error messages there is no way we can see what you did wrong. But I will say that the code being supplied to you is probably too far advanced for your current skill level. You really should be writing your own code not just taking code that you don't understand and trying to force it to work.



The g++ compiler also finds fault with line 66, this part in particular:

for (auto delimPosition = s.find(delim), tokenStart = 0U;
The auto is deducing the type as an unsigned long (size_t/std::string::size_type), but the second assignment is trying to assign an unsigned int to tokenStart.


Agreed. The auto type deduction from .find() depends upon 32/64 bit compile. Changed in previous post.
Oh okay, it does work now btw, so i'm gonna try and implement it into the 3 headers and get it running, i can only get it working under one main.


Agreed. The auto type deduction from .find() depends upon 32/64 bit compile. Changed in previous post
implement it into the 3 headers


goalies.h
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
#pragma once

#include <string>

class Goalies
{
public:
	// constructors
	Goalies();
	Goalies(const std::string& n, const std::string& t);
	Goalies(const std::string& n, const std::string& t, int w, int l, int ga, int sa);

	// implement setters
	void setName(const std::string& n);
	void setTeam(const std::string& t);
	void setWins(int w);
	void setLosses(int l);
	void setGoalsAllowed(int ga);
	void setShotsAgainst(int sa);

	// implement getters
	std::string getName() const;
	std::string getTeam() const;
	int getWins() const;
	int getLosses() const;
	int getGoalsAllowed() const;
	int getShotsAgainst() const;
	//double getSavePct() const;

private:
	//attributes
	std::string name;
	std::string team;
	int wins {};
	int losses {};
	int goalsAllowed {};
	int shotsAgainst {};
};


goalies.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#pragma once

#include <string>
#include "goalies.h"

Goalies::Goalies() {}
Goalies::Goalies(const std::string& n, const std::string& t) : name(n), team(t) {}
Goalies::Goalies(const std::string& n, const std::string& t, int w, int l, int ga, int sa) : name(n), team(t), wins(w), losses(l), goalsAllowed(ga), shotsAgainst(sa) {}

void Goalies::setName(const std::string& n) { name = n; }
void Goalies::setTeam(const std::string& t) { team = t; }
void Goalies::setWins(int w) { wins = w; }
void Goalies::setLosses(int l) { losses = l; }
void Goalies::setGoalsAllowed(int ga) { goalsAllowed = ga; }
void Goalies::setShotsAgainst(int sa) { shotsAgainst = sa; }

std::string Goalies::getName() const { return name; }
std::string Goalies::getTeam() const { return team; }
int Goalies::getWins() const { return wins; }
int Goalies::getLosses() const { return losses; }
int Goalies::getGoalsAllowed() const { return goalsAllowed; }
int Goalies::getShotsAgainst() const { return shotsAgainst; }


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

#include "goalies.h"
#include "goalies.cpp"

void split(const std::string& s, std::string elems[], size_t& noElems, char delim = ',')
{
	const size_t max_elems {noElems};
	noElems = 0;
	const auto pb {[&](size_t st, size_t dp) {elems[noElems++] = s.substr(st, dp - st); }};

	size_t tokenStart {};

	for (auto delimPosition = s.find(delim); noElems < max_elems && delimPosition != std::string::npos; )
		if (pb(tokenStart, delimPosition); (delimPosition = s.find(delim, (tokenStart = ++delimPosition))) == std::string::npos)
			pb(tokenStart, delimPosition);
}

std::istream& operator>>(std::istream& is, Goalies& g)
{
	if (std::string line; getline(is, line)) {
		constexpr size_t No_Elems {6};
		size_t gotElems {No_Elems};
		std::string tokens[No_Elems] {};

		if (split(line, tokens, gotElems); gotElems == No_Elems) {
			g.setName(tokens[0]);
			g.setTeam(tokens[1]);
			g.setWins(atoi(tokens[2].c_str()));
			g.setLosses(atoi(tokens[3].c_str()));
			g.setGoalsAllowed(atoi(tokens[4].c_str()));
			g.setShotsAgainst(atoi(tokens[5].c_str()));
		}
	}

	return is;
}

std::ostream& operator<<(std::ostream& os, const Goalies& g)
{
	return os << std::left << std::setw(25) << g.getName() << std::setw(15) << g.getTeam() << std::right << std::setw(4) << g.getWins() << std::setw(10) << g.getLosses() << std::setw(15) << g.getGoalsAllowed() << std::setw(15) << g.getShotsAgainst();
}

void showNames(const Goalies goalies[], size_t no_goalies)
{
	std::cout << std::left << std::setw(25) << "Name" << std::setw(15) << "Team" << std::setw(8) << "Wins" << std::setw(8) << "Losses" << std::setw(15) << "Goals Allowed" << std::setw(8) << "Shots Against\n";

	for (size_t g = 0; g < no_goalies; ++g)
		std::cout << goalies[g] << '\n';
}

void sortWins(Goalies goalies[], size_t no_goalies)
{
	std::sort(goalies, goalies + no_goalies, [](auto a, auto b) {return a.getWins() < b.getWins(); });
}

void sortLosses(Goalies goalies[], size_t no_goalies)
{
	std::sort(goalies, goalies + no_goalies, [](auto a, auto b) {return a.getLosses() < b.getLosses(); });
}

int getInt(const std::string& prm)
{
	int i {};

	while ((std::cout << prm) && !(std::cin >> i)) {
		std::cout << "Invalid number\n";
		if (prm.empty()) std::cout << "Please re-enter: ";
		std::cin.clear();
		std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
	}

	return i;
}

int main()
{
	constexpr size_t Max_Goalies {100};

	std::ifstream myFile("goalie_stats.csv");

	if (!myFile.is_open()) {
		std::cout << "Cannot open input file\n";
		return 1;
	}

	Goalies goalies[Max_Goalies] {};
	size_t no_goalies {};

	for (Goalies g; no_goalies < Max_Goalies && (myFile >> g); goalies[no_goalies++] = g);

	std::cout << "Data read OK. " << no_goalies << " records\n";

	int choice {};

	do
	{
		std::cout << "\n0. to quit\n";
		std::cout << "1. Sort by Wins\n";
		std::cout << "2. Sort By Losses\n";

		switch (choice = getInt("Enter choice: "))
		{
			case 0:
				std::cout << "Thanks for using my program!\n";
				break;

			case 1:
				std::cout << "Here are the Wins sorted\n\n";
				sortWins(goalies, no_goalies);
				showNames(goalies, no_goalies);
				break;

			case 2:
				std::cout << "Here are the Losses sorted\n\n";
				sortLosses(goalies, no_goalies);
				showNames(goalies, no_goalies);
				break;

			default:
				std::cout << "Invalid option\n";
				break;
		}
	} while (choice != 0);
}


Yes, you can put goalies.cpp into a different compilation unit if you want/is required. But it'll compile/run just fine as an #include.

Last edited on
I've done it this way because my professor requires that we send in the main file, .cpp file and .h file.

That's nice, but it doesn't contradict anything I've said. If you think I'm telling you not to have those 3 files, then you haven't read properly what I've written.

For the third time now:

When you have multiple C++ files, you should not use #include to include one C++ file inside another. You should set your project up so that the linker links the object files from both the C++ files into the same executable. If you're using your IDE/compiler right, it will do this for you by default.

(Using #include for source files can accidentally work in very, very simple cases. But you will very soon encounter problems with doing it that way. And if your teacher is competent, they will deduct marks for you doing it that way.)
Your file runs great and helps me understand the assignment better, thank you so much seeplus, bu i really wanted to do it on my own for experience, and i'm stuck on trying to load it into my array, i'm getting this error when running the program. I'm assuming it's something in the read or show function, i'm just not sure what?

terminate called after throwing an instance of 'std::out_of_range'
what(): basic_string::substr: __pos (which is 30) > this->size() (which is 29)

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
int main()
{

    Goalie goalies[MAX_GOALIES];
    int count;

    fstream myFile;


	if (openFileIn(myFile, "goalie_stats.csv"))
	{

	// file is open, so display the array.
	count = readGoalies(myFile, goalies);

	myFile.close();

    showGoalies(goalies, count);
	}
	else
        cout << "File open error!" << endl;
    return 0;


}



1
2
3
4
5
6
7
8
bool openFileIn(fstream &file, string name)
{
   file.open(name.c_str(), ios::in);
   if (file.fail())
      return false;
   else
      return true;
}


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
int readGoalies(fstream &file, Goalie *g_ptr)
{
    string input;	// To hold file input
    int count = 0;

    // get the header info from the first line in the file
    // This can be saved to a new string or just discarded
    getline(file, input);

    // Read widget data from file using ',' as a delimiter.
    while (count < MAX_GOALIES && getline(file, input)) {

        // vector to hold the tokens.
        vector<string> tokens;

        // Tokenize str1, using ' ' as the delimiter.
        split(input, ',', tokens);

        /*
         * copy the tokens to the goalie record
         */

        g_ptr->setName(tokens.at(1));
        g_ptr->setTeam(tokens.at(2));
        g_ptr->setWins(atoi(tokens.at(3).c_str()));
        g_ptr->setLosses(atoi(tokens.at(4).c_str()));
        g_ptr->setGoalsAllowed(atoi(tokens.at(5).c_str()));
        g_ptr->setShotsAgainst(atoi(tokens.at(6).c_str()));

        count++;
        g_ptr++;
        cout << endl;
    }
#if DEBUG
    printf("Read %d goalies from file into records\n", count);
#endif

    return count;
}


[code]
//show function
void showGoalies(Goalie *goalies, int count)
{
    cout << left;

    cout << setw(15) << "Name" << setw(10) << "Team" << setw(10) << "Wins" << setw(10) << "Losses" <<
    setw(10) << "Goals Allowed" << setw(10) << "Shots Against" << endl;
    for(int i = 0; i < count; i++) {
        cout << setw(15) << goalies->getName();
        cout << setw(10) << goalies->getTeam();
        cout << setw(10) << goalies->getWins();
        cout << setw(10) << goalies->getLosses();
        cout << setw(10) << goalies->getGoalsAllowed();
        cout << setw(10) << goalies->getShotsAgainst();
        cout << endl;
        goalies++;
    }

    cout << setprecision(3) << (double)1796/1958 << endl;
}

[/code]



Last edited on
ahh okay i was misinterpreting what you were telling me.


When you have multiple C++ files, you should not use #include to include one C++ file inside another. You should set your project up so that the linker links the object files from both the C++ files into the same executable. If you're using your IDE/compiler right, it will do this for you by default.

(Using #include for source files can accidentally work in very, very simple cases. But you will very soon encounter problems with doing it that way. And if your teacher is competent, they will deduct marks for you doing it that way.)
First I suggest you try to simplify the program. For example use std::ifstream instead of an std::fstream. A std::fstream has more failure potential when opening and since you don't need both input and output stick with the simpler ifstream.

Second why are you using std::vector in your read function but using arrays in your main()? Why are you using pointer notation to iterate through your array instead of the easier to read array notation[]?


Third where is your split() function?

Fourth you have been asked multiple times to post your input file but you still haven't posted the file.

Fifth for now I really suggest you consider using std::stringstream to parse the input line.

Sixth I don't recommend using the C function atoi() to convert a string to a number, either use a stringstream or use one of the stroX() functions. Unlike atoi() the stroX() functions can tell you if they fail to properly convert the value.

Please don't paraphrase the error message, post the complete error message, all of them, exactly as they appear in your development environment. Those messages have important information embedded within them and many times one error can cause several error messages. Also you need to always work on the first error first, fixing that one error may solve several of the other messages as well.

So ig my error has something to do with std::vector in the read function? I'm not sure how to do the other fixes you recommended besides converting it to ifstream, which i just tried and didn't work. When i run the program this is what is displayed in the console window:
 terminate called after throwing an instance of 'std::out_of_range'
  what():  basic_string::substr: __pos (which is 30) > this->size() (which is 29)

Process returned 3 (0x3)   execution time : 0.434 s
Press any key to continue. 



Split function: while (delimPosition != string::npos) <-- that's my one and only warning, and it's telling me:
C:\STAC CP2- brennan\prog3\Program3\main.cpp|152|warning: comparison of integer expressions of different signedness: 'int' and 'std::__cxx11::basic_string<char>::size_type' {aka 'long long unsigned int'} [-Wsign-compare]| -- my teacher just told us to copy and paste that code from his example program soo that one warning should be fine... i think lol

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
void split(const string& s, char delim, vector<string>& tokens)
{
   int tokenStart = 0;  // Starting position of the next token

   // Find the first occurrence of the delimiter.
   int delimPosition = s.find(delim);

   // While we haven't run out of delimiters...
   while (delimPosition != string::npos)
   {
      // Extract the token.
      string tok = s.substr(tokenStart, delimPosition - tokenStart);

      // Push the token onto the tokens vector.
      tokens.push_back(tok);

      // Move delimPosition to the next character position.
      delimPosition++;

      // Move tokenStart to delimPosition.
      tokenStart = delimPosition;

      // Find the next occurrence of the delimiter.
    auto delimPosition = s.find(delim);

      // If no more delimiters, extract the last token.
      if (delimPosition == string::npos)
      {
         // Extract the token.
         string tok = s.substr(tokenStart, delimPosition - tokenStart);

         // Push the token onto the vector.
         tokens.push_back(tok);
      }
   }
}




I just tried using ifstream instead and got the same error.


Full input file:

Player Tm W L GA SA
Jake Allen STL 19 17 121 1277
Frederik Andersen TOR 36 16 162 1958
Craig Anderson OTT 17 27 163 1676
Richard Bachman VAN 0 1 6 29
Jonathan Bernier DET 9 18 98 1025
Jordan Binnington STL 24 5 59 807
Ben Bishop DAL 27 15 87 1323
Mackenzie Blackwood NJD 10 10 55 669
Sergei Bobrovsky CBJ 37 24 153 1756
Landon Bow DAL 0 0 1 19
Kevin Boyle ANA 1 3 10 139
Laurent Brossoit WPG 13 6 49 652
Peter Budaj LAK 0 1 6 33
Jack Campbell LAK 10 14 61 845
Eric Comrie WPG 0 1 5 28
Mike Condon OTT 0 2 8 40
Pheonix Copley WSH 16 7 74 776
Corey Crawford CHI 14 18 108 1176
Joey Daccord OTT 0 1 5 40
Scott Darling CAR 2 4 27 233
Collin Delia CHI 6 4 50 545
Aaron Dell SJS 10 8 70 613
Thatcher Demko VAN 4 3 25 288
Casey DeSmith PIT 15 11 89 1060
Michael Dipietro VAN 0 1 7 24
Louis Domingue TBL 21 5 75 812
Devan Dubnyk MIN 31 28 163 1877
Brian Elliott PHI 11 11 69 741
Marc-Andre Fleury VEG 35 21 152 1745
Pavel Francouz COL 0 2 2 35
Kaden Fulcher DET 0 0 2 11
Alexandar Georgiev NYR 14 13 91 1057
Christopher Gibson NYI 0 0 1 17
John Gibson ANA 26 22 153 1838
Thomas Greiss NYI 23 14 87 1185
Philipp Grubauer COL 18 9 89 1071
Jaroslav Halak BOS 22 11 90 1158
Carter Hart PHI 16 13 81 976
Connor Hellebuyck WPG 34 23 179 2051
Adin Hill ARI 7 5 32 322
Marcus Hogberg OTT 0 2 14 121
Braden Holtby WSH 32 19 160 1795
Jimmy Howard DET 23 22 156 1709
Michael Hutchinson TOT 3 4 27 239
Carter Hutton BUF 18 25 142 1541
Tristan Jarry PIT 0 1 7 62
Chad Johnson TOT 2 11 49 406
Martin Jones SJS 36 19 176 1699
Anton Khudobin DAL 16 17 95 1232
Keith Kinkaid NJD 15 18 129 1188
Joonas Korpisalo CBJ 10 7 67 651
Mikko Koskinen EDM 25 21 146 1551
Darcy Kuemper ARI 27 20 126 1676
Maxime Lagace VEG 0 1 4 31
Robin Lehner NYI 25 13 93 1323
Charlie Lindgren MTL 1 0 5 49
Henrik Lundqvist NYR 18 23 158 1699
Roberto Luongo FLA 18 16 122 1205
Alex Lyon PHI 0 1 6 31
Jacob Markstrom VAN 28 23 166 1896
Curtis McElhinney CAR 20 11 85 968
Mike McKenna TOT 1 5 34 316
Ryan Miller ANA 8 7 51 578
Hunter Miska ARI 0 0 1 9
Sam Montembeault FLA 4 3 30 282
Petr Mrazek CAR 23 14 95 1104
Matt Murray PIT 29 14 129 1594
Alex Nedeljkovic CAR 1 0 2 26
Michal Neuvirth PHI 1 4 26 184
Antti Niemi MTL 8 6 61 539
Anders Nilsson TOT 14 19 101 1098
Eddie Pasquale TBL 2 1 12 102
Calvin Petersen LAK 5 4 27 355
Calvin Pickard TOT 4 6 48 384
Carey Price MTL 35 24 161 1952
Jonathan Quick LAK 16 23 149 1329
Antti Raanta ARI 5 6 33 351
Tuukka Rask BOS 27 13 109 1245
James Reimer FLA 13 12 93 929
Pekka Rinne NSH 30 19 130 1581
David Rittich CGY 27 9 109 1228
Juuse Saros NSH 17 10 74 870
Cory Schneider NJD 6 13 70 718
Mike Smith CGY 23 16 109 1069
Garret Sparks TOR 8 9 58 592
Alex Stalock MIN 6 8 53 525
Anthony Stolarz TOT 4 5 50 503
Malcolm Subban VEG 8 10 60 612
Cam Talbot TOT 11 17 108 997
Linus Ullmark BUF 15 14 109 1146
Semyon Varlamov COL 20 19 136 1496
Andrei Vasilevskiy TBL 39 10 128 1713
Cam Ward CHI 16 12 115 1113
Last edited on
Line 24: delimPosition is defined the second time. Thus the first definition (for the while loop / line 6) is not changed and you have nearly a infinite loop. Ust remove 'auto'.
ahh thank you! That removed the error message in my run window, but nothing shows up in the run window..? When i make the file name wrong i also get my error prompt... so the correct file is opening


Line 24: delimPosition is defined the second time. Thus the first definition (for the while loop / line 6) is not changed and you have nearly a infinite loop. Ust remove 'auto'.
Last edited on
Can someone help please this is due in 6 hours lol, i tried a new show function since maybe that was the problem, now i'm getting these 4 errors. lines 9-14 . Help is very appreciated

||=== Build: Debug in Program3 (compiler: GNU GCC Compiler) ===|
C:\STAC CP2- brennan\prog3\Program3\main.cpp||In function 'void showGoalies(Goalie*, int)':|
C:\STAC CP2- brennan\prog3\Program3\main.cpp|129|error: invalid use of member 'std::__cxx11::string Goalie::getName() const' (did you forget the '&' ?)|
C:\STAC CP2- brennan\prog3\Program3\main.cpp|129|error: expected ')' before 'c_str'|
C:\STAC CP2- brennan\prog3\Program3\main.cpp|131|error: invalid use of member 'void Goalie::setName(const string&)' (did you forget the '&' ?)|
C:\STAC CP2- brennan\prog3\Program3\main.cpp|132|error: invalid use of member 'void Goalie::setTeam(const string&)' (did you forget the '&' ?)|
||=== Build failed: 4 error(s), 2 warning(s) (0 minute(s), 0 second(s)) ===|


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
void showGoalies(Goalie *g_ptr, int count)
{
    /* Display the headings for each column, with spacing and justification flags */
    printf("%s%15s%25s%8s\n", "Name", "Team", "Wins", "Losses");

    // Read goalie data from file using ',' as a delimiter.
    for (int i = 0; i < count; i++) {

        if (g_ptr->setName.c_str() != 0) {
            printf("%-8d%-30s%-10d%-2.2f\n",
                    g_ptr->setName.c_str(),
                    g_ptr->setTeam.c_str(),
                    g_ptr->setWins,
                    g_ptr->setLosses);

            g_ptr++;
        }
        /* If the name field is zero, then we reached the last player, break
         * out of the for loop.
         */
        else
            break;
    }

}
Last edited on
Why are you trying to "set" something in a "show" function?

do you know that setName is probably a function()?

Why are you using the horrible printf() function instead of C++ streams?

Duplicate question:

http://www.cplusplus.com/forum/beginner/274564/

Please dont' do that.
Topic archived. No new replies allowed.
Pages: 123