How to read data from a text file into a struct - c++

I'm completely new to C++ and currently I'm trying to read very basic text file which look like this:
Dr John Doe
British
2
Soccer
Swimming
and my expected output should look like:
My information
Name: John Doe
Nationality: British
I have 2 hobbies:
1. Soccer
2. Swimming
My header file:
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <cstdlib>
#include <ctime>
#include <vector>
using namespace std;
const int MAX = 80;
const int MAXNO = 5;
enum Title {Miss, Mrs, Mr, Dr, Unknown};
struct Date
{
int day;
int month;
int year;
};
struct MyInfo
{
char name [MAX];
char national [MAX];
int noOfHobbies;
char hobby [MAXNO][MAX];
};
void getMyInfo (fstream& , char[] , MyInfo&);
void displayMyInfo (MyInfo);
My functions:
#include "Lab_1.h"
void getMyInfo (fstream& afile,char fileName[], MyInfo& x) {
afile.open (fileName);
if (!afile)
{
cout << "Binary file " << fileName << " opened for creation failed" << endl;
exit (-1);
}
cout << "\n" << "Begin reading of " << fileName << endl;
string line;
while(getline(afile, line))
{
afile >> x.national;
afile >> x.noOfHobbies;*/
if (afile >> x.name >> x.national >> x.noOfHobbies) {
cout << "Name: " << x.name << ", "
<< "National: " << x.national << ", "
<< "noOfHobbies: " << x.noOfHobbies << ", "
<< endl;
}
}
}
void displayMyInfo (MyInfo x) {
}
My main function:
#include "Lab_1.h"
int main () {
fstream afile;
MyInfo x;
string fileName;
getMyInfo(afile,"textfile.txt",x);
//displayMyInfo(x);
afile.close ();
}
The above code output nothing because I just put everything I understand over the forum with similar question. Since I'm already stuck for 1 day even though I've already done a lot of research but most of them suggest to use vector which I'm not familiar with at this moment, so can someone give me a solution to this problem? Thank you very much for your help in advance.

Random act of madness kindness:
Live On Coliru
#include <fstream>
#include <set>
struct Person {
std::string name;
std::string nationality;
std::set<std::string> hobbies;
friend std::istream& operator>>(std::istream& is, Person& into) {
size_t n = 0;
if (getline(is, into.name) &&
getline(is, into.nationality) &&
is >> n && is.ignore(1024, '\n'))
{
while (n--) {
std::string hobby;
if (getline(is, hobby))
into.hobbies.insert(hobby);
else
is.setstate(std::ios::failbit);
}
}
return is;
}
};
#include <iostream>
int main() {
std::ifstream ifs("input.txt");
Person p;
if (ifs >> p) {
std::cout << "My information\n";
std::cout << p.name << "\n";
std::cout << p.nationality << "\n";
std::cout << "I have " << p.hobbies.size() << " hobbies:\n";
size_t counter = 0;
for(auto const& hobby : p.hobbies) {
std::cout << ++counter << ". " << hobby << "\n";
}
} else {
std::cerr << "Parse failure\n";
}
}

Related

Combine input and output streams

I want to combine both input and output stream to the output stream.
I mean, if this is my code:
int num;
string str;
cout << "string: ";
cin >> str;
cout << "num: ";
cin >> num;
cout << "num is " << num << " str is " << str;
And I redirect the input stream to a txt file contains:
hey 1
My output stream will contain:
string: hey
num: 1
num is 1 str i hey
insted of:
string: num: num is 1 str is hey
I don't want to cout each variable in cin after I get my input. I want it to be automatically.
Overload std::istream::operator >> for a wrapper class and do what you like:
// Example program
#include <istream>
#include <string>
#include <vector>
class AutoCinToCoutReader {
public:
inline void write(const std::string& in) { std::cout << in << std::endl; }
};
std::istream& operator >> (std::istream& is, AutoCinToCoutReader& dt)
{
std::string in;
is >> in;
dt.write(in);
return is;
}
void read(const std::string& what, AutoCinToCoutReader& rd) {
std::cout << what << ": ";
std::cin >> rd;
}
int main()
{
AutoCinToCoutReader rd;
std::vector<std::string> fields = { "Test1", "Test2" };
for(const std::string& field : fields) {
read(field, rd);
}
}
Update:
The smallest thing I could offer is:
// Example program
#include <string>
#include <vector>
#include <iostream>
#include <istream>
#include <ostream>
std::istream& operator >> (std::istream& is, std::ostream& os) {
std::string in;
is >> in;
os << in << std::endl;
return is;
}
void read(const std::string& what) {
std::cout << what << ": ";
std::cin >> std::cout;
}
int main()
{
std::vector<std::string> fields = { "Test1", "Test2" };
for(const std::string& field : fields) {
read(field);
}
}
You can not immediately write into cout from cin. In any case, you need to work around it. See the updated operator, directly outputting to cout after storing in cin.

Copy from one structure to another structure of different type

I am trying this piece of code in vs 2008
#include <stdio.h>
#include <iostream>
#include <string>
typedef struct _first
{
int age;
std::string name;
}first;
typedef struct _second
{
int age;
char name[20];
}second;
void copy_structure()
{
first s;
second f;
f.age = 15;
cout<<"Enter the name"<<endl;
fgets(f.name, 20, stdin);
memcpy(&s,&f,20);
cout << "Name: " << s.name << endl;
cout << "Age: "<< s.age << endl;
}
int main()
{
copy_structure();
return 0;
}
while building I didn't get any error but when I run, name field is empty over here
cout << "Name: " << s.name << endl;
I am not getting any output over here, can somebody help me to solve this issue.
You should use an approach based on member-wise copying. For example
void copy_structure()
{
first f;
^^
second s;
^^
s.age = 15;
cout<<"Enter the name"<<endl;
fgets(s.name, 20, stdin);
f.age = s.age;
f.name = s.name;
cout << "Name: " << f.name << endl;
cout << "Age: "<< f.age << endl;
}
Otherwise the internals of the object name of the type std::string will be overwritten and the program will have undefined behaviour.
This looks like C but not like C++... Your current code will also brick your std::string instance. memcpy is dangerous and should not be used, unless you have a very, very good reason. I never had a reason for this so far.
My suggestion:
#include <iostream>
#include <string>
using namespace std;
struct second
{
int age;
char name[20];
};
struct first
{
int age;
string name;
first& operator=(const second& rhs);
};
// some operator for copying
first& first::operator=(const second& rhs)
{
age = rhs.age;
name = rhs.name;
return *this;
}
int main()
{
first s;
second f;
f.age = 15;
cout << "Enter your name" << endl;
cin >> f.name;
s = f;
cout << "Name: " << s.name << endl;
cout << "Age: " << s.age << endl;
return 0;
}
This is improvable, of course. You would usually rather use classes than structs. And you would might also have an operator>> for second.

Floating Point Exception while reading from file

the program should read from 2 files (author.dat and citation.dat) and save them into a map and set;
first it reads the citationlist without problem, then it seems to properly read the authors and after it went through the whole list (author.dat) a floating point exception arises .. can't quite figure out why
seems to happen in author.cpp inside the constructor for authorlist
author.cpp:
#include <fstream>
#include <iostream>
#include "authors.h"
using namespace std;
AuthorList::AuthorList(char *fileName) {
ifstream s (fileName);
int idTemp;
int nrTemp;
string nameTemp;
try {
while (true){
s >> idTemp >> nrTemp >> nameTemp;
cout << idTemp << " " << nrTemp << " " << nameTemp << " test_string";
authors.insert(std::make_pair(idTemp,Author(idTemp,nrTemp,nameTemp)));
if (!s){
cout << "IF-CLAUSE";
throw EOFException();
}
cout << "WHILE-LOOP_END" << endl;
}
} catch (EOFException){}
}
author.h:
#ifndef CPP_AUTHORS_H
#define CPP_AUTHORS_H
#include <iostream>
#include <map>
#include <string>
#include "citations.h"
class Author {
public:
Author (int id, int nr, std::string name) :
articleID(id),
authorNR(nr),
authorName(name){}
int getArticleID() const {
return articleID;
}
std::string getAuthorName() const {
return authorName;
}
private:
int articleID;
int authorNR;
std::string authorName;
};
class AuthorList {
public:
AuthorList(char *fileName);
std::pair<std::multimap<int,Author>::const_iterator, std::multimap<int,Author>::const_iterator> findAuthors(int articleID) {
return authors.equal_range(articleID);
}
private:
std::multimap<int,Author> authors;
};
#endif //CPP_AUTHORS_H
programm.cpp:
#include <iostream>
#include <cstdlib>
#include "citations.h"
#include "authors.h"
#include "authorCitation.h"
using namespace std;
int main(int argc, char *argv[]){
CitationList *cl;
AuthorList *al;
//check if argv array has its supposed length
if (argc != 4){
cerr << "usage: programm article.dat citation.dat author.dat";
return EXIT_FAILURE;
}
//inserting citation.dat and author.dat in corresponding lists (article.dat not used)
cl = new CitationList(argv[2]);
al = new AuthorList(argv[3]);
try {
AuthorCitationList *acl;
acl->createAuthorCitationList(al,cl);
acl->printAuthorCitationList2File("authorcitation.dat");
} catch (EOFException){
cerr << "something went wrong while writing to file";
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
All files:
https://drive.google.com/file/d/0B734gx5Q_mVAV0xWRG1KX0JuYW8/view?usp=sharing
I am willing to bet that the problem is caused by the following lines of code:
AuthorCitationList *acl;
acl->createAuthorCitationList(al,cl);
You are calling a member function using an uninitialized pointer. I suggest changing the first line to:
AuthorCitationList *acl = new AuthorCitationList;
Add any necessary arguments to the constructor.
While you are at it, change the loop for reading the data also. You have:
while (true){
s >> idTemp >> nrTemp >> nameTemp;
cout << idTemp << " " << nrTemp << " " << nameTemp << " test_string";
authors.insert(std::make_pair(idTemp,Author(idTemp,nrTemp,nameTemp)));
if (!s){
cout << "IF-CLAUSE";
throw EOFException();
}
cout << "WHILE-LOOP_END" << endl;
}
When you do that, you end up adding data once after the end of line has been reached. Also, you seem to have the last line in the wrong place. It seems to me that it should be outside the while loop.
You can use:
while (true){
s >> idTemp >> nrTemp >> nameTemp;
// Break out of the loop when reading the
// data is not successful.
if (!s){
cout << "IF-CLAUSE";
throw EOFException();
}
cout << idTemp << " " << nrTemp << " " << nameTemp << " test_string";
authors.insert(std::make_pair(idTemp,Author(idTemp,nrTemp,nameTemp)));
}
cout << "WHILE-LOOP_END" << endl;
You can simplify it further by using:
while (s >> idTemp >> nrTemp >> nameTemp){
cout << idTemp << " " << nrTemp << " " << nameTemp << " test_string";
authors.insert(std::make_pair(idTemp,Author(idTemp,nrTemp,nameTemp)));
}
cout << "WHILE-LOOP_END" << endl;

text file contents to array

I have a text file-> info.txt which contains the follow Id,games,amount
info.txt
1,left4dead,50
2,warcraft3,60
I know how to extract the details using vectors with my codes shown below.
stock.h
#ifndef stock_stock_h
#define stock_stock_h
#include <iostream>
class stock {
public:
stock() {
columnOneText = " ";
columnTwoText = " ";
}
stock(std::string columnOneText,
std::string columnTwoText
);
std::string getColumnOne();
std::string getColumnTwo();
void setItemId(std::string columnOneText);
void setItemDescription(std::string columnTwoText);
private:
std::string columnOneText, columnTwoText;
};
#endif
main.cpp
#include "stock.h"
#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
#include <vector>
using namespace std;
stock::stock(string columnOneText,
string columnTwoText)
{
setItemId(columnOneText);
setItemDescription(columnTwoText);
};
string stock::getColumnOne() {
return columnOneText;
}
string stock::getColumnTwo() {
return columnTwoText;
}
void stock::setItemId(string columnOneText) {
this->columnOneText = columnOneText;
}
void stock::setItemDescription(std::string columnTwoText) {
this->columnTwoText = columnTwoText;
}
int main(){
vector<stock> itemDetails;
string line;
string columnOneText;
string columnTwoText;
ifstream readFile("info.txt");
while(getline(readFile,line)) {
stringstream iss(line);
getline(iss, columnOneText,',');
getline(iss, columnTwoText, ',');
//consturctor
stock splitedColumns(columnOneText,
columnTwoText
);
itemDetails.push_back(splitedColumns);
}
readFile.close();
cout << "this is column One in text file" << endl;
for (int i =0; i<itemDetails.size(); i++) {
cout << itemDetails[i].getColumnOne() << " " << endl;
}
cout << "this is column Two in text file" << endl;
for (int i =0; i<itemDetails.size(); i++) {
cout << itemDetails[i].getColumnTwo() << " " << endl;
}
}
what I don't really know is how to extract the details using arrays instead of using vectors.
I have tried this but it doesn't seem to work
string line;
string columnOneText;
string columnTwoText;
string columnOneTextArray[7];
while(getline(readFile,line)) {
stringstream iss(line);
getline(iss, columnOneText,',');
getline(iss, columnTwoText, ',');
for(int i=0; i<8; i++) {
columnOneTextArray[i] = columnOneText;
cout << columnOneTextArray[i];
}
}
You guys might ask why do I want to do it in arrays instead of using vector,
I just curious and exploring how it can be done using arrays.
You problem can be solved in a lot simpler manner by using struct definitions in addition to using vectors (your use of classes is a bit of overkill, IMHO):
#include <fstream>
#include <iostream>
#include <cstdlib>
#include <vector>
#include <sstream>
//this utilizes a more idiomatic naming convention as opposed to `columnX`
typedef struct Stock {
int id;
std::string games;
int amount;
} Stock;
//Syntactic sugar for easier output
std::ostream& operator << (std::ostream& in, const Stock& stock) {
in << stock.id << " " << stock.games << " " << stock.amount;
return in;
}
int main() {
std::string filename = "info.txt";
std::fstream ifile;
std::vector <Stock> inventory;
Stock stock_t;//a temporary Stock variable
std::string temp;
ifile.open(filename.c_str(), std::ios::in);
if (!ifile.is_open()) {
std::cerr << "There was a problem opening the input file: \"" << filename << "\"\n";
exit(1);
}
while (ifile >> temp) {
std::istringstream iss(temp);
int column = 0;
//break each constituent line by using the comment as a delimiter:
while(std::getline(iss, temp, ',')) {
if (column == 0) {
stock_t.id = std::atoi(temp.c_str());
}
else if (column == 1) {
stock_t.games = temp;
}
else if (column == 2) {
stock_t.amount = std::atoi(temp.c_str());
}
++column;
}
inventory.push_back(stock_t);
}
for (int i = 0; i < inventory.size(); ++i) {
std::cout << inventory[i] << "\n";
}
ifile.close();
return 0;
}
Which outputs:
1 left4dead 50
2 warcraft3 60

C++ read/write to binary file. on program exit it gives System.AccessViolationException

This C++ program is created using Visual Studio 2010. It's a group project that has everyone in class stumped.
The program initially starts fine and the user can run through the program and add items that are written out to file. the items are read back in and displayed. When the user is done, on the program exiting return 0; it gives me "An unhandled exception of type System.AccessViolationException occurred. Attempted to read or write protected memory. This is often an indication that other memory is corrupt."
When this happens it opens up a file called utility here => for (_Iterator_base12 **_Pnext = &_Myproxy->_Myfirstiter; *_Pnext != 0; *_Pnext = (*_Pnext)->_Mynextiter) (*_Pnext)->_Myproxy = 0.
I can fix this by replacing return 0; with exit(0);
I know it's not a real fix though and just a band-aid over a bullet hole that is causing this issue.
After fixing (used very loosely here) that, then running the program again, it attempts to load the data file from the file system. It reads and loads the 1st item into a vector correctly but when it goes back to the start of the loop we see the same exception pop up, An unhandled exception of type System.AccessViolationException occurred.
This is the first project we have worked on using fstream and binary i/o. We had worked through a similar program that was just reading and writing strings w/out any issues.I believe that the issue stems from something in the fileHandler class but am having a difficult time pinpointing what is causing this issue.Any advice/help is greatly appreciated.Here is the code.stdafx.h
// stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently, but
// are changed infrequently
//
#pragma once
#include <stdio.h>
#include <iostream>
#include <stdlib.h>
#include <sstream>
#include <fstream>
#include <string.h>
#include <string>
#include <vector>
#include <time.h>
Week2.cpp (the main file for the project)
//Week2.cpp *******************
#include "stdafx.h"
#include "fileHandler.h"
using namespace std;
using namespace System;
int main(array<System::String ^> ^args)
{
fileHandler theFile("store.pkl");
vector<item> itemStack = theFile.getFile();
cout << "SKU Name Dept Vendor Max Order onHand" << endl;
cout << "-------------------------------------------" << endl;
for (int i = 0; i < itemStack.size(); i++)
{
cout << itemStack[i].toString() << endl;
}
vector<item> newStack;
//prompt for input
bool doneEditing = false;
while(!doneEditing)
{
int A;
int E;
int F;
int G;
string B;
string C;
string D;
string tempString;
cout << "Enter item info:" << endl << "Item SKU: ";
cin >> A;
cout << endl << "Item Name: ";
cin >> B;
cout << endl << "Item Dept: ";
cin >> C;
cout << endl << "Vendor Name: ";
cin >> D;
cout << endl << "Max Number: ";
cin >> E;
cout << endl << "Reorder Number: ";
cin >> F;
cout << endl << "OnHand Number: ";
cin >> G;
cout << endl << "Done?? Y/N: ";
cin >> tempString;
cout << endl;
item tempItem = item(A, B, C, D, E, F, G);
newStack.push_back(tempItem);
if (tempString == "Y" || tempString == "y")
{
doneEditing = true;
}
}
cout << "Saving stack to file" << endl;
theFile.putFile(newStack);
cout << "Items written to file" << endl;
vector<item> newFileStack = theFile.getFile();
cout << "After reload: " << endl;
cout << "SKU Name Dept Vendor Max Order onHand" << endl;
cout << "-------------------------------------------" << endl;
for (int i = 0; i < newFileStack.size(); i++)
{
cout << newFileStack[i].toString() << endl;
}
cout << "Thank you for using the Awesome Grocery Inventory Application" << endl;
system("PAUSE");
/*return 0; this breaks with same error as
when reading in saved file after application restart
*/
exit(0);
}
item.h
using namespace std;
#pragma once
class item
{
public:
item();
item(int sku, string name, string dept, string vendor, int max, int reorder, int onhand);
~item(void);
string toString();
int ItemSKU() const;
void ItemSKU(int val);
string ItemName() const;
void ItemName(string val);
string VendorName() const;
void VendorName(string val);
int MaxNumb() const;
void MaxNumb(int val);
int ReorderNumb() const;
void ReorderNumb(int val);
int OnHandNumb() const;
void OnHandNumb(int val);
private:
int itemSKU;
string itemName;
string itemDept;
string vendorName;
int maxNumb;
int reorderNumb;
int onHandNumb;
};
item.cpp
#include "StdAfx.h"
#include "item.h"
using namespace std;
item::item()
{
};
item::item(int sku, string name, string dept, string vendor, int max, int reorder, int onhand)
{
itemSKU = sku;
itemName = name;
itemDept = dept;
vendorName = vendor;
maxNumb = max;
reorderNumb = reorder;
onHandNumb = onhand;
}
item::~item(void)
{
}
string item::toString()
{
stringstream ss;
ss << itemSKU << "\t" << itemName << "\t" << itemDept << "\t" << vendorName << "\t" << maxNumb << "\t" << reorderNumb << "\t" << onHandNumb;
string s = ss.str();
return s;
}
int item::ItemSKU() const { return itemSKU; }
void item::ItemSKU(int val) { itemSKU = val; }
string item::ItemName() const { return itemName; }
void item::ItemName(string val) { itemName = val; }
string item::VendorName() const { return vendorName; }
void item::VendorName(string val) { vendorName = val; }
int item::MaxNumb() const { return maxNumb; }
void item::MaxNumb(int val) { maxNumb = val; }
int item::ReorderNumb() const { return reorderNumb; }
void item::ReorderNumb(int val) { reorderNumb = val; }
int item::OnHandNumb() const { return onHandNumb; }
void item::OnHandNumb(int val) { onHandNumb = val; }
fileHandler.h
#include "item.h"
using namespace std;
#pragma once
class fileHandler
{
public:
fileHandler(string);
~fileHandler(void);
vector<item> getFile();
void putFile(vector<item> &);
private:
string theFileName;
};
fileHandler.cpp
#include "stdafx.h"
#include "fileHandler.h"
using namespace std;
fileHandler::fileHandler(string name)
{
theFileName = name.c_str();
}
fileHandler::~fileHandler(void)
{
}
vector<item> fileHandler::getFile()
{
ifstream inFile;
string fileLine;
vector<item> localStack;
inFile.open(theFileName, ios::in|ios::binary);
if (inFile)
{
cout << "Getting file..." << endl;
cout << endl;
// not working on initial load if file is present at start
inFile.seekg(0);
while(!inFile.eof())
{
item tempItem;
inFile.read(reinterpret_cast< char * >(&tempItem), sizeof(item));
localStack.push_back(tempItem);
cout << "item added to stack" << endl;
} //breaks from here after reading in 1 item from saved file on reopen
} else {
ofstream newFile;
newFile.open(theFileName, ios::out|ios::binary);
newFile.close();
cout << "Creating new file..." << endl;
cout << endl;
inFile.open(theFileName, ios::in|ios::binary);
}
inFile.clear();
inFile.close();
if (localStack.size() > 0)
{
//removes some dirty data from end of stack
localStack.pop_back();
}
return localStack;
}
void fileHandler::putFile( vector<item> &items )
{
ofstream outFile;
outFile.open(theFileName, ios::out|ios::binary);
if(!outFile)
{
cerr<<"File could not be created"<<endl;
system("pause");
exit(1);
}
for (int i = 0; i < items.size(); i++)
{
outFile.write(reinterpret_cast<const char *>(&items[i]), sizeof(item));
}
outFile.clear();
outFile.close();
}
You cannot perform binary I/O this way with an object that contains std::string members. A std::string contains pointer(s) to dynamically allocated memory for its actual contents. You need to perform some type of serialization instead. The usual suggestion is Boost serialization.