fstream isnt reading from a text file after two lines - c++

im struggling with this part of code , no matter what i try i cant get it to read into a record after two lines
the text file contains
Mickey Mouse
12121
Goofy
24680
Andy Capp
01928
Quasi Modo
00041
end
and the code is
#include<iostream>
#include<string.h>
#include <stdio.h>
#include <windows.h>
#include<iomanip>
#include<conio.h>
#include<fstream>
#include<string>
using namespace std;
struct record
{
char name[20];
int number;
};
void main()
{
record credentials[30];
int row=0;
fstream textfile;//fstream variable
textfile.open("credentials.txt",ios::in);
textfile.getline (credentials[row].name,30);
//begin reading from test file, untill it reads end
while(0!=strcmp(credentials[row].name,"end"))
{
textfile>>credentials[row].number;
row++;
//read next name ....if its "end" loop will stop
textfile.getline (credentials[row].name,30);
}
textfile.close();
}
the record is only taking the first two lines and the rest is empty
any ideas ??

The problem is that:
textfile>>credentials[row].number;
while not consume the newline character. The subsequent call to textfile.getline() reads a blank line and the next:
textfile>>credentials[row].number;
attempts to read "Goofy" into an int which fails and set the failbit of the textfile stream meaning all further attempts to read fail. Check the return value to detect failure:
if (textfile >> credentials[row].number)
{
// Success.
}
I am not entirely sure how the program ends as "end" will never be read but I suspect it ends abnormally as there is no mechanism to prevent overruning the end of the credentials array (i.e no row < 30 as part of the loop terminating condition).
Other:
Instead of using a fixed sized char[] to read the names into you can use std::getline():
#include <string>
struct record
{
std::string name;
int number;
};
if (std::getline(textfile, credentials[row].name))
{
}
Instead of using a fixed sized record[] you could use a std::vector<record> which will grow as required.

Related

why reading one character from the file using char variable eating one more next character?

In the following program i am inputting data form file,
file contains : 1st line: answer key, subsequent line contains students ID and their answer response.
in the program i am comparing answer key and student response key and calculating grade and marks.
after reading id i need to discard space after the id, for that i need to read one character but while reading one character from the file with char variable it is reading space but also eating away next character so i am left with 9 char length student answer key, but it should be 10 char long.
and the while loop inside int main() which contain display function should run only one time because i have only one record in the file, but it is running 2 times.
what is wrong in this?
#include<iostream>
#include<string>
#include<fstream>
#include<iomanip>
using namespace std;
class student{
string ans,usn;
int marks,tot;
char grade;
public:
void input(string key,fstream &fp){
char ch;
marks=tot=0;
grade='z';
fp>>usn>>ch;
getline(fp,ans);
string::iterator it1,it2;
for(it1=key.begin(),it2=ans.begin()+1;it1!=key.end();++it1,++it2){
tot+=2;
if(*it1==*it2)
marks+=2;
else if(*it1!=*it2&&*it2!=' ');
//marks-=1;
}
grade=marks<0?'z':(75-(marks*10/tot));
}
void display(){
cout<<left<<setw(20)<<usn<<setw(20)<<ans<<setw(10)<<marks<<setw(10)<<grade<<ans.length()<<" "<<tot<<endl;
}
};
int main(){
student s;
string key;
char ch;
fstream fp("file.txt");
if(!fp){
cout<<"\nError in opening file"<<endl;
exit(0);
}
getline(fp,key);
cout<<left<<"key:"<<key<<endl<<setw(20)<<"usn"<<setw(20)<<"Answer key"<<setw(10)<<"marks"<<setw(10)<<"grade"<<endl<<setfill('-')<<setw(60)<<"-"<<setfill(' ')<<endl;
while(!fp.eof()){
s.input(key,fp);
s.display();
}
fp.close();
return 0;
}
file:
TTTTTTTTTT
1rv16is089 FTTTTTTTTT
output:
key:TTTTTTTTTT
usn Answer key marks grade
------------------------------------------------------------
1rv16is089 TTTTTTTTT 16 C 9 20
1rv16is089 TTTTTTTTT 16 C 9 20
Unless you have specifically asked the stream not to (noskipws) all the operator>> in the standard library will automatically skip all leading whitespace before starting to read its input.
So your fp >> ch will first skip all spaces and then read one more character.
There is a special manipulator std::ws that can be used to eat whitespace but not anyhting else. Just do fp >> std::ws;.
However, you also have a few other issues. When mixing >> and std::getline you might consider this, which probably is the base problem you tried to solve:
Why does std::getline() skip input after a formatted extraction?
And your problem with main() seeming to read one record too many is explained here:
Why is iostream::eof inside a loop condition considered wrong?

C++ program doesn't completely read huge input. Why?

I want to solve a programming contest task (C++ with XCode) which has a relatively big input (300 lines). When copying a test input into the console, it doesn't read it all.
So I have written a minimalistic test program to simply read in 300 lines:
#include <iostream>
using namespace std;
int main(int argc, const char * argv[])
{
ios_base::sync_with_stdio(false);
string xxx;
for(int i = 0; i < 300; i++)
cin >> xxx;
return 0;
}
If I execute it and copy 340 lines with "aaaaaaaaaa" into the console, it doesn't end. If I stop it with the debugger, it says i = 92. If I then continue, it quits.
But when I copy pieces of 50 lines into the console, it quits immeadiately as it should...
Can anyone help me with this?
PS: I inserted the 'ios_base::sync_with_stdio(false);', because I read that this would spped the input up.
I want to solve a programming contest task (C++ with XCode) which has a relatively big input (300 lines). When copying a test input into the console, it doesn't read it all
This is possible when you have more than one word per line because cin >> xx will read words as opposed to lines.
You would need to use the getline method to actually read lines.
while (getline(cin, xxx));
If I execute it and copy 340 lines with "aaaaaaaaaa" into the console, it doesn't end. If I stop it with the debugger, it says i = 92.
Yes, this is exactly the same symptom. Even if you had one word per line, you would reach only 300 lines, never 340.
Here is the whole code I would write for your reference:
#include <iostream>
using namespace std;
int main(int argc, const char * argv[])
{
ios_base::sync_with_stdio(false);
string xxx;
while (getline(cin, xxx))
cout << xxx << endl;
return 0;
}
cin >> string inputs words, not lines. Try:
string xxx;
while (getline(cin, xxx)) {
;
}
to input a full line at a time into xxx.
I couldn't solve the problem with X-Code but it works with Qt. So I use Qt now.

fstream write/read to a binary file doesn't work as expected.!

#include <iostream>
#include <string.h>
#include <fstream>
#include <conio.h>
using namespace std;
int main(int argc, char*argv[])
{
ifstream fpr;
ofstream fpw;
char * rec1 = "helloWorld";
char * rec2 = "my";
char out1[50];
char out2[50];
fpw.open("sample.txt",ios::in|ios::binary|ios::app);
if(fpw.fail())
{
cout<<"The file could not be opened!\n";
exit(1); // 0 – normal exit, non zero – some error
}
fpr.open("sample.txt",ios::out|ios::binary);
if(fpr.fail())
{
cout<<"The file could not be opened!\n";
exit(1); // 0 – normal exit, non zero – some error
}
fpw.write(rec1,10);
fpr.read(out1,10);
out1[10] = '\0';
cout<<out1<<"\n";
fpw.seekp(2,ios::beg);
fpw.write(rec2,2);
fpr.seekg(0,ios::beg);
fpr.read(out2,strlen(rec1));
cout<<"\n"<<out2<<"\n";
getch();
}
With this code I just want to insert a string named 'my' to the 2byte location of 'helloworld' string. But it doesn't insert it(even though I'm seeking to the correct location). Could anyone help me out?
from documentation on ios::mode
ios::app:
the content to the current content of the file. This flag can only be
used in streams open for output-only operations.All output operations are performed at the
end of the file, appending
Remove the ios::app, and you will be able to write "my" over "ll" in `"helloworld".
Note that you won't be able to "insert" something into a file - the only way to achieve that is to read from the original file and write the new data to a new file [or read whatever is after you want to modify, insert the text you want, and write back the parts you want after the modified bit].

breaking down an input sentence

in the code i am working on, the input will be of this form: abcd = insert(15MB). What i need to do is insert 15MB into the identifier 'abcd'. Here is the code i have.
#include <iostream>
#include <algorithm>
#include <string>
#include <iomanip>
#include <limits>
#include <stdio.h>
using namespace std;
string extract(string pMem);
double toByte(int phyMem, string val);
string pMem, comment, sGen, val,foo;
int gen, phyMem, i=0, oBrckt=0, cBrckt=0;
double pmemSize =0;
int main()
{
getline(cin,foo);
if((foo.find("insert"))!= string::npos)
cout<<"Found insert"<<endl;
cin.clear();
}
The problem: I am unable to find the code word insert from the input command. I am guessing the problem is because the word insert(15MB) is considered as a whole. Is there any way to break it down so that i can save abcd into the identifier "tag", and 50MB into the identifier "Memory"?
You may use scanf, which is faster than cin and also provides the functionality you want:
char t[256], m[256];
scanf("%s = insert(%[^)]);", t, m);
string tag = t, Memory = m;
This basically means: read a string, then skip " = insert(", then read the inner string until you find a ')', then skip the final ");".
Just make sure you are reading from the correct input.
If you really want to read the input with getline, you can still use sscanf to achieve the same, on top of your foo string:
sscanf(foo.c_str(), "%s = insert(%[^)]);", t, m);
Note the extra 's' in sscanf is not a typo here. t and m are just temporary char buffers to store your content, you can assign it directly to a string afterwards if you wish. Please note the code above assumes the 'tag' and 'Memory' contents will not be longer than 255 characters each.

Initializing array of objects with data from text file

I’m getting system error when I try to compile the code below on Visual C++ 2008 Express. What I’m trying to do is to initialize array of objects with data read from file. I think there is something wrong inside the while loop, because when I initialize these objects manually without the while loop it seems to work. Here is the code and text file:
#include <iostream>
#include <string>
#include "Book.h"
using namespace std;
int main()
{
const int arraySize = 3;
int indexOfArray = 0;
Book bookList[arraySize];
double tempPrice;//temporary stores price
string tempStr;//temporary stores author, title
fstream fileIn( "books.txt" );
while ( !fileIn.eof( ))
{
getline(fileIn,tempStr);
bookList[indexOfArray].setAuthor(tempStr);
getline(fileIn,tempStr);
bookList[indexOfArray].setTitle(tempStr);
fileIn >> tempPrice;
bookList[indexOfArray].setPrice(tempPrice);
if ( indexOfArray < arraySize ) //shifting array index while not exceeding array size
indexOfArray++;
}
fileIn.close();
return 0;
}
and the text file:
Author1
Book1
23.99
Author2
Book2
10.99
Autho3
Book3
14.56
It looks like you are trying to write to bookList[3] in the loop. You will loop through three times filling your array incrementing indexOfArray each time. This will leave indexOfArray at 3 -- your condition as it is written will allow indexOfAray to be incremented to 3. Then if you have a newline after the "14.56" in your data file you will loop one more time and attempt to pass an empty string to bookList[indexOfArray].setAuthor() leading to a segfault since indexOfArray is past the end of the array.
I would suggest ditching the hard-coded array and using a std::vector instead. At the start of each loop just use push_back() to add a new book to the end of the vector and then use back() to access the new element in the array.
There's another run-time error in your code: You don't read an entire line with the call to fileIn >> tempPrice;. The next call to getline() will read to the end of the line, so you'll get an empty string when you're expecting an author.
You're then off by one line in your text file, and you try to convert a title into a double. That make the fstream signal an error, and after that, you're in trouble.
Brett's right, a vector with push_back is a better solution here.
Brett also correctly pointed out that you could run into errors if your file has extra lines. You can fix that by checking if you successfully read from the file:
if(fileIn >> tempPrice)
{
bookList[indexOfArray].setPrice(tempPrice);
}
else
{
break;
}
if(!getline(fileIn,tempStr))
{
break;
}
The key must be in the contents of
#include "Book.h"
I copy-pasted your code, and replaced the #include with my assumption of what class Book might look like:
class Book
{
std::string auth;
std::string title;
double price;
public:
void setAuthor(std::string& str)
{
auth = str;
}
void setTitle(std::string& t)
{
title = t;
}
void setPrice(double d)
{
d = price;
}
};
and it compiled. Perhaps you could share your Book.h, or look there for any problems? Start with some simple definition from Book (like above) and begin readding code until you've found the lines that cause the problem. Its a crude method of figuring out the issue, but sometimes its the most direct way.