File I/O assignment [closed] - c++

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 1 year ago.
Improve this question
I am working on an assignment, and the instruction is below:
This fifth assignment will allow you to better explore the concept of File I/O within the C++ programming language.
For this assignment, you are going to read-in (using C++ File I/O) the contents of a text file (.txt) and calculate the letter grade for a given student based upon weighted averages and write this out to a text file (.txt). We will use the weights as outlined in the Syllabus for this course: Assignments: 50%, Participation: 10%, Midterm Exam: 20%, Final Exam: 20%. Your program should read-in the grade category and then each of the respective scores separated/delimited by a comma.
Once you have finished reading the contents of the file you will need to invoke a function, calculateLetterGrade, that has a return type of void and two parameters: one of type double with By-Value semantics and the other of type char with By-Reference semantics. Your program should then write this calculated grade to another user specified text file (.txt) before terminating. You are expected to check to ensure that each respective file opens and that you properly close your file(s). The output file should have a score of 85.8 and letter grade B
Here is my code:
#include <iostream>
#include <fstream>
#include <string>
void calculateLetterGrade(double score, char &grade);
int main(){
std::string fileName("");
char grade;
double totalScore(0);
std::cout << "Welcome to the great Grade Calculator!" << std::endl;
std::cout << "Please enter the file you wish to open: ";
std::cin >> fileName;
// open file to read
std::ifstream file(fileName);
//display the file on the console
if(file.is_open())
{
std::cout << "Reading from file " << fileName << "...\n";
std::cout << "Here is your file " << std::endl;
while(std::getline(file, fileName))
{
std::cout << fileName << std::endl;
}
}
else
{
std::cout << "Unable to open file. " << std::endl;
}
// loop upto end of file
while(!file.eof())
{
// read type
std::string gradeCategory("");
file >> gradeCategory; //stream extraction
// assign the weight in each category
double weight(0);
if(gradeCategory == "Assignments")
{
weight = 0.5; //50%
}
else if(gradeCategory == "Participation")
{
weight = 0.1; //10%
}
else if(gradeCategory == "Midterm" || gradeCategory == "Final")
{
weight = 0.2; //20%
}
double total(0), count(0);
// read count of scores for type
file >> count;
// loop for count times
for(int i = 0; i < count; i++)
{
// read score and add to total
double score;
file >> score;
total = total+score;
}
// calculate average and add weighted score to totalScore
double average = total/count;
totalScore = totalScore+(average*weight);
}
// close file
file.close();
// call function to get grade
std::cout << "Calculating grades...\n";
calculateLetterGrade(totalScore,grade);
// read output filename and open it
std::cout << "Save To (Filename): ";
std::cin >> fileName;
std::ofstream fileForGrade(fileName);
// write score to file
fileForGrade << totalScore;
// write grade to file and then close file
fileForGrade << grade;
fileForGrade.close();
std::cout << "Score & Letter Grade written to file: " << fileName << std::endl;
std::cout << "Thank you for using my program, have a bless day!" << std::endl;
return 0;
}
// function to calculate grade by give score
void calculateLetterGrade(double score, char &grade){
// assign 'A' if score greater than or equal to 90
if(score>=90){
grade = 'A';
}
// assign 'B' if score greater than or equal to 80
else if(score>=80){
grade = 'B';
}
// assign 'C' if score greater than or equal to 70
else if(score>=70){
grade = 'C';
}
// assign 'D' if score greater than or equal to 60
else if(score>=60){
grade = 'D';
}
// assign 'F', means fail
else{
grade = 'F';
}
}
My code compiles, but the output file comes out to be 0 F. Can someone point out what I did wrong in the code?
UPDATE: here is my latest code:
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
void calculateLetterGrade(double score, char &grade);
int main(){
std::string fileName("");
char grade;
double totalScore(0);
std::cout << "Welcome to the great Grade Calculator!" << std::endl;
std::cout << "Please enter the file you wish to open: ";
std::cin >> fileName;
// open file to read
std::ifstream file(fileName);
//display the file on the console
if(file.is_open())
{
std::cout << "Reading from file " << fileName << "...\n";
std::cout << "Here is your file " << std::endl;
std::string line;
while(std::getline(file, line))
{
std::cout << line << std::endl;
std::istringstream iss(line);
std::string gradeCategory;
iss >> gradeCategory;
// assign the weight in each category
double weight(0);
if(gradeCategory == "Assignments")
{
weight = 0.5; //50%
}
else if(gradeCategory == "Participation")
{
weight = 0.1; //10%
}
else if(gradeCategory == "Midterm" || gradeCategory == "Final")
{
weight = 0.2; //20%
}
double total(0);
int count(0);
// read count of scores for type
iss >> count;
// loop for count times
for(int i = 0; i < count; ++i)
{
// read score and add to total
double score;
iss >> score;
total += score;
}
// calculate average and add weighted score to totalScore
double average = total/count;
totalScore = totalScore+(average*weight);
}
}
else
{
std::cout << "Unable to open file. " << std::endl;
}
// close file
file.close();
// call function to get grade
std::cout << "Calculating grades...\n";
calculateLetterGrade(totalScore,grade);
// read output filename and open it
std::cout << "Save To (Filename): ";
std::cin >> fileName;
std::ofstream fileForGrade(fileName);
// write score to file
fileForGrade << totalScore;
// write grade to file and then close file
fileForGrade << " " << grade;
fileForGrade.close();
std::cout << "Score & Letter Grade written to file: " << fileName << std::endl;
std::cout << "Thank you for using my program, have a bless day!" << std::endl;
return 0;
}
// function to calculate grade by give score
void calculateLetterGrade(double score, char &grade){
// assign 'A' if score greater than or equal to 90
if(score>=90){
grade = 'A';
}
// assign 'B' if score greater than or equal to 80
else if(score>=80){
grade = 'B';
}
// assign 'C' if score greater than or equal to 70
else if(score>=70){
grade = 'C';
}
// assign 'D' if score greater than or equal to 60
else if(score>=60){
grade = 'D';
}
// assign 'F', means fail
else{
grade = 'F';
}
}
And here is my input file named grade.txt:
Assignments
75,86,90,80,95,100
Participation
90
Midterm
75
Final
90

After the 1st while loop reads all of the file, file's position is at the end of the file. You need to call file.seekg(0) to reset the position back to the beginning of the file before you can read the contents again in the 2nd while loop.
std::ifstream file(fileName);
...
while(std::getline(file, fileName))
{
std::cout << fileName << std::endl;
}
file.seekg(0); // <-- ADD THIS!
...
That being said, consider combining the 2 loops. You can use std::istringstream to parse each line that is read.
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
...
std::ifstream file(fileName);
if (file.is_open())
{
...
std::string line;
while (std::getline(file, line))
{
std::cout << line << std::endl;
std::istringstream iss(line);
std::string gradeCategory;
iss >> gradeCategory;
...
int count = 0;
iss >> count;
double total = 0.0;
for (int i = 0; i < count; ++i)
{
double score;
iss >> score;
total += score;
}
...
}
}
else
{
std::cout << "Unable to open file. " << std::endl;
}
...
UPDATE: given that we can now see what you input file actually looks like, the code shown so far will not be able to read it correctly. You will have to make some additional logic changes to the reading loop, eg:
...
std::string line;
while (std::getline(file, line))
{
std::cout << line << std::endl;
// assign the weight in each category
std::string gradeCategory = line;
double weight = 0.0;
if (gradeCategory == "Assignments")
{
weight = 0.5; //50%
}
else if (gradeCategory == "Participation")
{
weight = 0.1; //10%
}
else if (gradeCategory == "Midterm" || gradeCategory == "Final")
{
weight = 0.2; //20%
}
// read scores and add to total
std::getline(file, line);
std::istringstream iss(line);
double score, total = 0.0;
int count = 0;
char comma;
while (iss >> score)
{
total += score;
++count;
iss >> comma;
}
if (count != 0)
{
// calculate average and add weighted score to totalScore
double average = total / count;
totalScore += (average * weight);
}
}
...
Demo

Related

file not opening via terminal using g++ file is in same directory

i made a program that processes a file with the name passed in by the user.
when compiling through an IDE i get the correect outputs, but when im compiling and running through the MacOS terminal using g++, the program doesnt catch the entered filename so im stuck in the while loop and the rest of the code wont run.
#include <iostream>
#include <fstream>
#include <sstream>
#include <iomanip>
using namespace std;
double numrows(string name)
{
double index = 0;
string currentline;
fstream myFile;
myFile.open(name);
while(myFile)
{
getline(myFile, currentline);
index++;
if(myFile.eof())
{
myFile.clear();
myFile.seekg(0,ios::beg);
break;
}
}
return index;
}
double findaverage(double numrows, double sum)
{
return (sum/numrows);
}
bool checkifvalid(string victim)
{
for(auto &ch: victim)
if(!(isdigit(ch)))
{
return false;
}
return true;
}
int main()
{
string currentline, number,NaN;
double largest = 0.0;
int index = 0;
double validcount =0.0;
double firstcolsum = 0;
fstream myFile;
bool userinput = false;
string filename;
cout << "please input file name :";
cin >> filename;
myFile.open(filename);
while(!myFile)
{
cout << "file not found please try again.." ;
cin >> filename;
myFile.open(filename);
}
double size = numrows(filename);
while(myFile)
{
getline(myFile, currentline);
stringstream ss(currentline);
while(getline(ss, number, ','))
{
bool valid = checkifvalid(number); // checking if number is valid (in string)
if(valid == false)
{
NaN += number + ",";
}
else
{
double num = stoi(number);
if(index%2 == 0) //check if index even or odd if even then its first row, viceversa
{
firstcolsum += num;
validcount++;
}
else
{
if(num > largest)
largest = num;
}
}
index++;
}
if(myFile.eof())
break;
}
double average = findaverage(validcount, firstcolsum);
cout << fixed<< setprecision(4);
cout << "The average value of all numbers in the first column: " << average << endl;
cout<< setprecision(0);
cout << "The largest value of all numbers in the second column: " << largest<< endl;
cout << "The total number of rows in the file is: " << size << endl;
cout << "The invalid numbers are: " << NaN << endl;
}`
is my current code and it works via other IDE's but not g++
i tried making new folders and sources but nothing seems to be working.
Make sure you have navigated into the folder containing the source and input files using the 'cd' command, and that the name of the input file does not contain any spaces.

Getting the input from the file as string and also integer C++

I have a text file. I have a text file consisting of member data. I am developing a program where we can get the member data from the file. After searching in the internet, I have searched a way to read all the data from the file as char array. But I want to change it where upon reading from file I want the data to be string and also integer.
name, icno, email, phone_number, acc_num, password ( read from file AS STRING )
month, year ( read from file AS INTEGER )
Content of Membership.txt
Mathavan|021127100897|MathavanKrishnan27#gmail.com|0167750575|1410065449|Mathavan1234|3|2022
Mathavan|021127100897|MathavanKrishnan27#gmail.com|0167750575|1410065448|Mathavan1234|3|2024
Mathavan|021127100897|MathavanKrishnan27#gmail.com|0167750575|1410065447|Mathavan1234|3|2022
string member_login(){
title();
fstream member;
member.open("Membership.txt",ios::in);
string pass_input, line, acc_num1, password1;
int login_attempt = 0, count = 0 , account = 0;
char dummy, resp, accno_input[25], name[25], icno[25],email [40], phone_number[25],acc_num[25],password[25],month[25], year[25];
account_num:
cout << " Enter your account number : ";
cin >> accno_input;
ifstream file("Membership.txt");
while (!file.eof()){
getline(file, line);
count++;
}
cout << accno_input;
int i = 0;
while(i <= count)
{
member.getline(name,25,'|');
member.getline(icno,25,'|');
member.getline(email,40,'|');
member.getline(phone_number,25, '|');
member.getline(acc_num,25, '|');
member.getline(password,25,'|' );
member.getline(month,25,'|' );
member.getline(year, 25);
cout << name << " ";
cout << icno << " ";
cout << acc_num << " ";
cout << accno_input;
if (acc_num == accno_input){
account = 1;
break;
}
i ++;
}
cout << account;
member.close();
if ( account != 1 ){
cout << endl;
cout << " Your account not found !!!"<< endl;
cout << " Please try again !!" << endl << endl;
cout << " PLEASE ENTER ANY KEY TO CONTINUE >>> ";
cin >> dummy;
goto account_num;
}
password1 = password;
cout << endl;
cout << " Enter your account password : ";
cin >> pass_input;
for (login_attempt = 1 ; login_attempt <= 2 ; login_attempt ++){
if (pass_input == password1){
cout << "Login Successful !!!";
break;
}
cout << endl;
cout << "Login Failed. Attempt " << login_attempt << " of 3" << endl;
cout << "Please re-enter Password: " ;
cin >> pass_input;
if (pass_input == password1){
cout << "Login Successful !!!";
break;
}
}
if ( login_attempt == 3){
cout << endl;
cout << "Login Failed. Attempt 3 of 3";
}
return accno_input;
}
There are so many things completely wrong in your program that I do recomend to you:
Delete and start from scratch.
There is no meaningful fix possible. There is even a goto. And you MUST stop using C-Style arrays with some agic dimension in C++. And C++ has many things to make your live easier. Simply use them.
Please find below a C++ solution.
You can copy and paste it and stay as you are, or, you take 3 hours and google all constructs and try to understand and learn and become a better programmer. Your choise.
#include <iostream>
#include <fstream>
#include <string>
#include <iomanip>
#include <vector>
#include <regex>
#include <iterator>
#include <algorithm>
const std::regex re{ R"(\|)" };
struct Member {
// Memeber data
std::string name{};
std::string icno{};
std::string email{};
std::string phoneNumber{};
std::string accountNumber{};
std::string password{};
int month{};
int year{};
// Extractor operator
friend std::istream& operator >> (std::istream& is, Member& m) {
// Readone complete line
if (std::string line{}; std::getline(is, line)) {
// Split it into parts
std::vector parts(std::sregex_token_iterator(line.begin(), line.end(), re, -1), {});
// assign parts to member data
if (parts.size() == 8) {
m.name = parts[0]; m.icno = parts[1]; m.email = parts[2]; m.phoneNumber = parts[3]; m.accountNumber = parts[4]; m.password = parts[5];
m.month = std::stoi(parts[6]); m.year = std::stoi(parts[7]);
}
}
return is;
}
};
// Filename for member data
const std::string fileName{ "r:\\Membership.txt" };
int main() {
// Open the data file and check, if it could be opened
if (std::ifstream fileStream{ fileName }; fileStream) {
// Read complete source file, parse it and get all data
std::vector memberData(std::istream_iterator<Member>(fileStream), {});
// We want the user to give 3 trials to enter valid data
constexpr unsigned int MaxTrials = 3u;
unsigned int numberOfTrials{};
// A valid input will stop the loop immediately
bool validInputgiven{};
// Now, try to get the correct input
while (not validInputgiven and numberOfTrials < MaxTrials) {
// Get an acoount number
std::cout << "\nEnter a account number: ";
std::string account{};
std::cin >> account;
// Check, if the account number is in the member data
if (std::count_if(memberData.begin(), memberData.end(), [&](const Member& m) { return m.accountNumber == account; }) > 0) {
// Account info wasOK. Get the password
std::cout << "\nEnter your password: ";
std::string password{};
std::cin >> password;
if (std::count_if(memberData.begin(), memberData.end(), [&](const Member& m) { return m.accountNumber == account and m.password == password; }) > 0) {
// Valid data found
validInputgiven = true;
std::cout << "\n\nEverything OK. Data validated.\n\n";
}
}
// Next try
++numberOfTrials;
if (not validInputgiven and numberOfTrials < MaxTrials) std::cout << "\nInvalid input. Please try again\n\n\n";
}
if (not validInputgiven ) std::cout << "\nToo many wrong tries. Aborting . . .\n\n\n";
}
else std::cerr << "\n\nError. Could not open source file '" << fileName << "'\n\n";
}

Error on getline function no instance matches the arguments

Why my code is not executing and showing me error ?? Im getting error on this line
while (getline(s, word, ' , '))
my Code is below:
#include <fstream>
#include <string>
#include <string.h>
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
// first we define a class that will represent all the candidates
class Candidate
{
string name;
int votes;
public:
Candidate()
{
name = "";
int votes = 0;
}
Candidate(string cand_name, int vote_count)
{
name = cand_name; votes = vote_count;
} string getName() { return name; } int getVotes() { return votes; } void get_details() { cout << name << ", " << votes << endl; }
//Following member method is used to increment the vote count
void vote_this_candidate() { votes++; }
};
int main()
{
cout << "Welcome to Student President Voting System!!!" << endl;
Candidate allCandidates[100];
int totalVotes = 0;
// File pointer fstream fin; // Open an existing file
fstream fin;
fin.open("candidantes.txt", ios::in); // Read the Data from the file // as String Vector
vector <string> row;
string line, word, temp; int index = 0; // Following while loop will iterate for each line in the file
while (fin >> temp) {
row.clear(); // read an entire row and // store it in a string variable 'line'
getline(fin, line); // used for breaking words
string s(line); // read every column data of a row and // store it in a string variable, 'word'
while (getline(s, word, ' , '))
{ // adding the splitted words to row
row.push_back(word);
} allCandidates[index] = Candidate(row[0], stoi(row[1])); totalVotes += stoi(row[1]); index++;
}
string name = ""; cout << "\nPlease enter the name of the candidante you want to vote : ";
getline(cin, name); int cand_no = -1; string userChoice; int i = 0; //Now we find the candidante with the same inputted name
while (i < index) {
if (allCandidates[i].getName() == " " + name) {
cand_no = i; cout << "Do you want to vote this candidante [y/n] : ";
cin >> userChoice; //After finding the candidate just ask the user to vote the candidante
if (userChoice == "y") { //to vote just call the member method that increments the vote count
allCandidates[cand_no].vote_this_candidate(); totalVotes++; cout << endl << "You successfully voted to " << name << " Thanks for voting!!!" << endl;
}
else { cout << "You didn't vote!!!" << endl; } break;
}
i++;
} if (cand_no == -1) {
cout << "Candidante not found!!! Do you like to add this candidate [y/n]: ";
cin >> userChoice; if (userChoice == "y") { allCandidates[index + 1] = Candidate(name, 1); totalVotes++; index++; }
}
//To show top five candidates we first sort the array with lambda
std::sort(allCandidates, allCandidates + 10, [](Candidate a, Candidate b) -> bool { return a.getVotes() > b.getVotes(); });
//then we show only first five candidates
cout << endl << "These are top 5 candidantes so far : " << endl;
for (int i = 0; i < 5; i++)
{
cout << i + 1 << ","; allCandidates[i].get_details();
} cout << endl << "Total studnets voted: " << totalVotes;
}
Problem is here:
string s(line);
while (getline(s, word, ' , '))
because getline has no overload that takes a std::string as its first parameter.
However, there is an overload that takes a stringstream, so you can do:
stringstream ss(line);
while (getline(ss, word, ' , '))
Also, ' , ' won't do what you think. Perhaps you meant ','.
Finally, int votes = 0; in your Candidate() constructor should just be votes = 0;. As it is, you are just declaring, initialising and then discarding a local variable.
The problem is that the compiler is telling you that the parameters you've given don't match a definition of the function. In your case I believe the problem is that you've given it 3 characters instead of 1 in the character portion (remember, a space is also a character). Try changing ' , ' to ','

Exception thrown at 0x5914F3BE (ucrtbased.dll)

I have some code that takes a list of names + double values from a .txt file and displays these in the command prompt. For this an array of structs is dynamically allocated. The code should know the size of the array based on the first value in the .txt file, which is then followed by the names and associated values. It should then display the list in two parts with names that have an associated double value higher than or equal to 10.000 listed first. If none of the values qualifies, it displays 'None' in the first half.
The program executes, but the debugger gives an exception and the output is not as expected.
#include <iostream>
#include <fstream>
#include <string>
#include <cstdlib>
using namespace std;
struct donor
{
string name;
double contribution = 0;
};
int main()
{
string filename;
ifstream inFile;
cout << "Enter name of data file: ";
cin >> filename;
inFile.open(filename);
cin.clear();
if(!inFile.is_open())
{
cout << "Could not open the file " << filename << endl;
cout << "Program terminating.\n";
exit(EXIT_FAILURE);
}
int amount;
inFile >> amount;
cin.clear();
donor* dlist = new donor[amount];
int i;
while(inFile.good())
{
for(i = 0; i < amount; i++)
{
getline(inFile, dlist[i].name);
cin.clear();
inFile >> dlist[i].contribution;
cin.clear();
}
}
cout << "Here's the list of Grand Patrons:\n";
bool grandpatrons = false;
for(i = 0; i < amount; i++)
{
if(dlist[i].contribution >= 10000)
{
grandpatrons = true;
cout << dlist[i].name << endl;
cout << dlist[i].contribution << endl;
}
}
if(grandpatrons == false)
{
cout << "None" << endl;
}
cout << "Here's the list of Patrons:\n";
for (i = 0; 1 < amount; i++)
{
if (dlist[i].contribution < 10000)
{
cout << dlist[i].name << endl;
cout << dlist[i].contribution << endl;
}
}
delete[] dlist;
return 0;
}
The donorlist.txt file looks like this:
4
Bob
400
Alice
11000
But the output looks like this:
Enter name of data file: donorlist.txt
Here's the list of Grand Patrons:
None
Here's the list of Patrons:
0
0
0
0
The exception that the debugger gives me is:
Exception thrown at 0x5914F3BE (ucrtbased.dll) in 6_9.exe: 0xC0000005: Access violation reading location 0xA519E363.
Now I assume something is going wrong with reading from the dynamically allocated memory. Maybe something is causing me to read from memory beyond the allocated array? I'm having trouble finding exactly where the mistake is being made.
Your problems begin with the wrong amount written in your data file.
Fix it with:
2
Bob
400
Alice
11000
They then continue with the fact that you inccorectly read the file.
Remember: Mixing operator>> and getline() is not as simple as it seems.
You see, operator>> IGNORES newline and space characters until it finds any other character.
It then reads the upcoming characters until it encounters the next newline or space character, BUT DOES NOT DISCARD IT.
Here is where the problem with getline comes in. getline reads EVERYTHING until it encounters newline or a specified delim character.
Meaning, that if your operator>> stops after encountering newline, getline will read NOTHING since it immediately encounters newline.
To fix this, you need to dispose of the newline character.
You can do this by first checking if the next character in the stream is indeed newline and then using istream::ignore() on it;
int next_char = stream.peek();
if(next_char == '\n'){
stream.ignore();
}
A working example of your code would be:
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
//Suggestion: class/struct names should start with a capital letter.
struct Donor{
//Suggestion: Use member initializer lists to specify default values.
Donor() : name(), contribution(0){}
string name;
double contribution;
};
int main(){
cout << "Enter the filename: ";
string filename;
cin >> filename;
//Suggestion: Open the file immediately with the filename and use `operator bool` to check if it opened.
ifstream inFile(filename);
if(!inFile){
cout << "Could not open the file " << filename << '\n';
cout << "Program terminating.\n";
exit(EXIT_FAILURE);
}
int amount;
inFile >> amount; //! Leaves '\n'
Donor* donors = new Donor[amount];
for(int i = 0; i < amount; ++i){
switch(inFile.peek()){
case '\n': inFile.ignore();
break;
case EOF: cout << "Donor amount too big!\n";
exit(EXIT_FAILURE);
}
getline(inFile, donors[i].name);
inFile >> donors[i].contribution;
}
cout << "Here's the list of Grand Patrons:\n";
bool grandpatrons_exist = false;
for(int i = 0; i < amount; ++i){
if(donors[i].contribution >= 10000){
grandpatrons_exist = true;
cout << donors[i].name << '\n';
cout << donors[i].contribution << '\n';
}
}
if(!grandpatrons_exist){
cout << "None\n";
}
cout << "Here's the list of Patrons:\n";
for(int i = 0; 1 < amount; ++i){
if(donors[i].contribution < 10000){
cout << donors[i].name << '\n';
cout << donors[i].contribution << '\n';
}
}
delete[] donors;
return 0;
}
Now, an even better solution would be to use vectors instead of raw pointers and implement operator>> and operator<< which would greatly simplify
the reading and printing of the objects.
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
class Donor{
public:
Donor() noexcept: name(), contribution(0){}
friend istream& operator>>(istream& stream, Donor& donor){
switch(stream.peek()){
case EOF: return stream;
case '\n': stream.ignore();
}
getline(stream, donor.name);
stream >> donor.contribution;
return stream;
}
friend ostream& operator<<(ostream& stream, const Donor& donor){
stream << donor.name << ' ' << donor.contribution;
return stream;
}
const string& get_name() const noexcept{
return name;
}
const double& get_contribution() const noexcept{
return contribution;
}
private:
string name;
double contribution;
};
int main(){
cout << "Enter the filename: ";
string filename;
cin >> filename;
ifstream inFile(filename);
if(!inFile){
cout << "Could not open the file " << filename << '\n';
cout << "Program terminating.\n";
exit(EXIT_FAILURE);
}
int amount;
inFile >> amount;
vector<Donor> donors(amount);
//Read it as `for donor in donors`
for(Donor& donor : donors){
inFile >> donor;
}
//An STL function that takes a lambda as the thirs argument. You should read up on them if you haven't.
//I would prefer using this since it greatly improves readability.
//This isn't mandatory, your implementation of this part is good enough.
bool grandpatrons_exist = any_of(begin(donors), end(donors), [](const Donor& donor){ return donor.get_contribution() >= 10000; });
cout << "Here's the list of Grand Patrons:\n";
if(grandpatrons_exist){
for(const Donor& donor : donors){
if(donor.get_contribution() >= 10000){
cout << donor << '\n';
}
}
}
else{
cout << "None\n";
}
cout << "\nHere's the list of Patrons:\n";
for(const Donor& donor : donors){
if(donor.get_contribution() < 10000){
cout << donor << '\n';
}
}
return 0;
}
Some other great improvements would be:
Use partition to seperate great patrons from normal ones.
Use stream iterators to read the objects into the vector.
int main(){
cout << "Enter the filename: ";
string filename;
cin >> filename;
ifstream inFile(filename);
if(!inFile){
cout << "Could not open the file " << filename << '\n';
cout << "Program terminating.\n";
exit(EXIT_FAILURE);
}
//Ignore the first line completely
inFile.ignore(numeric_limits<streamsize>::max(), '\n');
//Calls `operator>>` internally
vector<Donor> donors(istream_iterator<Donor>{inFile}, istream_iterator<Donor>{});
auto first_grand_patron = partition(begin(donors), end(donors), [](const Donor& donor){ return donor.get_contribution() >= 10000; });
cout << "Here's the list of Grand Patrons:\n";
if(first_grand_patron == begin(donors)){
cout << "None!\n";
}
for(auto patron = begin(donors); patron != first_grand_patron; ++patron){
cout << *patron << '\n';
}
cout << "\nHere's the list of Patrons:\n";
for(auto patron = first_grand_patron; patron != end(donors); ++patron){
cout << *patron << '\n';
}
return 0;
}
Now some general tips:
Struct/Class names should start with a capital letter.
Stop Using std::endl.
No need to cin.clear(). Cin is only used once and never again.
Use member-initializer lists.
Optionally use ++i instead of i++ in for loops to get used to the correct way of incrementing a variable unless needed otherwise.
bool grandpatrons is too much of an abstract name for a flag.
donors is a subjectively better name than short for donor list.

How do I replace a specific word within a line in a file?

My Text File:
Name G M S
Cart 1 0 1
Jane 0 1 0
What I have so far:
#include <iostream>
#include <string>
#include <fstream>
#include <stdlib.h>
#include <algorithm>
using namespace std;
void scoreChanger();
string line;
int main()
{
string yn;
int ctr = 0;
ifstream infile;
infile.open("WiiTourney.txt");
if (infile.is_open())
{
cout << "This is your current score table: " << endl;
while(getline(infile, line))
{
ctr++;
cout << line << endl;
cout << ctr << endl;
}
cout << endl;
}
else
{
cout << "Unable to open file" << endl;
}
infile.close();
cout << endl;
cout << "Would you like to change the scores? " << endl;
cin >> yn;
transform(yn.begin(), yn.end(), yn.begin(), ::tolower);
if (yn == "yes")
{
scoreChanger();
}
else
{
infile.close();
return 0;
}
return 0;
}
void scoreChanger()
{
string name;
ofstream outfile;
outfile.open("WiiTourney.txt");
if (outfile.is_open())
{
cout << "Who won the game? " << endl;
cin >> name;
transform(name.begin(), name.end(), name.begin(), ::tolower);
if (name == "jane")
{
while(getline(outfile, line))
{
cout << line << endl;
}
}
for (int x = 0; x < line.length(); x++)
{
if (line[x] == 8 && line[x] != 'G')
{
}
}
}
else
{
cout << "Error opening file. " << endl;
exit(1);
}
}
What I want it to do:
Let's say I wanted to be able to add 1 point to the Games column(G) only for Cart. The problem for me is that I only want to change the 1 in the G column and I know that I would encounter problems by just looping through and searching for instances where 1 comes up because there could be multiple 1's in one line. I am also getting the error on the line while(getline(outfile, line)) that says "no matching function for call to 'getline(std::ofstream&, std::string&)'"
Thank you, your help is very much appreciated.
My first thought was that the structure of the table is very uniform, so you could determine the position of a specific score using columns and rows.
Because the names are the only elements with variable length (assuming the scores don't go above 9, because that would give 2 characters), I would first read the first word of every row and input this into an array of names.
From this you can find specific elements using the row and column indices. If C++ doesn't contain a function to get characters based on row and column indices, I would loop through the file and add each character to the corresponding position in a 2-dimensional array.
For example:
characters[0][0]
would return N, from the start of "Names".
And of course to retrieve the score you incorporate the length of the name the specific line to get the value:
characters[names[0].length()+1][1]
This would return the score under G for the first name in the list.