How to skip reading the first line of file? - c++

How can I ignore the first line of the text file and start at the second line when I called it in the code? I was wondering how. Also, how can I sort the file according to first name, last name and grade? I just have the first name sorted but not the last name and grade accordingly. If you have any idea, I hope you can share it with me. Thanks for the help! Here's my code:
#include <iostream>
#include <fstream>
using namespace std;
struct studentRecord{
string lastname;
string firstname;
string grade;
};
int main(){
ifstream ifs("student-file.txt");
string lastname, firstname, grade, key;
studentRecord records[20];
if(ifs.fail()) {
cout << "Error opening student records file" <<endl;
exit(1);
}
int i = 0;
while(! ifs.eof()){
ifs >> lastname >> firstname >> grade;
records[i].lastname = lastname;
records[i].firstname = firstname;
records[i].grade = grade;
i++;
}
for (int a = 1, b = 0; a < 20; a++) {
key = records[a].firstname ;
b = a-1;
while (b >= 0 && records[b].firstname > key) {
records[b+1].firstname = records[b].firstname;
b--;
}
records[b+1].firstname = key;
}
for (int k = 0; k < 20; k++) {
cout << "\n\t" << records[k].firstname << "\t"<< records[k].lastname << "\t" << records[k].grade;
}
}

When I saw this post it reminded me of a similar task completed at uni. I have rewritten your code to perform the same task but using classes instead of structs. I have also included a way to sort the vector by using the function here.
I have included the "ignore first line" method #Scheff's Cat mentioned.
Here it is:
#include <iostream>
#include <fstream>
#include <sstream>
#include <limits>
#include <string>
#include <vector>
using namespace std;
class studentrecord{
string firstname, lastname, grade;
public:
studentrecord(string firstname, string lastname, string grade){
this -> firstname = firstname;
this -> lastname = lastname;
this -> grade = grade;
}
friend ostream& operator<<(ostream& os, const studentrecord& studentrecord) {
os << "\n\t" << studentrecord.firstname << "\t" << studentrecord.lastname << "\t" << studentrecord.grade;
return os;
}
};
void displayRecords(vector <studentrecord*> records){
for(int i = 0; i < records.size(); i++){
cout << *records[i];
}
}
int main(){
//read in file
ifstream infile;
infile.open("student-file.txt");
infile.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
if (!infile.is_open()){
cout << "Error opening student records file" <<endl;
exit(1);
}
vector <studentrecord*> records;
string firstname, lastname, grade;
while (infile >> firstname >> lastname >> grade;) {
records.push_back(new studentrecord(firstname, lastname, grade));
}
displayRecords(records);
return 0;
}
To sort the vector so that it prints in order of either first name, last name or grade I used the following functions:
bool sortfirstname(studentrecord* A, studentrecord* B) {
return (A->getfirstname() < B->getfirstname());
}
bool sortlastname(studentrecord* A, studentrecord* B) {
return (A->getlastname() < B->getlastname());
}
bool sortgrade(studentrecord* A, studentrecord* B) {
return (A->getgrade() < B->getgrade());
}
sort(records.begin(), records.end(), (sortfirstname));
sort(records.begin(), records.end(), sortlastname);
sort(records.begin(), records.end(), sortgrade);
If you wanted to sort by first name you would call the sort(records.begin(), records.end(), (sortfirstname)); function and then the displayrecords() function.
The advantage of using classes stored in vectors is that you don't have to state the size of the vector containing the details about students since you can keep adding information to the end of the vector using the vector.push_back() function. It also makes sorting the data contained easier.
If anything isn't clear, let me know and I can give you a hand.

Related

Passing Arrays through functions and pulling certain objects

I am working on an assignment that I am needing assistance on. I need to verify I did my array first (to make sure they are all pulling correctly) and then pass that array to another function that will loop through the array and look for a certain custID that will be entered into the console by the user. Here is my current code.
This is my singleton file
#include "MyDataStore.h"
#include <fstream>
MyDataStore * MyDataStore::iInstance;
//Declare private customer array..
Customer customers[5];
void getCustomerList(Customer[], int);
MyDataStore::MyDataStore()
{
getCustomerList(customers, 5);
}
MyDataStore * MyDataStore::GetInstance()
{
if (iInstance == NULL())
{
iInstance = new MyDataStore();
}
return iInstance;
}
void MyDataStore::getBooks(Book books[], int size)
{
ifstream input;
input.open("Books.txt");
string ISBN, title, author;
double price = 0.0;
int i = 0;
while (input >> title >> author >> ISBN >> price)
{
Book b = Book(ISBN, title, author, price);
if (i < size)
{
books[i] = b;
i++;
}
}
}
Customer MyDataStore::getCustomer(int custID) // need help here
{
//for (int i = -0; i < 5; i++) {
for (Customer c: customers)
{
if (custID = c.getCustID())
{
//custID = c.getCustID();
return c;
}
}
//}
//for range
//for each customer c in customers
//if custID = c.getCustID()
//return c
//
}
void getCustomerList(Customer customers[], int size)
{
//need help here
ifstream custfile;
custfile.open("Customer.txt");
int custID;
string firstName, lastName, city, street, state, zip;
Address address;
int i = 0;
while (custfile >> custID >> firstName >> lastName >> city >> street >> state >> zip)
{
Customer c = Customer(custID, firstName, lastName, address);
if (i < size)
{
customers[i] = c;
i++;
}
//Need to make the address part work
}
//load customer array
}
This is the source file it is being called to:
#include <iostream>
#include <string>
#include "Address.h"
#include "Book.h"
#include "Customer.h"
#include "MyDataStore.h"
#include <fstream>
using namespace std;
//Main function
void main()
{
MyDataStore * obj1 = MyDataStore::GetInstance();
MyDataStore * obj2 = MyDataStore::GetInstance();
//declare a book array --> this works great!
Book books[6];
//send array to get books
MyDataStore::getBooks(books, 6);
//loop through the filled in book array and just show the author
for (Book b: books)
{
cout << b.getTitle() << endl;
cout << b.getAuthor() << endl;
cout << b.getPrice() << endl;
}
//This will only print out the first line.
Customer c = MyDataStore::getCustomer(2345);
cout << c.print();
system("pause");
}
I hope this all makes sense. So I need to check to see if in the singleton if my
void getCustomerList(Customer customers[], int size)
is actually doing the array correctly (there are 5 items, all coming from the text file. I also need to then put then in the:
Customer MyDataStore::getCustomer(int custID)
But, I need to ask the console what the custID is and validate it, if it is what is listed in the text, then print it, if not then default it to 0 or say invalid.
I hope this all makes sense, thank you for any help!
Figured out, the rest of the code was correct, this is what I had to add to get it to work properly.
Inside the Singleton:
Customer MyDataStore::getCustomer(int custID)
{
for (Customer c : customers) {
if (custID == c.getCustID()) {
return c;
}
}
}
Inside of the source code:
int x = 0;
cout << "Please enter the customer ID!" << endl;
cin >> x;
Customer c = MyDataStore::getCustomer(x);
cout << c.print();

C++ program hangs when using cin.getline()

I am making a program keeping track of different persons, which I try to read in from a file. I use a constructor that takes an ifstream file as an argument, and I then try to read in the data from the file. I can read the first line, which is just an int (a unique number for each person), but when I try to go to the next line and getline it, the program hangs. Does anyone know why?
#include <iostream>
#include <fstream>
#include <cstring>
#include <cctype>
#include <cstdlib>
using namespace std;
const int MAXPERS = 100;
const int MAXTXT = 80;
const int DATELEN = 7;
class Person {
private:
int nr;
char* firstName;
char birthDate[DATELEN];
public:
Person() {
char fname[MAXTXT];
cout << "First name: "; cin.getline(fname, MAXTXT);
firstName = new char[strlen(fname) + 1];
strcpy(firstName, fname);
cout << "Birth date (DDMMYY): ";
cin >> birthDate; cin.ignore();
}
Person(int n, ifstream & in) {
nr = n;
char fname[MAXTXT];
cin.getline(fname, MAXTXT);
firstName = new char[strlen(fname) + 1];
strcpy(firstName, fname);
in >> birthDate;
}
void display() {
cout << "\nFirst name: " << firstName;
cout << "\nBorn: " << birthDate;
}
void writeToFile(ofstream & ut) {
ut << firstName << "\n" << birthDate;
}
};
void readFromFile();
Person* persons[MAXPERS + 1];
int lastUsed = 0;
int main() {
readFromFile();
persons[1]->display();
return 0;
}
void readFromFile() {
ifstream infile("ANSATTE.DAT");
if(infile) {
while(!infile.eof() && lastUsed < MAXPERS) {
int nr;
infile >> nr;
persons[++lastUsed] = new Person(nr, infile);
}
}
}
My file looks like this:
1
Andy
180885
2
Michael
230399
In your constructor you have
cin.getline(fnavn, MAXTXT);
So your program is waiting for you to type something in. If you meant to get the name from the file then you need
in.getline(fnavn, MAXTXT);
^^ ifstream object
You are also going to run into the issue of mixing >> with getline. You will need to add
infile.ignore(std::numeric_limits<std::streamsize>::max(), '\n')
after infile >> nr; in your while loop.
strlen(fname + 1) will be strlen(fname) - 1 if fname is one-character long or more and indeterminate if fname is zero-character long. It should be strlen(fname) + 1.
strlen(fnavn + 1) has the same issue and should be strlen(fnavn) + 1.

C++ and output on files

I was trying to do a C++ program who do a thing like this:
in a list of surname and name (file), read the same surname and stamp in another file 'people with surname surname are: name,name,name etc..
That's is what i did, but something went wrong
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
struct persona
{
string nome;
string cognome;
};
int carica_vettore (persona a [])
{
string name, surname;
int i=0, np=0;
ifstream fin ("people.txt");
while (cin >> name >> surname)
{
if (name == "0" && surname == "0")
break;
a[i].nome = name;
a[i].cognome = surname;
i++;
np++;
}
return np;
}
int main ()
{
string nomepers, cognomepers;
int cont = 0;
persona persone [50];
cont = carica_vettore(persone);
for (int k = 0; k < cont; k++)
{
for (int j = k+1; j < cont-1; j++)
if (persone[k] == persone[j])
cout << "People with surname (" << persone[i] << "), are: " << persone[i].nome;
}
return 0;
}
And also i forget to stamp on file, but i think that's is not such a big problem
So, anyone could help me?
2 'for' who check if there is any same surnames btw
Didn't you mean to read from a file?
ifstream fin("people.txt");
while(cin >> name >> surname) // cin reads from the console, waits for your input
Replace cin with fin.
You also don't have operator== for persona overloaded:
bool operator==(persona const& other) const
{
return nome == other.nome && cognome == other.cognome;
}
And also operator<<, which is required here:
cout << "People with surname (" << persone[i] << ...
Print persone[i].nome or persone[i].cognome instead.
if (persone[k] == persone[j]) is the problem. The error message tells you what is wrong and what the line number is. you are comparing two Persona structs, but you cannot use the == operator on them. maybe you should compare their nome or cognome values instead.

C++ import data from a .txt file via a string pointer

players.txt
2
Zlatan
Ibrahimovic
1981
4
20130110
20130117
20130122
20130208
Yohan
Cabaye
1986
1
20130301
Main.cpp
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
int main()
{
ifstream pFile("players.txt");
int numberOfPlayers;
string firstName;
string lastName;
int birthYear;
int numberOfMatches = 0;
string *matchDates = NULL;
matchDates = new string[];
while (pFile >> numberOfPlayers >> firstName >> lastName >> birthYear >> numberOfMatches >> matchDates)
{
for(int i = 0; i < numberOfPlayers; i++)
{
cout << firstName << endl;
cout << lastName << endl;
cout << birthYear << endl;
for(int i = 0; i < numberOfMatches; i++)
{
cout << matchDates[i] << endl;
}
}
}
delete[] matchDates;
getchar();
return 0;
}
So I want to import data from a textfile, e.g. soccer players as above or anything else, like hockey players etc. The point is to be able to use this code for all kind of sports aka it's not set to like 12 players max, amount of players should be dynamic. Well I'm already stuck here with what I thought was a dynamic array (matchDates) but I've been told that it's not and is still a static array.
matchDates should also be dynamic because some players could've 20 mathcdates, another could have five, another three and so on. In my example zlatan has four and youhan one.
Well my problem appear on line 20, posted below:
while (pFile >> numberOfPlayers >> firstName >> lastName >> birthYear >> numberOfMatches >> matchDates)
Error message when I hover over the bolded ">>" (which is underlined with red in VS)
Error no operator ">>" matches these operands
operand types are: std::basic_istream> >> std::string *
I want to print out all matchdates but it doesn't work and I'm very sure it's something to do with matchDates.
Thanks in advance and regards Adam
Use C++ class for player, stop using new and override stream operator.
See the code in action here
#include <iostream>
#include <string>
#include <deque>
#include <fstream>
#include <algorithm>
#include <iterator>
using namespace std;
class Player
{
public:
Player() : firstName(""), lastName(""), birthYear(0){}
~Player() {}
//copy ctor by default
// Operator Overloaders
friend ostream &operator <<(ostream &output, const Player p);
friend istream &operator >>(istream &input, Player &p);
private:
string firstName;
string lastName;
int birthYear;
deque<string> matchDates;
};
ostream& operator <<( ostream& output, const Player p )
{
output << p.firstName << " " << p.lastName << " etc ...";
return output;
}
istream& operator >>( istream& input, Player &p )
{
input >> p.firstName;
input >> p.lastName;
input >> p.birthYear;
int nbMatch = 0; input >> nbMatch;
for(int i = 0 ; i < nbMatch ; ++i) {
string match_date; input >> match_date;
p.matchDates.push_back(match_date);
}
return input;
}//*/
int main()
{
//ifstream pFile("players.txt");
int numberOfPlayers;
deque<Player> players;
cin >> numberOfPlayers; int i = 0;
while( i < numberOfPlayers)
{
Player p;
cin >> p;
players.push_back(p);
i++;
}
std::ostream_iterator< Player > output( cout, "\n" );
cout << "What we pushed into our deque: ";
copy( players.begin(), players.end(), output );
getchar();
return 0;
}
The Problem
This is the error Clang gives me:
error: invalid operands to binary expression ('istream' and 'string *')
Then it goes on to list the various overloads of operator>>() and why a right-hand operand of type std::string* cannot convert to respective right-hand types. This is expected because there are no overloads of operator>>() that take a pointer or array of that type.
Solution
When reading into an array, you normally read into "temporary" objects and copy that to the array. For example:
#include <iostream>
int main()
{
int array[5];
for (int i = 0, temp; i < 5 && std::cin >> temp; ++i)
{
array[i] = temp;
}
}
But in your case, you initialized your array with the following line which I assume to be an attempt to create an indefinitely-sized array:
matchDates = new string[];
I don't know about Visual Studio, but on Clang I got the following error:
Error(s):
error: expected expression
int* j = new int[];
^
1 error generated
Dynamically-sized arrays are not possible in C++. If you need an array that will grow in size, consider using a std::vector. You would need to call push_back() to insert elements.
You can put things at one line to ease the code for your eye but don't over do it. Take a 'record' as a one record, so you can say.
An array doesn't have the >> operator.
Would go for user 0x499602D2 his answer but I may not upvote nor comment yet, so I put it here as I already answered. ;)
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
int main()
{
ifstream pFile( "players.txt" );
int numberOfPlayers;
string firstName;
string lastName;
int birthYear;
int numberOfMatches = 0;
while( pFile >> numberOfPlayers )
{
for( int i = 0; i < numberOfPlayers; i++ )
{
pFile >> firstName >> lastName >> birthYear >> numberOfMatches;
cout << firstName << endl;
cout << lastName << endl;
cout << birthYear << endl;
for( int i = 0; i < numberOfMatches; i++ )
{
string date;
pFile >> date;
cout << date << endl;
}
}
}
getchar();
return 0;
}
To maintain the data you can createa a struct (or class). The second while loop is just to print out while the first gets the data.
#include <iostream>
#include <string>
#include <fstream>
#include <vector>
using namespace std;
struct Player
{
string firstName;
string lastName;
int birthYear;
std::vector<string> matchDates;
};
int main()
{
ifstream pFile( "players.txt" );
int numberOfPlayers;
int numberOfMatches = 0;
std::vector<Player> players;
// fill the vector players
while( pFile >> numberOfPlayers )
{
for( int i = 0; i < numberOfPlayers; i++ )
{
// create player struct and fill it
Player player;
pFile >> player.firstName >> player.lastName >> player.birthYear >> numberOfMatches;
for( int i = 0; i < numberOfMatches; i++ )
{
string date;
pFile >> date;
player.matchDates.push_back( date );
}
// add it to the vector
players.push_back( player );
}
}
// print out the values
std::vector<Player>::iterator iterPlayer = players.begin(),
endPlayer = players.end;
while( iterPlayer != endPlayer )
{
Player player = *iterPlayer;
cout << player.firstName << endl;
cout << player.lastName << endl;
cout << player.birthYear << endl;
std::vector<string>::iterator iterDates = player.matchDates.begin(),
endDates = player.matchDates.end;
while( iterDates != endDates )
{
string date = *iterDates;
cout << date << endl;
}
}
getchar();
return 0;
}

Using getline to read data from a file in C++

I want to read from a file two things, the full name (first name and last name)
and age. After that I want to store them in an array then print the data.
However, when I try to reading the first record is read find, but the other two are not.
Please tell me what am I missing.
Thank you.
The content of the file is:
sampleFirst1 sampleLast1
30
sampleFirst2 sampleLast2
25
sampleFirst3 sampleLast3
40
The Output is:
Name: sampleFirst1 Age: 30
Name: Age: 30
Name: Age: 30
Here's my Code:
#include "Person.h"
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
ifstream inputFile("data.txt", ios::in);
string full_name;
int age = 0;
int i = 0;
Person personArray[3];
while (i < 3)
{
getline(inputFile, full_name);
personArray[i].set_name(full_name);
inputFile >> age;
personArray[i].set_age(age);
++i;
}
inputFile.close();
printData(personArray, 3);
cout << endl;
return 0;
}
You should not mix getline and the >> operator in that way. Prefer a simpler code like this one :
#include <iostream>
#include <fstream>
#include <array>
#include <string>
using namespace std;
struct Person {
std::string name;
int age;
void set_name(std::string const& i_name) { name = i_name; }
void set_age(int i_age) { age = i_age; }
};
int main()
{
ifstream inputFile("data.txt", ios::in);
std::string first;
std::string last;
int age = 0;
int i = 0;
std::array<Person,3> personArray;
while (i < personArray.size()) {
inputFile >> first >> last >> age;
personArray[i].set_name(first + " " + last);
personArray[i].set_age(age);
++i;
}
inputFile.close();
for(Person const& person : personArray) {
std::cout << "Name: " << person.name << " Age: " << person.age << "\n";
}
std::cout << std::flush;
return 0;
}
Or use only getline and a istringstream to pase the age if you dont want to pay the string concatenation extra cost for the full name.
A lot could be said of the parsing method but that is not the point here.