Reading from file C++ - c++

I need to read this txt file but I don't understand what I'm doing wrong?
http://pastebin.com/gPVbuvhb Here's my reading function
void Read(School & snew){
string school, name, group;
Student S;
ifstream fd(CD);
getline(fd, school, ';');
S.SetSchool(school);
cout << S.GetSchool() << endl;
while(!fd.eof()){
getline(fd, name, ',');
fd >> ws;
getline(fd, group, ' ');
int Paz[Student::M];
int kiek = 0;
while(fd.peek()!= '\n' && !fd.eof()){
fd >> Paz[kiek++];
}
fd.ignore();
}
fd.close();
}
Here's my Student class
class Student{
public:
static const int M = 5;
private:
string school, name, group;
int *Marks; // dynamic array of student marks
int nmax; // max size of array
int n; // current size of array
void IncreaseCapasity(int kiek);
public:
Student(int nmax = 0);
~Student();
void SetMarks(int mark);
void SetSchool(string school);
void SetName(string name);
void SetGroup(string group);
int GetMark(int i){return Marks[i];}
string GetSchool(){return school;}
string GetName(){return name;}
string GetGroup(){return group;}
int GetN(){return n;}
};
Student::Student(int nmax):Marks(NULL), n(n), nmax(nmax){
if(nmax > 0){
Marks = new int[nmax];
}
}
Student::~Student(){
if(Marks){
delete [] Marks;
Marks = NULL;
}
}
void Student::IncreaseCapasity(int kiek){ // maybe this function is incorrect?
if(kiek > nmax){ // if array increasing
int *SNew = new int [kiek];
for(int i=0; i<n; i++)
SNew[i] = Marks[i];
delete [] Marks;
Marks = SNew;
nmax = kiek;
}if(kiek < nmax){ // if array decreasing
int *SNew = new int [kiek];
for(int i=0; i<kiek; i++)
SNew[i] = Marks[i];
delete [] Marks;
Marks = SNew;
n = nmax = kiek;
}
}
void Student::SetMarks(int mark){
if(n == nmax) IncreaseCapasity(n + M);
Marks[n] = mark;
n++;
}
void Student::SetSchool(string school){
this->school = school;
}
void Student::SetName(string name){
this->name = name;
}
void Student::SetGroup(string group){
this->group = group;
}
when I'm reading int values fd >> Paz[kiek++]; I get this error
Unhandled exception at 0x571121F8 (msvcp110d.dll) in ConsoleApplication1.exe: 0xC0000005: Access violation reading location 0x0000000D.

getline(fd, school, ';');
reads from the fd stream, stopping at first occurence of ';'. Since there is no ';' in your file, it reads whole file into school string.
What you actually want to do is to parse your file line by line, constructing instance of istringstream using each line:
std::string line;
while (std::getline(fd, line)) {
if (line.empty())
continue;
std::istringstream is(line);
std::string name, group;
if (std::getline(is, name, ',') && std::getline(is, group, ',')) {
std::cout << "Name: " << name << " Group: " << group << std::endl;
}
}
just don't forget to #include <sstream>.
Also note that:
while (!fd.eof()) {
std::getline(...);
// relying on getline call being successful here
}
is not safe, just use its return value directly.

Related

How to read file into class in C++?

I am reading File that contains
Boss, level, Specials,
"FireMen", 3, "Flame,Thrower", Fire,Breath
"Medusa", 6, "Snake,Poison"
"Hype", 10, "One,punch,Knock", Fly,Kick, "Dragon,Breath"
I am trying to read it into class with objects boss, level and specials
I am having problem reading from file since I split each by words by comma but it read specials like Flame,Thrower as separate due to comma in between them. How can I combine specials rather then splitting by commas so that it read Flame Thrower rather then Flame and thrower separately.
Also some specials are in quotation others are not.
I have been stuck at reading this rather complicated file. If anyone has time to read through my code and fix 10s of errors that I am getting would greatly be appreciated, Thank You
(What I did doesn't make much sense since this is my one month into C++ so still newbie and progressing)
#include <iostream>
#include <string>
#include <vector>
#include <fstream>
#include <iomanip>
#include "Boss.h"
using namespace std;
vector <Boss*> Info;
Boss* parseLine(string str)
{
vector<string> store;
string smt = " ";
Boss* values = nullptr;
if (smt != "")
{
(store.push_back(smt));
}
for (int i = 0; i < (int)str.size(); i++)
{
char ch = str[i];
if (ch != ',')
{
smt = smt + ch;
}
else
{
store.push_back(smt);
smt = "";
}
}
values = new Boss(store[0], stoi(store[1]), store[2]);
Name = store[0];
Level = store[1];
Specials = store[2];
return values;
}
bool readFile()
{
std::ifstream myFile("Bosses.txt");
if (!myFile.is_open())
{
cout << "fAILED" << "\n";
return false;
}
string str;
int i = 0;
while (std::getline(myFile, str))
{
cout << str << endl;
if (str[0] != '/')
{
Boss* Boss = parseLine(str);
result.push_back(Boss);
}
}
return true;
}
int main()
{
std::cout << "Read file\n;";
bool data = readFile();
for (Boss* t : result)
{
delete t;
}
And Class
#include <string>
#include <vector>
class Boss {
std::string Name;
int Level;
std::vector<std::string> Specials;
Boss(std::string Name, int Level, std::vector<std::string> Specials);
~Boss();
Boss(Boss& b);
void setName(std::string Name);
void setLevel(int Level);
};
Boss::Boss(std::string Name, int Level, std::vector<std::string> Specials)
{
this->Name= Name;
this->Level = Level;
this->Specials = Specials;
}
Boss::~Boss() {}
Boss::Boss(Boss& b)
{
Name = b.Name;
Level = b.Level;
Specials = b.Specials;
}
void Boss::setName(std::string Name) {
this->Name = Name;
}
void Boss::setLevel(int Level)
{
this->Level = Level;
}
This code reads your file and stores the data in the std::vector Info using stringstreams and other things to parse.
#include <iostream>
#include <string>
#include <vector>
#include <fstream>
#include <iomanip>
#include <sstream>
using namespace std;
class Boss {
std::string Name;
int Level;
std::vector<std::string> Specials;
public:
Boss(std::string n, int l, std::vector<std::string> s)
{
this->Name = n;
this->Level = l;
this->Specials = s;
};
~Boss() {};
Boss(const Boss& b) {
this->Name = b.Name;
this->Level = b.Level;
this->Specials = b.Specials;
};
Boss() {};
Boss operator= (Boss b) {
this->Name = b.Name;
this->Level = b.Level;
this->Specials = b.Specials;
return b;
}
void setName(std::string n) { Name = n; };
void setLevel(int l) { Level = l; };
void setSpecials(std::vector<std::string> s) {Specials = s;}
std::string getName() const { return Name; }
int getLevel() const { return Level; }
std::vector<std::string> getSpecials() const { return Specials; }
};
vector <Boss> Info;
Boss parseLine(string str)
{
vector<string> store;
string smt;
stringstream evaluator;
Boss value;
evaluator << str; //put our string into evaluator
{
char double_quote_remover;
evaluator >> double_quote_remover; //remove the first double quote
getline(evaluator, smt, '"'); //get the name until the next double quote
char comma_remover;
evaluator >> comma_remover; //remove the comma
}
value.setName(smt); //put smt into the Boss's name
{
int Level;
evaluator >> Level; //get an int from our string
value.setLevel(Level); //put our int into our Boss
}
char curr;
while (evaluator >> curr && curr != ','); //get the comma after the int
smt = ""; //reset
curr = ' '; //reset
while (evaluator >> curr) { //while we read chars into curr
if (isalpha(curr)) { evaluator.putback(curr); curr = ','; } //if the char is a letter, put it back
if (curr == '\"') getline(evaluator,smt,'\"'); //if the char is a double quote, read until we reach another
else if (curr == ',') getline(evaluator,smt,','); //if the char is a comma, read until we get another
if (smt != "") //if the string is not null, put it in store
store.push_back(smt);
smt = ""; //reset
}
value.setSpecials(store); //put store into our Boss
return value; //return our boss
}
bool readFile()
{
std::ifstream myFile("Bosses.txt");
if (!myFile.is_open())
{
cout << "FAILED" << "\n";
return false;
}
string str;
getline(myFile, str); //for the first line, which we don't need
int i = 0;
while (std::getline(myFile, str))
{
Boss Boss = parseLine(str);
Info.push_back(Boss);
}
return true;
}
int main()
{
bool data = readFile();
}
This should work. I have tested it thouroughly. Inform me of any errors.
Note: There was no need for pointers that were in your original code.

Why do I get a segmentation fault when fetching this variable?

I am pulling names as strings from a file, create a Person *p object, and put it into an array.
Then to search the array for a name but when I try to fetch the name I get a segmentation fault.
Why is this segmentation fault happening, and what can I do to fix it?
#include <iostream>
#include <string>
using namespace std;
class Person {
private:
string firstName;
string lastName;
string phoneNumber;
public:
Person();
Person(string f, string l, string n);
~Person(void);
void setName()
{
}
string getFirstName()
{
return firstName;
}
string getLastName()
{
return lastName;
}
string getNumber() { return phoneNumber; }
void print();
};
Array creation.
{
ifstream file;
file.open("phonebook.txt");
if (!file.is_open()) //Check for File Error.
{
cerr << "Failed to open file" << endl;
exit(1);
}
//Get Array Size
string line;
while (getline(file, line))
{
count++;
}
file.close();
//Create an array
Person *arrList[count];
buildArray(arrList, count);
if (uInput == "a" || uInput == "A") //To add
{
int x = addPerson();
if (x == 1)
{
count++;
}
delete[] arrList;
}
void buildArray(Person *arr[], int size)
{
string f, l, n;
ifstream file;
file.open("phonebook.txt");
for (int i = 0; i < size; i++)
{
file >> f >> l >> n;
Person *p = new Person(f, l, n);
arr[i] = p;
delete p;
}
}
The search, This is the part that has the trouble. I have tried a few different things including creating 2 Persons, and comparing their parts but whenever it goes into the .h it can not return the name.
if (uInput == "s" || uInput == "S")
{ //To Search
string f, l;
cout << "Find Who (Firstname Lastname) " << endl;
cin >> f >> l;
Person *n = new Person(f, l, "");
int i = 0;
bool found = false;
while (i <= count && found == false)
{
Person *p = new Person("", "", "");
p = arrList[i];
if (p->getFirstName() == n->getFirstName() && p->getLastName() == n->getLastName())
{
arrList[i]->print();
found = true;
delete p;
delete n;
}
i++;
}
while (i == count && found == false)
{
cout << "No results found. " << endl;
found = true;
}
}

Have problem with dynamic array of structures program

Having trouble compiling program. Should read input from text file and store into a dynamic array of structure. I'm prettty sure my problem lies in the ipod_Initialize function. I'm not sure how to pass the dynamic array structure through the function.
#include <iostream>
#include <string>
#include <fstream>
# include <ctime>
using namespace std;
struct Song
{
string title;
string artist;
float size{};
};
int song_Count(string);
void ipod_Initialize(string, int, Song);
void show_playlist();
int main(char *argv[]) {
// argv is filename
int count = song_Count(argv[1]);
Song* songInfo = new Song[count];
ipod_Initialize(argv[1], count, *songInfo);
cout << songInfo[0].title;
delete[] songInfo;
return 0;
}
int song_Count(string fileName){
ifstream inFile;
string data;
int count = 0;
inFile.open(fileName);
if (!inFile.is_open()){
cout << "Error opening file" << endl;
return 0;
}
while(!inFile.eof()){
getline(inFile, data);
if (!data.empty()){
count++;
}
}
inFile.close();
count = count / 3 + 1;
return count;
}
void ipod_Initialize(string fileName, int count, Song* songInfo) {
string data;
ifstream inFile;
inFile.open(fileName);
for (int i = 0; i <= count; i++) {
getline(inFile, data);
if (!data.empty())
songInfo[i].title = data;
getline(inFile, data);
if (!data.empty())
songInfo[i].artist = data;
//getline(inFile, mem);
if (!data.empty())
inFile >> songInfo[i].size;
}
}

Program crashes due to undefined behavior

So I'm writing a program that creates a library for a collection of CDs and displays them. My program compiles but crashes whenever I write an array of pointers to songs from a file into structs contained within an array shown here:
//Get song array
for (int a = 0; a < num_songs; a++)
{
getline (infile, line);
sub = line.c_str();
word = createString(sub);
length = substr(word, -1, 5);
title = substr(word, 5, strlen(sub));
cd->song_array[a] = createSong(title,length);
destroyString(word);
}
I think it's due to undefined behavior, here's the .cpp file that this is happening in.
#include <iostream>
#include "CDs.h"
#include "CD.h"
#include <fstream>
#include <string>
#include <cstring>
using namespace std;
//Creates a collection of CDs
CDs* createCDs(const char* file_name)
{
//Declare variables and allocate memory
int max_cds = 50;
CDs* collection = new CDs;
collection->max_cds = max_cds;
CD** cd_array = new CD*[max_cds];
int num;
int sentinel = 0;
String* word;
string line;
CD* cd;
const char* sub;
String* length;
String* title;
//Open .txt file
ifstream infile;
infile.open(file_name);
if (infile.is_open())
{
while (infile.good())
{
for (int i = 0; i < max_cds; i++)
{
//Get the artist from .txt file
cd = cd_array[i];
getline (infile, line);
sub = line.c_str();
word = createString(sub); //Create string from infile line
cd->artist = word;
destroyString(word);
//Get the Title of the album from file
getline (infile, line);
sub = line.c_str();
word = createString(sub);
cd->title = word;
destroyString(word);
//Get the Year of the album from file
infile >> num;
cd->year = num;
//Get the Rating
infile >> num;
cd->rating = num;
//Get number of tracks
int num_songs;
infile >> cd->num_tracks;
//Get song array
for (int a = 0; a < num_songs; a++)
{
getline (infile, line);
sub = line.c_str();
word = createString(sub);
cout << "SHIT" << endl;
length = substr(word, -1, 5);
title = substr(word, 5, strlen(sub));
cd->song_array[a] = createSong(title,length);
destroyString(word);
}
cd_array[i] = cd;
sentinel++;
}
}
}
else
{
cout << "file did not open";
}
collection->cd_array = cd_array;
collection->num_cds = sentinel;
collection->max_cds = max_cds;
return collection;
}
I have no idea what to do to make this run, If someone could help that would be amazing.
edit - I didn't give the .cpp that is included and has some of the functions used
#include <iostream>
#include <cstring>
#include "String.h"
using namespace std;
//Function that creates a string
String* createString(const char* char_array)
{
//Allocate memory for a pointer to String struct
//String* string;
String* string = new String;
//Write the char_array to String struct
int length = strlen(char_array);
char array[30];
for (int i = 0; i <= length; i++)
{
array[i] = char_array[i];
string->array[i] = array[i];
}
return string;
}
//Function that displays the string
void displayString(String* str)
{
for (int i = 0; i < strlen(str->array); i++)
{
cout << str->array[i];
}
cout << endl;
}
//Function that destroys the string
void destroyString(String* str)
{
delete str;
str = NULL;
}
int find(String* str, char delimiter, int start)
{
for (int i = start; i <= strlen(str->array); i++)
{
if (str->array[i] == delimiter)
{
return i;
}
}
cout << "No occurences of delimiter were found" << endl;
return -1;
}
String* substr(String* str, int start, int end)
{
String* new_str = new String;
int count = 0;
for (int i = start + 1; i < end - 1; i++)
{
new_str->array[count] = str->array[i];
count++;
}
return new_str;
}
void compare(String* str1, String* str2)
{
if (str1->array < str2->array)
{
cout << str1->array << " is less than " << str2->array << endl;
}
if (str1 > str2)
{
cout << str2->array <<" is less than " << str1->array << endl;
}
if (str1 == str2)
{
cout << "The strings are equal" << endl;
}
}
You never allocate memory for the effective CD. You just allocate an array of pointers to CDs (cd_array). This means you have an array of pointers, pointing to unkown memory locations.
The best way to ensure no such bad access is possible, is to not dynamically allocate memory. Just use CD cd_array[max_cds] and work with that. (Use call by reference, if you need to pass this to a function.)
You need to add the following lines:
//Get the artist from .txt file
cd_array[i] = new CD;
cd = cd_array[i];
.....
You should de-allocate the memory once finished using them
for(...)
delete cd_array[i];
delete []cd_array;

Alternative to strcmp() to alphabetically sort strings

stuType Class:
#include<iostream>
#include<cstring>
using namespace std;
#ifndef STUTYPE
#define STUTYPE
class stuType {
private:
string fname;
string lname;
string social;
float gpa;
public:
stuType(void) {
fname = "no_fname";
lname = "no_lname";
social = "no_social";
gpa = 0.0;
}
stuType(string fname_in, string lname_in, string social_in, float gpa_in) {
fname = fname_in;
lname = lname_in;
social = social_in;
gpa = gpa_in;
}
~stuType() {
//Nothing needs to be added here.
}
void set_fname(string new_fname) {
fname = new_fname;
}
void set_lname(string new_lname) {
lname = new_lname;
}
void set_ssn(string new_ssn) {
social = new_ssn;
}
void set_gpa(float new_gpa) {
gpa = new_gpa;
}
string get_fname(void) {
return fname;
}
string get_lname(void) {
return lname;
}
string get_ssn(void) {
return social;
}
float get_gpa(void) {
return gpa;
}
friend istream & operator>>(istream &in, stuType &stu) {
in>>stu.fname;
in>>stu.lname;
in>>stu.social;
in>>stu.gpa;
return in;
}
};
#endif
Sort.cpp:
#include<iostream>
#include<fstream>
#include<cstdlib>
#include<cstring>
#include"stuType.h"
using namespace std;
/*Loads the elements of the object instance with data from the input file.*/
void load(istream &input, stuType Student[], int *size);
/*Used in combination with the shellSort method to exchange the values of two variables in the class object.*/
void exchange(stuType &a, stuType &b);
/*Sorts the objects in ascending order by comparing the values of the lname strings between object indices.*/
void shellSort(stuType Student[], int size);
int main() {
stuType Student[10];
int size;
char inputFile[200];
char outputFile[200];
ifstream input;
ofstream output;
cout<<"[INPUT_FILE]: ";
cin>>inputFile;
cout<<"[OUTPUT_FILE]: ";
cin>>outputFile;
input.open(inputFile);
output.open(outputFile);
if (input.fail()) {
cerr<<"\n[FILE] Error opening '"<<inputFile<<"'"<<endl;
exit(1);
}
if (output.fail()) {
cerr<<"\n[FILE] Error opening '"<<outputFile<<"'"<<endl;
exit(1);
}
load(input, Student, &size);
shellSort(Student, size);
return 0;
}
void load(istream &input, stuType Student[], int *size) {
int length = 0, i = 0;
float gpa;
string social;
string fname;
string lname;
while(input >> social >> fname >> lname >> gpa) {
cout<<"[Node::Load] Setting 'social' for index ["<<i<<"] to "<<social<<endl;
Student[i].set_ssn(social);
cout<<"[Node::Load] Setting 'fname' for index ["<<i<<"] to "<<fname<<endl;
Student[i].set_fname(fname);
cout<<"[Node::Load] Setting 'lname' for index ["<<i<<"] to "<<lname<<endl;
Student[i].set_lname(lname);
cout<<"[Node::Load] Setting 'gpa' for index ["<<i<<"] to "<<gpa<<endl;
Student[i].set_gpa(gpa);
cout<<"[Node::Load] Incrementing 'length'..."<<endl;
length++;
cout<<"[Node::Load] Incrementing 'i'..."<<endl;
i++;
}
cout<<"==================================="<<endl;
for (int i = 0; i<length; i++) {
cout<<"[ENTRY] Index: "<<i<<" | SSN: "<<Student[i].get_ssn()<<" | fname: "<<Student[i].get_fname()<<" | lname: "<<Student[i].get_lname()<<" | gpa: "<<Student[i].get_gpa()<<endl;
}
cout<<"==================================="<<endl;
*size = length;
}
void exchange(stuType &a, stuType &b) {
stuType *temp;
*temp = a;
a = b;
b = *temp;
delete temp;
}
void shellSort(stuType Student[], int size) {
int gap = size/2;
bool passOK;
while(gap>0) {
passOK = true;
for(int i = 0; i<size-gap; i++) {
if (strcmp(Student[i].get_lname(), Student[i+gap].get_lname)>0) {
cout<<"[Node::Sort] Exchanging Index ["<<i<<"] with Index ["<<i+gap<<"]..."<<endl;
exchange(Student[i], Student[i+gap]);
passOK = false;
} else if (strcmp(Student[i].get_lname(), Student[i+gap].get_lname())==0) {
if (strcmp(Student[i].get_fname(), Student[i+gap].get_fname())>0) {
cout<<"[Node::Sort] Exchanging Index ["<<i<<"] with Index ["<<i+gap<<"]..."<<endl;
exchange(Student[i], Student[i+gap]);
passOK = false;
}
}
}
if (passOK) {
gap /= 2;
}
}
}
strcmp() expects to receive a character array to do the comparison, but since I am using strings, I cannot do that. What is an alternative? The variable 'lname' needs to be compared and should return true if Student[i].get_lname() is greater than Student[i+gap].get_lname(). The exchange function will then be called and exchange the values of the object's local variables. The objects should be sorted in ascending order based on the value of the 'lname' variable and the 'fname' variable should only be referenced if the two 'lname's being compared are the same.
C++ strings provide implementations of operators < and >, so you can use them instead of strcmp:
std::string a = "hello";
std::string b = "world";
if (a < b) {
cout << a << " is less than " << b << endl;
}