I've never posted here before but I'm really stuck so I thought i'd give it a try. I've been working on this code for a while, The aim is to input a few students with their marks and to output them into tables with averages and totals. I was given a file like this:
15
Albert Einstein 52 67 63
Steve Abrew 90 86 90 93
David Nagasake 100 85 93 89
Mike Black 81 87 81 85
Andrew Van Den 90 82 95 87
Joanne Dong Nguyen 84 80 95 91
Chris Walljasper 86 100 96 89
Fred Albert 70 68
Dennis Dudley 74 79 77 81
Leo Rice 95
Fred Flintstone 73 81 78 74
Frances Dupre 82 76 79
Dave Light 89 76 91 83
Hua Tran Du 91 81 87 94
Sarah Trapp 83 98
my problem is that when I am inputting the names the program crashes after Fred Flinstone, I know its not a problem with the formatting of the next name (Frances Dupre) because when i moved him up the list it read it fine.
I have located where the program is crashing with 'cerr' outputting at different stages of the read process and it crashes when it is trying to read in Frances's marks.
a1main.cpp
#include <iostream>
#include "student.h"
using namespace std;
int main()
{
int numStds;
cin >> numStds;
cerr << endl << "Num Stds: " << numStds << endl;
Student std[numStds+1];
for(int i = 0; i <= numStds; i++)
{
std[i].readData();
std[i].printStudent();
}
// delete [] std;
return 0;
}
student.h
#include <iostream>
using namespace std;
class Student {
private:
char* name;
int mark[4];
int num;
public:
Student();
~Student();
void readData();
void printStudent();
float getTotal();
float getAverage();
};
student.cpp
#include <iostream>
#include <cstring>
#include <cctype>
#include "student.h"
using namespace std;
Student::Student()
{
name = new char;
mark[0] = 0;
mark[1] = 0;
mark[2] = 0;
mark[3] = 0;
num = 0;
}
Student::~Student()
{
// Doesn't work?
// delete name;
}
void Student::readData()
{
int l = 0;
// Reading the Name
cin >> name; // Read in the first name
l = strlen(name); // get the strlength
name[l] = ' '; // Putting a space between the first and last name
cin >> &name[l+1]; // Read in the last name
cerr << endl << "I have read the name!" << endl;
// Checking if there is a third name
if(cin.peek() == ' ')
cin >> ws; // checking and navigating past the whitespace
char next = cin.peek();
if( isalpha(next) ) // Checking whether the next cin is a char
{
l = 0;
l = strlen(name);
name[l] = ' ';
cin >> &name[l+1];
}
cerr << "I've checked for a third name!" << endl;
// Reading in the marks
for(int i = 0; i < 4; i++)
{
// Checks if the next cin is a newline
if (cin.peek() == '\n')
break;
cin >> mark[i];
}
cerr << "I've read in the marks!" << endl;
//cerr << endl << "I have read " << name << "'s marks!" << endl << endl;
for(int m = 0; m < 4; m++)
{
if(mark[m] != 0)
{
num++;
}
}
cerr << "I've incremented num!" << endl << endl;
}
// Function for error checking
void Student::printStudent()
{
cout << endl << "Student Name: " << name << endl;
cout << "Mark 1: " << mark[0] << endl;
cout << "Mark 2: " << mark[1] << endl;
cout << "Mark 3: " << mark[2] << endl;
cout << "Mark 4: " << mark[3] << endl;
cout << "num marks: " << num << endl << endl;
}
float Student::getTotal()
{}
float Student::getAverage()
{}
Can anyone see what i'm doing wrong? thanks :)
You're never allocating memory to store the student names.
In your Student constructor, add this code:
name = new char[100]; // allows names up to 100 characters long
and uncomment this line in the destructor:
delete[] name;
You could also make the code more sophisticated and robust by measuring the name length and allocating the correct size, or use std::string as suggested below.
Related
for my csc 102 assignment, I need to create a class to hold a student's grades and name. Then output that information to a text file. The grades and name are both read from an input file. I got it to succesfully run one instance of student. However, I do not know how to make the next student object read from the next line.
the input file is in this format:
Jonathan Blythe 87 76 79 88
Jessica Blake 87 79 58 86
Jonathan Lee 88 86 69 100
Joseph Blake 78 89 50 69
My first Student object Student a; reads the correct line. However, when I call the function again for another Student object Student b;, it still reads the first line, and overwrites the output file. I thought if I didn't close the file until the end of main that it may read correctly. I will show the class header file, and the implementation file for Student below.
#include "Student.h"
Student::Student() {
cout << "Default Constructor" << endl;
}
void Student::getscores() {
ifstream infile;
infile.open("input.txt");
infile >> firstName >> lastName;
for (int i = 0; i <= 3; i++) {
infile >> scores[i];
}
infile.close();
}
void Student::getaverage() {
average = 0;
for (int i = 0; i < 4; i++) {
average = average + scores[i];
}
average = average / 4;
}
void Student::print()const {
ofstream outfile;
outfile.open("output.txt");
outfile << firstName << " " << lastName << endl;
cout << firstName << " " << lastName << endl;
for (int i = 0; i <= 3; i++) {
cout << scores[i] << " ";
outfile << scores[i] << " ";
}
cout << endl;
outfile << endl;
cout << "Average Score: " << average << endl;
outfile << "Average Score" << average << endl;
cout << "Letter Grade: " << grade << endl;
outfile << "Letter Grade: " << grade << endl;
//outfile.close();
}
void Student::getletter() {
if (average >= 90)
grade = 'A';
else if (average >= 80 && average < 90)
grade = 'B';
else if (average >= 70 && average < 80)
grade = 'C';
else if (average >= 60 && average < 70)
grade = 'D';
else if (average < 60)
grade = 'F';
}
Student::~Student() {
}
and
#pragma once
#include<iostream>
#include<string>
#include <fstream>
using namespace std;
class Student
{
string lastName;
string firstName;
int scores[4] = { 0,0,0,0 };
int average = 0;
char grade = 'n';
public:
Student();
Student(string, string, int, int, int, int, char);
~Student();
void getscores();
void getaverage();
void getletter();
void print()const;
};
How do I read incrementally to the next line everytime a function is called?
One option is to pass the input stream as an argument to the function.
You should read the input.txt line by line, for each line you need to parse to get the firstName, lastName, scores then use them to create a new object of Student class (you need some changes of Student class to create object from name, set scores, etc.)
I suggest the code skeleton is something like below:
char line[128] = {0,};
ifstream infile;
infile.open("input.txt");
if (!infile.is_open()) {
return;
}
while (infile.getline(line, sizeof(line) - 1)) { // read content of next line then store into line variable
// parse content of line to get firstName, lastName, scores
...
// create new object of Student class from firstName, lastName, scores you got
...
// clear content in line
memset(line, '\0', sizeof(line));
}
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
int main()
{
ifstream fin ("data1.txt");
int ID;
string name;
int test1, test2, test3;
char answer;
cin >> answer;
while (answer = 'Y')
{
fin >> ID;
getline(fin, name);
cout << name << endl;
fin >> test1, test2, test3;
cout << ID << endl;
cout << test1 << "\t" << test2 << "\t" << test3 << "\t";
cin >> answer;
}
}
http://postimg.org/image/fjknavue9/ (Image showing the error)
It showing this error.
For some reason it is just reading the first ID. And then garbage.
This is the TXT file
211692
Ahmed, Marco
66 88 99
240885
ATamimi, Trevone
30 60 90
281393
Choudhury, Jacob
45 55 65
272760
De la Cruz, Edward
79 89 49
199593
Edwards, Faraj
90 56 96
256109
Edwards, Bill
93 94 95
246779
Gallimore, Christian
22 88 66
270081
Lopez, Luis
100 100 100
114757
Mora, Sam
63 78 88
270079
Moses, Samuel
48 95 99
193280
Perez, Albert
97 57 0
252830
Rivas, Jonathan
44 56 76
252830
Robinson, Albert
85 87 89
276895
Miranda, Michael
82 72 62
280515
Robinson, Iris
64 78 91
Program wwill only read the first id, but nothing else, yet it will display whats given, if not garbage. With knowing the solution or understanding, what is going wrong, it can help me in another program that deals with the same logic.
As #Akshat Mahajan mentioned two problems in your code, I fixed and tested them.
One more thing is needed. You should add a line fin.ignore() to ignore the the new line after taking an integer from file.
Here is the working code:
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
int main()
{
ifstream fin ("data1.txt");
int ID;
string name;
int test1, test2, test3;
char answer;
cin >> answer;
while (answer == 'Y')
{
fin >> ID;
fin.ignore();
getline(fin, name);
cout << name << endl;
fin >> test1>> test2>> test3;
cout << ID << endl;
cout << test1 << "\t" << test2 << "\t" << test3 << "\t";
cin >> answer;
}
}
However, you have done some bad practice in your code. Instead of using answer == 'Y' as the condition of while, try something like fin>>ID.
If you choose to use getline for everything, you can change your code a little bit as below.
#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
using namespace std;
int main()
{
ifstream fin ("data1.txt");
int ID;
string name, line;
int test1, test2, test3;
char answer;
cin >> answer;
while (answer == 'Y')
{
getline (fin, line);
ID = stoi(line);
getline(fin, name);
cout << name << endl;
getline(fin, line);
stringstream ss(line);
ss >> test1 >> test2 >> test3;
cout << ID << endl;
cout << test1 << "\t" << test2 << "\t" << test3 << "\t";
cin >> answer;
}
}
I'm a very novice programmer, and I'm trying to make a program that reads a txt file containing the names of 5 students (first names only) as well as four exam scores for each student. I'm trying to read the names into an array called students, then read the scores into 4 separate arrays named test1, test2, test3, test4, then display it from the monitor. The file looks like this:
Steve 78 65 82 73
Shawn 87 90 79 82
Annie 92 90 89 96
Carol 72 65 65 60
Kathy 34 50 45 20
I'm having a very hard time with breaking up the arrays and organizing them. Can someone help me? Please keep in mind I'm very novice, so I don't know a large amount about programming.
This is my code thus far:
#include <cstdlib>
#include <iostream>
#include <string>
#include <fstream>
#include <iomanip>
#include <ctime>
#define over2 "\t\t"
#define over3 "\t\t\t"
#define over4 "\t\t\t\t"
#define down5 "\n\n\n\n\n"
using namespace std;
int main(int argc, char *argv[])
{
ifstream inputFile;
//Constant for max string size
const int SIZE = 5;
//Constant for the scores
string names[SIZE], fileName, line, test1[SIZE], test2[SIZE], test3[SIZE], test4[SIZE];
//input section, user enters their file name
cout << down5 << down5 << over2 << "Please enter your file name: ";
cin >> fileName;
system("CLS");
//open the file containing the responses
inputFile.open(fileName.c_str());
cout << endl;
//kicks you out if file isn't found
if (inputFile)
{
for(int i = 0; i < SIZE; i++)
{
getline(inputFile, line);
names[i] = line;
getline(inputFile, line);
test1[i] = line;
getline(inputFile, line);
test2[i] = line;
getline(inputFile, line);
test3[i] = line;
getline(inputFile, line);
test4[i] = line;
}
inputFile.close();
}
cout << down5 << over3 << "Student\tTest1\tTest2\tTest3\tTest4\n";
cout << over3 << "-------\t-----\t-----\t-----\t-----\n";
for(int i = 0; i < SIZE; i++)
{
cout << over3 << names[i] << endl;
cout << over3 << test1[i] << endl;
cout << over3 << test2[i] << endl;
cout << over3 << test3[i] << endl;
cout << over3 << test4[i] << endl;
}
return 0;
}
Let's look at the structure of the file you're trying to read:
Steve 78 65 82 73
Shawn 87 90 79 82
Annie 92 90 89 96
Carol 72 65 65 60
Kathy 34 50 45 20
The format of the data can be described as follows:
Each line represents a single "record".
Each "record" contains multiple columns.
Columns are separated by whitespace.
You're currently using getline() for every column:
for(int i = 0; i < SIZE; i++)
{
getline(inputFile, line);
names[i] = line;
getline(inputFile, line);
test1[i] = line;
getline(inputFile, line);
test2[i] = line;
getline(inputFile, line);
test3[i] = line;
getline(inputFile, line);
test4[i] = line;
}
...whereas you actually want to read in a single line for each record and split it up:
for (int i = 0; i < SIZE; i++)
{
string line;
size_t start = 0;
// For each line, attempt to read 5 columns:
getline(inputFile, line);
names[i] = get_column(line, start);
test1[i] = get_column(line, start);
test2[i] = get_column(line, start);
test3[i] = get_column(line, start);
test4[i] = get_column(line, start);
}
Here's a modified version of your original code, which splits up each line as described above:
#include <cctype>
#include <fstream>
#include <iostream>
#include <string>
using namespace std;
static string get_column(string line, size_t &pos)
{
size_t len = 0;
// Skip any leading whitespace characters.
while (isspace(line.c_str()[pos])) { ++pos; }
// Count the number of non-whitespace characters that follow.
while (!isspace(line.c_str()[pos+len]) && line.c_str()[pos+len]) { ++len; }
// Extract those characters as a new string.
string result = line.substr(pos, len);
// Update the "start" position (for the next time this function is called).
pos += len;
// Return the string.
return result;
}
int main()
{
const int SIZE = 5;
string names[SIZE], test1[SIZE], test2[SIZE], test3[SIZE], test4[SIZE];
// Ask the user to enter a file name.
cout << "Please enter your file name: ";
string fileName;
cin >> fileName;
// Open the file and read the data.
ifstream inputFile(fileName.c_str());
if (!inputFile.is_open()) { return 0; }
for (int i = 0; i < SIZE; i++)
{
string line;
size_t start = 0;
// For each line, attempt to read 5 columns:
getline(inputFile, line);
names[i] = get_column(line, start);
test1[i] = get_column(line, start);
test2[i] = get_column(line, start);
test3[i] = get_column(line, start);
test4[i] = get_column(line, start);
}
inputFile.close();
// Display the data.
cout << "Student\tTest1\tTest2\tTest3\tTest4" << endl;
cout << "-------\t-----\t-----\t-----\t-----" << endl;
for(int i = 0; i < SIZE; i++)
{
cout << names[i] << "\t";
cout << test1[i] << "\t";
cout << test2[i] << "\t";
cout << test3[i] << "\t";
cout << test4[i] << endl;
}
}
Running the program produces the following output:
Please enter your file name: textfile.txt
Student Test1 Test2 Test3 Test4
------- ----- ----- ----- -----
Steve 78 65 82 73
Shawn 87 90 79 82
Annie 92 90 89 96
Carol 72 65 65 60
Kathy 34 50 45 20
Note that the get_column() function handles multiple spaces or too-short lines, so that this file:
Steve 78 65 82 73
Shawn 87 90
Annie 92 90 89 96
Carol 72
Kathy 34 50 45 20
...produces the following output:
Please enter your file name: textfile.txt
Student Test1 Test2 Test3 Test4
------- ----- ----- ----- -----
Steve 78 65 82 73
Shawn 87 90
Annie 92 90 89 96
Carol 72
Kathy 34 50 45 20
The previous answer is overthinking the problem.
You can use your input file stream to retrieve 'formatted input' (that is, input you know to be in a format such as 'string' then 'int', 'int', 'int', 'int') with the >> operator.
string name;
int score[4];
ifstream mf;
mf.open("score.txt");
// Get name string.
mf >> name;
// Get four score values into an array.
mf >> score[0] >> score[1] >> score[2] >> score[3];
And then:
cout << name;
cout << score[0];
cout << score[1];
cout << score[2];
cout << score[3];
So i have a program that reads from a text file and outputs to another text file. Here is the file text (format included) that it reads:
Duckey Donald 85
Goof Goofy 89
Brave Balto 93
Snow Smitn 93
Alice Wonderful 89
Samina Akthar 85
Simba Green 95
Donald Egger 90
Brown Deer 86
Johny Jackson 95
Greg Gupta 75
Samuel Happy 80
Danny Arora 80
Sleepy June 70
Amy Cheng 83
Shelly Malik 95
Chelsea Tomek 95
Angela Clodfelter 95
Allison Nields 95
Lance Norman 88
In the program it adds each of these to a struct within an array; it then calculates the grade and prints.
cout << "Student Name Test Score Grade" << endl;
for (int studentNumber = 0; studentNumber < STUDENT_NUMBER; studentNumber++){
cout << students[studentNumber].studentLName << ", "
<< students[studentNumber].studentFName << " "
<< students[studentNumber].testScore << " "
<< students[studentNumber].grade << endl;
}
The desired output looks like this:
Student Name Test Score Grade
Donald, Duckey 85 B
Goofy, Goof 89 B
Balto, Brave 93 A
Smitn, Snow 93 A
Wonderful, Alice 89 B
Akthar, Samina 85 B
Green, Simba 95 A
Egger, Donald 90 A
Deer, Brown 86 B
Jackson, Johny 95 A
Gupta, Greg 75 C
Happy, Samuel 80 B
Arora, Danny 80 B
June, Sleepy 70 C
Cheng, Amy 83 B
Malik, Shelly 95 A
Tomek, Chelsea 95 A
Clodfelter, Angela 95 A
Nields, Allison 95 A
Norman, Lance 88 B
Highest Test Score: 95
Students having the highest test score:
Green, Simba
Jackson, Johny
Malik, Shelly
Tomek, Chelsea
Clodfelter, Angela
Nields, Allison
So basically my question is this... is there any way for the test score column integers to line up like they do in my above desired output?
SOLUTION
int colWidth = 20;
for (int studentNumber = 0; studentNumber < STUDENT_NUMBER; studentNumber++){
string s = students[studentNumber].studentFName + ", " + students[studentNumber].studentLName;
int size = s.size();
cout << s << std::string(colWidth - size, ' ')
<< students[studentNumber].testScore << " "
<<
You can pad the string manually with spaces like so:
#include <string>
#include <iostream>
int main()
{
std::string first("John");
std::string last("Smith");
std::string full = last + ", " + first;
int colWidth = 20;
std::cout << "12345678901234567890\n"
<< full << std::string(colWidth - full.size(), ' ')
<< "aligned after 20 characters\n";
return 0;
}
Outputs:
12345678901234567890
Smith, John aligned after 20 characters
This will work for left justifying your text, given you calculate the number of characters you print.
For right-justifying, std::setw from <iomanip> works well. Unlike other stream manipulators, std::setw is not sticky, so it will only modify your next immediate output.
#include <string>
#include <iostream>
#include <iomanip>
int main()
{
std::string s("ABCDE");
int colWidth = 20;
std::cout << "12345678901234567890\n";
std::cout << std::setw(colWidth) << s << "\n";
return 0;
}
Prints
12345678901234567890
ABCDE
Putting it all together, I would left justify the first column, and right justify the second and third columns.
#include <string>
#include <iostream>
#include <iomanip>
int main()
{
std::string first("John");
std::string last("Smith");
std::string full = last + ", " + first;
int score = 100;
std::string grade("A");
std::cout << "123456789012345678901234512345\n"
<< full << std::string(20 - full.size(), ' ')
<< std::setw(5) << score
<< std::setw(5) << grade << "\n";
return 0;
}
Prints:
123456789012345678901234512345
Smith, John 100 A
You can change your code like this:
#include <iomanip>
cout << "Student Name Test Score Grade" << endl;
for (int studentNumber = 0; studentNumber < STUDENT_NUMBER; studentNumber++){
cout << setiosflags(ios::left) << setw(29) << setfill(' ')
<< students[studentNumber].studentLName + ", " + students[studentNumber].studentFName
<< setw(8) << students[studentNumber].testScore
<< students[studentNumber].grade << endl;
}
where 29 and 8 are calculated based on your disired output format, you can change it as you needs.
I'm having a problem assigning users to an array and then displaying the array. Typical 'flight seat-assign' program. Any help would be fantastic, as I am seriously stuck.
I haven't been getting any errors when compiling so I'm assuming I'm not too far off? code as follows.
Note, classes in separate header files.
// Flight Class - Scotia 2
// Contains information on seating (array), space available and return to menu option.
#include <iostream>
#include <string>
#include "booking.h"
using namespace std;
class Flight
{
public:
public:
struct Seat
{
int Available;
string fullName;
};// End of struct
// Structure for seat plan (24 spaces available)
struct Seat seatArray[4][6];
void seatPlan()
{ //------
cout << "Scotia Airlines Seating Plan\n";
cout << "------------------------\n";
cout << " 1D 2D 3D 4D 5D 6D\n";
cout << " 1C 2C 3C 4C 5C 6C\n";
cout << " \n";
cout << " 1B 2B 3B 4B 5B 6B\n";
cout << " 1A 2A 3A 4A 5A 6A\n";
cout << "------------------------\n\n\n";
//------
for (int i=0;i<4;i++)
{
for (int j=0;j<6;j++)
{
if (seatArray[i][j].Available == 0)
cout << seatArray[i][j].fullName << "=" << i+1;
else
cout << "Seating Plan is unavailable";
break;
}
}// End of for loop
}// End of seatPlan function
};// End of Flight class
Here is my booking class also, as I'm sure it'll help identify a problem...
//Booking class - Scotia Airlines
//This class will reserve a seat for passenger
#include <iostream>
#include <string>
using namespace std;
class Booking{
public:
struct Seat
{
int Available;
string fullName;
};// End of struct
// Structure for seat plan (24 spaces available)
struct Seat seatArray[4][6];
//variables for taking in customer details, calculating ticket cost (inc discounts) and adding details to system
public:
string fName, sName, busName, fullName;
int age, livesAt;
float discount, tickPrice, tCost;
void addBooking()
{
cout << "\tBooking Menu \n\n";
cout << "Please select ticket type: \n";
cout << "1- Business \n";
cout << "2- Western Isles \n";
cout << "3- Ordinary \n";
cin >> livesAt;
// This will be used to calc total cost for each passenger dependant on ticket type
if(livesAt == 1)
{
discount = 0.75;
cout << "Please enter your business name\n";
cin >> busName;
}
else if (livesAt == 2)
{
discount = 0.90;
}
else
{
discount = 1.0;
};
// Calculation - Standard ticket price is 60 Beans
tickPrice = 60.0;
tCost = (tickPrice * discount);
bool booked = false;
for(int i = 0; i < 4 && !booked; i++)
{
for(int j = 0; j < 6 && !booked; j++)
{
if(seatArray[i][j].Available == 1)
{
cout << "Please enter your first name \n";
cin >> fName;
cout << "Please enter your second name \n";
cin >> sName;
fullName == fName + " " + sName;
seatArray[i][j].fullName = fullName;
booked = true;
// Message on screen for customer displaying cost of flight
cout << "*******************************\n";
cout << "\tBooking for " << fName + " " + sName << " confirmed.\n";
cout << "\tTotal cost = " << tCost << " GBP.\n";
}//end of if
}//end of for2
}//end of for1
}// End of addBooking function
};// End of Booking class
Any help would be greatly appreciated!
Here are some errors I have spotted:
First of all you never mark a seat as not available. Add this to your add booing function.
Second the else in the second for in seatPlan should be in the else I believe.
You don't need a semi-column after an else statement(in the else when setting discount to 1.0)
As you never mention what are the errors you are getting this is as good as I can get. Hope this answer helps.