Reading file into object array C++ - c++

I have to read from a data file which is formatted like this
abcd(string) 1(int) 2(int) 3(int)
abcde(string) 4(int) 3(int) 2(int)
.
.
.
I want to perform some functions which use the variables in the same line only. But here's my code. I'm a beginner so please correct me thank you.
in the .h file
#include <string>
using namespace std;
#ifndef CALC_H
#define CALC_H
class Calc
{
public:
void readFile(string file);
private:
string name;
int a;
int b;
int c;
};
#endif
in the implementation file
#include "Vehicle.h"
#include iostream>
#include fstream>
#include string>
#include cstdlib>
#include cmath>
using namespace std;
void Vehicle::readFile(string filename)
{
ifstream myIn;
int totalNum=0;
myIn.open(filename.c_str());
if (!myIn)
{
cerr<<"Data file failed to open!\n";
exit (0);
}
for (int i=0; i<MAX; i++)
{
while (myIn.peek() != EOF)
{
myIn>>calc[i].name;
myIn>>calc[i].a;
myIn>>calc[i].b;
myIn>>calc[i].c;
totalNum++;
}
}
myIN.close();
and then I want to display what i just read from the file
for (int i = 0; i < MAX; i++)
cout << calc[i].name << calc[i].a << calc[i].b << calc[i].c << endl;
sorry I left out alot of stuff I just want to know if I on the right path. Thanks

The proper way to do this is to overload the >> operator for your class Calc.
class Calc {
public:
friend istream& operator >>(istream& myIn, Calc& calc);
};
istream& operator >>(istream& myIn, Calc& calc) {
myIn >> calc.name;
myIn >> calc.a;
myIn >> calc.b;
myIn >> calc.c;
return myIn;
}
Now you can just do:
while (myIn >> calc[i]) {
++totalNum;
}

You should consider designing it a bit differently.
create a class that holds one line i.e. string int int int - like you have it in "Calc" but without making it dependent on how you create a line (readfile). Lets call it "Line"
class Line
{
public:
std::string name;
int a;
int b;
int c;
};
Now since you need to read several lines you will need some kind of container to hold them, create a vector of Line (or some other container)
std::vector<Line> contents;
then override the stream operator as Tushar suggested so when you read from a file (or from e.g. stdin) you can create instances of Line for each line you read, these instances you use to fill the 'contents' array
now you can start doing whatever it is you want to do with the lines i.e. the actual operation calc

Related

Reading in input to construct an object

I am trying to read a string line for line down a .txt file in order to initiate an array of objects using a constructor that takes a string.
The text file is written like
TransAm
Mustang
Corvette
I feel like my loop is not iterating the information I want to be set correctly. Is there an easy way of accomplishing this?
main.cc
#include <string>
#include <iostream>
#include "Car.cc"
#include <fstream>
using namespace std;
int main()
{
Car cars[3];
string STRING;
ifstream infile;
infile.open("cars.txt");
// THIS IS HOW IT'S ACHIEVED USING FOR-LOOP - Sam
for(int i = 0; i<3 && infile;++i){
getline(infile,STRING);
cars[i].setName(STRING);
}
/* THIS IS WHAT I HAD
while(!infile)
{
getline(infile,STRING);
for(int i = 0; i<sizeof(cars);i++){
cars[i].setName(STRING);
}
}
*/
infile.close();
for(int j = 0;j<sizeof(cars);j++){
cars[j].print();
}
}
Car.h
#include <string>
using namespace std;
class Car{
public:
Car();
Car(string);
string getName();
void setName(string);
void print();
private:
string name;
};
Car.cc
#include <string>
#include "Car.h"
using namespace std;
Car::Car()
{
}
Car::Car(string s)
{
setName(s);
}
void Car::setName(string s)
{
name = s;
}
string Car::getName()
{
return name;
}
void Car::print()
{
cout << name;
}
These points need to be corrected:
while (!infile) prevents you from entering the loop.
You don't need two loops.
You can modify your loop like this:
for (int i = 0; i < sizeof(cars) && getline(infile, STRING); ++i)
cars[i].setName(STRING);
Or like this:
for (int i = 0; i < sizeof(cars) && infile; ++i) {
getline(infile, STRING);
cars[i].setName(STRING);
}
Your loop does at the moment nothing if the file is correctly opened. It will only enter if the call to open was unsuccessful.
Change your loop to either
while (getline(infile,STRING))
{
//...
}
or
while (infile)
{
//...
}
As it's been said, "Change while(!infile) to while(getline(infile,STRING))" but do not forget to remove the getline(infile,STRING); afterwards.

How to read a separate line from textfile for different objects?

I have two rectangles objects which I'm trying to read different lines in a textfile with readcood() however when I run this I get the same line from the text file.
#include<iostream>
#include<fstream>
using namespace std;
class rect{
int xcood[3],ycood[3],x1,x2,x3,x4,y1,y2,y3,y4;
public:
void readcood()
{
char dummy;
ifstream myfile;
myfile.open("coordinates.txt");
for(int i=0;i<4;i++)
{
myfile>>xcood[i]>>dummy>>ycood[i];
}
}
void printcood()
{
for(int i=0;i<4;i++)
{
cout<<xcood[i]<<"\t"<<ycood[i]<<endl;
}
}
};
int main()
{
char dummy;
string coordinates;
rect rectangle1,rectangle2;
rectangle1.readcood();
rectangle2.readcood();
rectangle1.printcood();
rectangle2.printcood();
}
It's because you open the file in the function. When the function returns the file-stream object will be destructed and all you've done will be lost.
You could open it in the main function and pass it (by reference) to the read function.
Another solution is to add an open function to your rect class, that opens the file, and have the file stream being a member of the class.
However the solution I would recommend is to make your own overloaded input function, that takes a rect object and reads into that. Something like
class rect
{
public:
...
friend std::istream& operator>>(std::istream& is, rect& r)
{
char dummy;
for (int i = 0; i < 3; ++i)
is >> r.xcood[i] >> dummy >> r.ycood[i];
return is;
}
...
};
Then you can simply do e.g.
std::ifstream file("some/path/file");
rect r1, r2;
file >> r1 >> r2;

Inputting a file into a structure

I am trying to read the lines from a file called 'weapon.txt' and input them into a structure something a long the lines of this
struct weapon
{
char name[20]; //Edited
int strength;
}
The file to be read looks like this:
Excalibur
150
Throwing Stars
15
Rapier
200
Bow and Arrow
100
Axe
200
Crossbow
100
Scimitar
250
Rusted Sword
10
Soul Slayer
500
The code I have right now is
#include<fstream>
#include<iostream>
#include<cstring>
using namespace std;
struct WeaponInfo
{
char name[16];
int strength;
};
const int MaxWeap = 10;
void openfile(ifstream&); //Opening the file
void displayfile(ifstream&, WeaponInfo&);//Display file
int main ()
{
WeaponInfo weapon[MaxWeap];
ifstream fin;
openfile(fin);
displayfile(fin, weapon[MaxWeap]);
}
void openfile(ifstream& fin)
{
fin.open("weapon.txt");
}
void displayfile(ifstream& fin, WeaponInfo& weapon[MaxWeap])
{
char nm;
int str;
while (fin.eof() == 0)
{
for(int i = 0; i <= MaxWeap; i++);
{
fin.getline(nm);
fin.getline(str);
strcpy(weapon[i].name, nm);
strcpy(weapon[i].strength, str);
i++;
cout << weapon[i].name << "\n" << weapon[i].strength << endl;
}
}
fin.close();
}
EDIT: This is what I have right now after re-doing it, I am getting compile errors of : declaration of 'weapon' as array of references; In function 'void displayfile(...) 'fin' was not declared in this scope; 'weapon' is not declared in this scope; ma,e lookup of 'i' changed for ISO 'for' scoping [-fpermissive].
I'd firstly tend to use std::string rather than char arrays - they're just easier to work with. So the structure noww looks like this:
struct weapon
{
string name;
int strength;
};
Next you need something that will read the structure from an input stream:
bool getWeapon( ifstream& is, weapon& w )
{
getline(is, w.name) ;
string strengthStr;
getline(is, strengthStr) ;
w.strength = strtol( strengthStr.c_str(), NULL, 0 );
return !is.eof();
}
Two things here, I've used strtol as a conversion function from string to int. atoi is used but strtol gives you slightly more flexibility and crucially, better error cchecking, alkthough I've not bothered to implement it here. A stringstream might have been another alternative here.
Secondly, I return a boolean indicating whether the name was empty. The reason for this is that when, later in the code, I check for eof() on the ifstream, it isn't actually set until you read past the end of the file. So the last good read will not set it but the first attempt to reead past it will. Returning false here then will indicate to the caller that the 'get' failed due to the ifstream being at end of file.
Lastly, we need something to read all of the weappons in:
ifstream input;
input.open("weapons.txt");
vector<weapon> ws;
if ( input )
{
while (! (input.eof()))
{
weapon w;
if ( ! getWeapon( input, w ) )
break;
ws.push_back( w );
}
}
input.close();
This wwill place all the weapons into a vector. Note the call to getWeapon breaks if it failed to prrevent adding on an 'empty' weapon. Not the most glamorous solution but it should work.
Pseudo-code goes something like this, (and like Martol1ni has coded for you):
open the file
while (!end-of file)
{
create instance of struct weapon
read a line and strcpy into weapon.name
read a line and set weapon.strength = atoi(line)
do something with the instance, eg. add to list, call a member function, etc.
}
loop
close file.
Assuming you control the weapons.txt, don't bother checking for errors in the file, you can do this. Next time, do a little research... :)
#include <fstream>
#include <vector>
#include <string>
#include <iostream>
#include <cstdlib>
using namespace std;
struct weapon
{
string name;
int strength;
weapon(string n, int s) : name(n), strength(s) {}
};
void readFileToVec(vector<weapon> &myVec) {
ifstream in("weapon.txt");
while (!in.eof()) {
string name;
getline(in,name);
string strength;
getline(in,strength);
weapon myWep(name,atoi(strength.c_str()));
myVec.push_back(myWep);
}
in.close();
}

Reading from text files C++

I have a text file containing three columns of numbers; one column each for the x,y,z coordinates of a bunch of points. All numbers are between 0 and 1.
I have created the following structure:
typedef struct
{
double xcd, ycd, zcd;
} point;
I want to create a size-N array of structures of type point. Then I want to scan the text file line by line and for the nth particle, I want to put in the three numbers on the nth line into the respective xcd, ycd and zcd positions.
Tell me if there is some efficeint way of going about this.
Simply do it like has been shown five million billion kajillion times before, using ifstream, vector and various other accouterments.
ifstream infile("myfile.txt");
// check if file opened successfully
if (!infile) {
cerr << "failure, can't open file" << endl;
cin.get();
return EXIT_FAILURE;
}
// the container in which we will store all the points
vector<point> points;
// a temporary point to hold the three coords in while we read them all
point tmp;
// read in three doubles from infile into the three coords in tmp
while (infile >> tmp.xcd && infile >> tmp.ycd && infile >> tmp.zcd)
// add a copy of tmp to points
points.push_back(tmp);
This will read in three doubles and put them in a point then put a copy of that point in points. However, if the number of numbers in the file modulus 3 is not 0, it will stop and not add the incomplete point to points.
Use a std::fstream.
If you're sure that the file is correct:
struct Point {
double xcd, ycd, zcd;
};
// btw this is how you should declare a structure in C++,
// the way you shown is rather characteristic to C and only used there
Point tab[N];
void foo() {
std::ifstream f("file.txt");
for (int i=0; i<N; ++i) {
f >> tab[i].xcd >> tab[i].ycd >> tab[i].zcd;
}
}
If you're not sure that the file will exist and contain exactly this number of particles, you should check for f.fail() after each a read attempt.
I prefer using the standard generic algorithms to writing my own loops:
#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
#include <fstream>
typedef struct
{
double xcd, ycd, zcd;
} point;
std::istream& operator>>(std::istream&is, point& pt)
{
return is >> pt.xcd >> pt.ycd >> pt.zcd;
}
int main(int ac, char **av) {
std::ifstream f("file.txt");
std::vector<point> v;
std::copy(
std::istream_iterator<point>(f),
std::istream_iterator<point>(),
std::back_inserter(v));
}
Another design is to overload the stream extraction operator in your point structure:
struct Point
{
double x;
double y;
double z;
friend istream& operator>>(istream& inp, Point& p);
}
istream& operator>>(istream& inp, Point& p)
{
inp >> x;
inp >> y;
inp >> z;
inp.ignore(100000, '\n');
return inp;
}
Usage:
ifstream myfile("data.txt");
Point p;
vector<Point> point_container;
while (myfile >> p)
{
point_container.push_back(p);
}

spaces are not printing when reads the input file

I am trying to read each 'char' of the input file and write in the output file until finds the '?' as the end of file . Every char is written in output file except the spaces between words. I dont know what's wrong in this code??
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
ifstream infile("in.txt");
ofstream outfile("out.txt");
char ch;
infile >> ch;
while(ch != '?')
{
outfile<<ch;
infile >> ch;
}
}
Try using noskipws on read...
infile >> noskipws >> ch;
The noskipws tells the input stream to not skip whitespace which it does by default.
istream operator >> ignores whitespace. Try this:
std::string s;
std::getline(infile,s,'?');
outfile << s;
The >> operator for input streams is generally associated with interpretation. For example, when reading strings it skips spaces. This may be the case when reading chars.
You ought to use the read method, for example:
infile.read(&ch, 1)
See http://www.cplusplus.com/reference/iostream/ifstream/ for reference
edit I forgot about the get method. That'll get you a single character, cast as an int. The read method is more geared for reading a chunk of data in one call.
#Andrew White has already pointed out how to fix the problem you've seen. I'll toss in my idea (typically for me, probably over-engineered) idea of how to do the rest of the job:
#pragma once
#if !defined(SENTINEL_ITERATOR_H_)
#define SENTINEL_ITERATOR_H_
#include <istream>
#include <iterator>
template <class T,
class charT=char,
class traits=std::char_traits<charT>,
class distance = ptrdiff_t>
class sentinel_iterator :
public std::iterator<std::input_iterator_tag,distance,void,void,void>
{
std::basic_istream<charT,traits> *is;
T value;
public:
typedef charT char_type;
typedef traits traits_type;
typedef std::basic_istream<charT,traits> istream_type;
sentinel_iterator(istream_type& s)
: is(&s)
{ s >> value; }
sentinel_iterator(T const &s) : is(0), value(s) { }
const T &operator*() const { return value; }
const T *operator->() const { return &value; }
sentinel_iterator &operator++() {
(*is)>>value;
return *this;
}
sentinel_iterator &operator++(int) {
sentinel_iterator tmp = *this;
(*is)>>value;
return (tmp);
}
bool operator==(sentinel_iterator<T,charT,traits,distance> const &x) {
return value == x.value;
}
bool operator!=(sentinel_iterator<T,charT,traits,distance> const &x) {
return !(value == x.value);
}
};
#endif
Then the code becomes something like this:
#include <algorithm>
#include <fstream>
#include "sentinel_iterator.h"
int main() {
ifstream infile("in.txt");
ofstream outfile("out.txt");
infile >> noskipws;
std::copy(sentinel_iterator<char>(infile),
sentinel_iterator<char>('?'),
std::ostream_iterator<char>(outfile));
return 0;
}