The following code is supposed to read records from input and store them in a file called file.dat. Then it is supposed to arrange these records in ascending order, but for some reason the program hangs in the second while loop at line "file1.seekg(-(sizeof(r)),std::ios::cur);". Can someone please tell me what's wrong?
#include <iostream>
#include <fstream>
#include <strstream>
int main()
{
std::ofstream file;
file.open("file.dat",std::ios::trunc|std::ios::binary);
if(!file)
std::cout<<"unable to open for output";
struct record
{
char code[6];
char name[20];
int i;
};
record r;
int a = 0;
while(1)
{
std::cout<<"Record " << a + 1 << std::endl;
std::cout<<"Enter character code, name and an int \n";
std::cin.ignore();
std::cin.getline(r.code,6);
std::cin.getline(r.name,20);
std::cin>>r.i;
file.write((char *)&r,sizeof(r));
std::cout<<"\nAdd another (y\\n) : ";
char c;
std::cin>>c;
if(c == 'n')
break;
a++;
std::cout<<'\n'<<'\n';
}
file.close();
std::fstream file1("file.dat",std::ios::in|std::ios::out|std::ios::binary);
if(!file1)
std::cout<<"unable to open file1";
else
{
if(a>0)
{ while(a)
{
file1.seekp(0);
for(int i = a; i>0;i--)
{
record r1;
file1.read((char *)&r,sizeof(r));
file1.read((char *)&r1,sizeof(r1));
if(r1.i < r.i)
{
file1.seekp(-(sizeof(r)*2),std::ios::cur);
file1.write((char *)&r1,sizeof(r));
file1.write((char *)&r,sizeof(r));
file1.seekg(-(sizeof(r)),std::ios::cur);
}
}
a--;
}
}
file1.close();
}
std::ifstream file2("file.dat",std::ios::binary);
if(!file2)
std::cout<<"unable to open file2";
else
while(1)
{
std::cout<<"\n\n";
file2.read((char *)&r,sizeof(r));
if(file2.eof())
break;
std::cout<<r.code<<'\t'<<r.name<<'\t'<<r.i;
}
}
first
change std::get.ignore -> std::cin.ignore()
if you want to discard one character.
it compiled well and created file.dat file..
you might check the record inside file.dat though
If you are trying to ignore the new line character entered after the actual dat, then you have to use:
std::cin.ignore();
If you want more reference on use of ignore go to this LINK
Related
I have two files. main.cpp:
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
ifstream file;
file.open("file.txt");
if (!file.good()) {
cout << "Error." << endl;
return 1;
}
int n;
while (!file.eof()) {
file.clear();
file >> n;
if (!file.good() && !file.bad()) {
continue;
} else {
cout << "Hardware error." << endl;
break;
}
cout << n << endl;
}
file.close();
return 0;
}
and file.txt:
a 1 2 321b9 ac.de ef##g 5 #3
I'd like to read only integers from this file and write them out to the console. When file contains only integers program works well but when it contains any invalid characters then I get infinite loop. How can I fix that?
The loop is because the stream doesn't extract the character that is not an integer. You need to extract it before attempting to read another integer.
A small tweak could be all that is needed;
// on a failed read...
file.clear();
char dummy;
file >> dummy;
continue;
A side note on the use of while (!file.eof()); it is generally not recommended to do this. There are several Q&A on SO on this issue.
Im sorry about posting a super long code, but when I run this code all I see is this-
Heap size: 1638652
Getting int:
Getting int:
Getting int:
Getting int:
Getting int:
Heap size: 1638653
and it keeps going in a loop with the heapsize being incremented by one.
#include <iostream>
#include <fstream>
#include <algorithm>
#include <vector>
#include <exception>
#ifndef WX_REPORT_H
#define WX_REPORT_H
#include <string>
#include <sstream>
using std::string;
using std::stringstream;
typedef struct WX_REPORT
{
string unitType;
string stationName;
string time;
string gpsLoc;
int pressure;
int windSpeed;
int temperature;
int humidity;
int windDirection;
string toString()
{
stringstream str;
str << stationName << ": " << time << "\t" << gpsLoc << "\n";
str << pressure << "\n" << windSpeed << "\n" << temperature << "\n";
str << humidity << "\n" << windDirection;
return str.str();
}
}
WXReport;
#endif
/*
* Reports must be in the following format:
* M or I // Metric or imperial units
*/
using namespace std;
vector<WXReport*> heap;
bool compTime(const WXReport* a, const WXReport* b) {
if(a->time < b->time) { // timing
return false;
} else {
return true; // commands to return true
}
}
void heapAdd(WXReport* wx) {
heap.push_back(wx);
push_heap(heap.begin(), heap.end());
}
WXReport* heapPop() { // header popup
pop_heap(heap.begin(), heap.end());
WXReport* rep = heap.back();
heap.pop_back();
return rep;
}
void getInt(istream &input, int &i) {
string temp;
input>>temp;
cout<<"Getting int: "<<temp<<endl;
i = atoi(temp.c_str());
}
void readInFile(string filename) {
ifstream input(filename);
WXReport *report;
while(!input.eof()) {
report = new WXReport();
getline(input, report->unitType);
getline(input, report->stationName);
getline(input, report->time);
getline(input, report->gpsLoc);
getInt(input, report->pressure);
getInt(input, report->windSpeed);
getInt(input, report->temperature);
getInt(input, report->humidity);
getInt(input, report->windDirection);
heapAdd(report);
cout<<"Heap size: "<<heap.size()<<endl;
}
}
int menu() {
cout<<"\n\nPlease select one: "<<endl;
cout<<"1) Read in another file"<<endl;
cout<<"2) Display the fastest wind speed"<<endl;
cout<<"3) Display weather stations by name"<<endl;
cout<<"4) Display all weather reports"<<endl;
cout<<"5) Remove a weather report"<<endl;
cout<<"6) Write weather reports to file"<<endl;
cout<<"0) Exit"<<endl;
int choice;
cin>>choice;
return choice;
}
void printAllReports() {
cout<<"Printing all reports"<<endl;
for(WXReport* rep: heap) {
cout<<rep->toString()<<endl;
}
cout<<"Done printing reports"<<endl;
}
int main(int argc, char* argv[]) {
string filename = "report.txt";
readInFile(filename);
int choice = menu();
while(choice != 0) {
switch(choice) {
case 1:
cout<<"What file would you like to read in?"<<endl;
cin>>filename;
readInFile(filename);
break;
case 2:
cout<<"Has not been implemented"<<endl;
break;
case 3:
cout<<"Has not been implemented"<<endl;
break;
case 4:
printAllReports();
break;
case 5:
cout<<"Has not been implemented"<<endl;
break;
case 6:
cout<<"Has not been implemented"<<endl;
break;
default:
cout<<"Invalid choice, please try again."<<endl;
}
choice = menu();
}
cout<<"Thank you!"<<endl;
return 0;
}
Important part. If you read nothing else, read this: Always check the error codes and return values.
After ifstream input(filename); you have no idea if the file opened. Testing with input.is_open() gets past that.
If the file isn't open, all those calls to getline fail as does eof(). File not open, can't read end of file and can't exit loop. Even if the the file is open, if you don't check the output of getline, how do you know you read a line?
One of the fun parts of streams is if you test the stream, it tells you if it is in a bad state, so you can write code that looks like
if (getline(...) && getline(...) && ...)
So you don't have to make a massive block of if-else-if or a sea of nested ifs. First bad read and you are out.
The problem with if eof() is covered in the comments to the question. The basic is you don't know if you got the end of the file until you start reading. Also, what happen if you hit the end of the file in the middle of a bunch of reads?
So read a line. If it's good, read the next line, etc... until done.
getInt isn't necessary.
int val;
input >> val;
loads an integer into val, if the stream can be parsed into an int. If it can't, input is marked bad and you can check why. Could be unparsable. Could be end of file.
int val;
if (input >> val)
{
//do stuff
}
else
{
//no int here. Do other stuff
}
Just like above, you can chain the instructions and get
if (input >> val >> anotherval >> ...)
I have my prototypes in a header file, but I need some help. I am having some trouble getting the program to compile all the way through. It appears to be getting caught in a loop with the input. Possibly some issues with the functions. Thanks in advance for any input.
#include <iostream>
#include <conio.h>
#include "header.h"
#include <fstream>
class Caesar
{
public: void readText(char *input);
void encrypt(char *input,char *output,char *key);
void decrypt(char *input,char *output,char *key);
};
void main()
{
Caesar a;
char key[1000];
ifstream fin;
int choice;
char input[100],output[100];
cout<<"\n Enter input file: ";
cin>>input;
cout << input;
cout<<"\n Enter output file: ";
cin>>output;
cout <<output;
cout<<"\n Enter key: ";
cin>>key;
cout <<key;
cout<<"\n\n 1. Encrypt\n 2. Decrypt\n\n Select choice(1 or 2): "<< endl;
cin >> choice;
cout << choice;
a.readText(input);
if(choice==1)
{
a.encrypt(input,output,key);
}
if(choice==2)
{
a.decrypt(input,output,key);
}
else
{
cout<<"\n\n Unknown choice";
}
}
void Caesar::readText(char *input)
{
ifstream reader;
char buf;
reader.open(input);
cout<<"\n\n <--- "<<input<<" --->\n";
buf=reader.get();
while(!reader.eof())
{
cout<<buf;
buf=reader.get();
}
reader.close();
}
void Caesar::encrypt(char *input,char *output,char *key)
{
ifstream reader;
ofstream writer;
char buf;
reader.open(input);
writer.open(output);
buf=reader.get();
while(!reader.eof())
{
if(buf>='a'&&buf<='z')
{
buf-='a';
buf+=key[buf];
buf%=26;
buf+='A';
}
writer.put(buf);
buf=reader.get();
}
reader.close();
writer.close();
readText(input);
readText(output);
}
void Caesar::decrypt(char *input,char *output,char *key)
{
ifstream reader;
ofstream writer;
char buf;
reader.open(input);
writer.open(output);
buf=reader.get();
while(!reader.eof())
{
if(buf>='A'&&buf<='Z')
{
buf-='A';
buf+=26-key[buf];
buf%=26;
buf+='a';
}
writer.put(buf);
buf=reader.get();
}
reader.close();
writer.close();
readText(input);
readText(output);
}
if(choice=1)
should be
if(choice==1)
and also in the other if
In your case, you are assigning the value 1 to choice, then test if choice is true, and it is, since any non-zero numeral type is implicitly casted to bool true.
I have just executed your code and tried debugging it and took a screen shot
you program gets into a loop after entering the choice.there is no problem with cin>>.
From your comments, it seems like you're just trying to debug main. Everything seems to work fine. What are you inputting for key? If it's a very large integer, that may be your problem as it might exceed the maximum integer range and cause overflow.
Your key is an integer variable. You are inputting a string for the file name that holds your key, so that should be changed to a C string array. Change all of the passed key parameters to char* instead of int.
You have an infinite loop when the readText() function is called.
Maybe try this:
void Caesar::readText(char *input)
{
ifstream reader(input);
if(reader.is_open())
{
char buf;
cout<<"\n\n <--- "<<input<<" --->\n";
while(reader.get(buf))
{
cout << buf;
}
}
reader.close();
}
Make sure that your text file is in the same folder as your code. See this for more details: ifstream not opening file
sorry for having to ask such a trivial question here, but I have to admit I can't think the reason that's causing my program to behave this way.
Here's the problem;
I'm trying to read from a file which has 32 lines with each line containing a 32-bit long binary number.
I've got a string array of size 32 and I'm trying to store each number from the file in it. It seems straight forward to me but then when I get to the line that tests getline() it jumps to the else bit and ouputs my error message. Initially it was working fine on eclipse but not from the terminal, I thought it had something to do with the permissions so I changed them all to rwx to no avail. I even tried changing the name but that caused the program to not work even in eclipse and now even going back to the original name doesn't work !!
I would appreciate if anyone can shed a light on the problem for me.
Ta!
Edit: Thank you guys for helping me investigate the problem, so far the file seems to be read just fine, I've got a cout statement in my main function to print the second element of the vector in which data is stored (after being read from the file) and it prints fine, in eclipse that is!! .When I compile the same code from the terminal and then run a.out it simply doesn't output anything.
I decided I would include my entire code and hope this will be more helpful.
Here's a quick recap to the questions I was asked:
-The file is just a simple text file that contains lines of 1's and 0's here's what it looks like
00000000000000000000000000000000
11100000000000100000000000000000
00010000000000010000000000000000
10010000000001100000000000000000
10010000000000100000000000000000
10010000000001100000000000000000
00000000000001110000000000000000
10000000001000000000000000000000
10110110010000000000000000000000
00000000000000000000000000000000
I've got a cpp file with it's corresponding header like this:
#ifndef MANCHESTER_H_
#define MANCHESTER_H_
#include <string>
#include <iostream>
#include <fstream>
#include <cmath>
#include <vector>
using namespace std;
class Manchester {
private:
struct Processor
{
enum operation { JMP,JRP,LDN,STO,SUB,CMP,STP };
char accumulator[32]; // holds results of arithmetic operations.
char controlInstruction[32]; // program counter.holds the address of an instruction.
char presentInstruction[32]; //contains the actual instruction fetched and being executed.
};
Processor processor;
public:
vector<string> store;
int static const size = 32;
Manchester();
~Manchester();
void copyFromFileToStore();
string decToBinary(int );
int binToDecimal(string s);
string getInstruction(int lineNumber);
string getOperand(int lineNumber);
};
#endif /* MANCHESTER_H_ */
Here's the .cpp file
#include "Manchester.h"
Manchester::Manchester()
{
copyFromFileToStore(); // load the program in the store.
}
Manchester::~Manchester() {}
void Manchester::copyFromFileToStore()
{
ifstream myfile;
myfile.open("BabyTest1-MC.txt");
if (!myfile.is_open())
{
cout << "Cannot read file!" << endl;
}
else
{
int i =0;
while( i < 10)
{
string line;
if (getline(myfile,line))
{
store.push_back(line);
i++;
}
else
{
cout << "Error while reading file!" << endl; // always outputs when running the code.
return;
}
}
myfile.close();
}
}
string Manchester::decToBinary(int number)
{
string converted="";
char holder;
do
{
holder = number % 2 + '0';
converted = holder + converted;
number = number /2;
}while (number != 0);
string filler = "";
int stringsize = converted.size();
int diff = (8 - stringsize);
if (diff > 0)
{
for (int i = 0; i < diff; i++)
filler = filler + '0';
}
converted = filler + converted;
return converted;
}
int Manchester::binToDecimal(string s)
{
int converted =0;
int power = 0;
for (int i = s.size()-1; i >= 0; --i)
{
converted += (s[i] - '0') * pow(2, power);
power++;
}
return converted;
}
And finally the file containing the main():
#include "Manchester.h"
int main()
{
Manchester baby;
cout << baby.store.at(1);
return 0;
}
These the original parts that I posted that I didn't want to delete:
string store[32];
ifstream myfile;
myfile.open("BabyTest1-MC.txt");
if (!myfile.is_open())
{
cout << "Cannot read file!" << endl;
}
else
{
int i =0;
while( i < 32)
{
if (getline(myfile,store[i]))
{
i++;
}
else
{
cout << "Error while reading file!" << endl; // always outputs when running the code.
return;
}
}
myfile.close();
}
Sorry I'm editing to show you what works on eclipse but not from the terminal!!!
I simply don't understand the behaviour !!!
string store[32];
ifstream myfile;
myfile.open("BabyTest1-MC.txt");
if (!myfile.is_open())
{
cout << "Cannot read file!" << endl;
}
else
{
int i =0;
while( i < 32)
{
getline(myfile,store[i]);
i++;
}
myfile.close();
}
Why don't you use a std::vector<std::string>, and push_back() to populate it?
std::vector<std::string> store;
// ...
while(i < 32) {
std::string line;
if (getline(myfile,line)) {
store.push_back(line);
i++;
}
// ...
}
What about:
string store[32];
ifstream myfile;
int i;
myfile.open("filename.txt");
if (!myfile.is_open())
{
cout << "Cannot read file!" << endl;
}
else
{
for (i = 0; i < 32; i++)
{
if (!getline(myfile, store[i]))
{
cout << "Error while reading file!" << endl; // always outputs when running the code.
return 0;
}
}
myfile.close();
}
Tested it and it was working for me.
This way the for loop automatically increment you variable and if for some strange reason the program reaches the end of the file, it will display your error message.
I got some help from one of the guys at university and we figured what the problem was !!
It was to do with the endline characters. I'm working on linux which uses \n as the endline character but the file I'm trying to read was built on Windows which of course has \r\n as the endline character! Eclipse seems to be accepting both versions of end of line but not bash!
I edited my code to get rid of those characters altogether before storing them in the vector and it now works fine.
Sorry for the trouble caused in here and hope this will at least remind beginners that there is a difference between files built on windows, mac and linux !! and that attention needs to be made when working with different files !!
void Manchester::copyFromFileToStore()
{
ifstream myfile;
myfile.open("BabyTest1-MC.txt");
if (!myfile.is_open())
{
cout << "Cannot read file!" << endl;
}
else
{
int i =0;
string line;
while(getline(myfile,line))
{
line.erase(std::remove(line.begin(), line.end(), '\r'), line.end());
line.erase(std::remove(line.begin(), line.end(), '\n'), line.end());
store.push_back(line);
i++;
}
myfile.close();
}
}
I'm writing, reading and deleting the content of a file. Eeverything works fine except the delete part, as when I press y it says deleted but doesn't display any records.
typedef struct ch
{
char str[10];
};
void disp(ch d)
{
cout<<"\n"<<d.str<<"\n";
}
//delete part
cout<<"\nwant to delete??";
char c;
cin>>c;
if(c=='y')
{
char s[10];
cout<<"nter - ";
cin>>s;
file.seekg(0);
int found=0;
fstream temp("temp.dat",ios::in|ios::out|ios::app);
while(file.read((char *)&dta,sizeof(dta)))
{
if(strcmp(dta.str,s)==0)
{
found=1;
cout<<"deleted";
}
else
temp.write((char *)&dta,sizeof(dta));
}
if(!found)
cout<<"not found";
remove("new.dat");
rename("temp.dat","new.dat");
temp.close();
file.open("new.dat",ios::in|ios::out|ios::app);
}
EDIT: Looking over your code again, I see the problem is that you are using the ios::app although you have also passed ios::in.
ios::app -- All output operations are performed at the end of the file, appending
the content to the current content of the file. This flag can only be
used in streams open for output-only operations.
http://www.cplusplus.com/doc/tutorial/files/
Old Post:
Take a look at the following code example:
#include <iostream>
#include <fstream>
#include <cstdio>
#include <cstring>
using namespace std;
const char g_szTestData[] = "This is some test da$$$$######ta and some more"
" tes$$$$######ting";
int main(int argc, char** argv)
{
fstream file("new.dat", ios::in|ios::out);
file << g_szTestData << flush;
cout << "Do you want to delete all $$$$######?";
if (cin.get() == 'y')
{
char szBuffer[10]; //< File read buffer
char szString[11] = "$$$$######"; //< 10 characters + '\0'
bool bFound = false;
fstream temp("temp.dat", ios::out);
file.seekg(0, file.beg);
while (file.read(szBuffer, sizeof(szBuffer)))
{
if (strncmp(szBuffer,szString,10) == 0) bFound = true;
else temp.write(szBuffer, sizeof(szBuffer));
}
temp.flush();
temp.close();
if (bFound)
{
file.close();
remove("new.dat");
rename("temp.dat", "new.dat");
file.open("new.dat",ios::in|ios::out);
}
else cout << "Pattern Not Found!" << endl;
}
/* Do something with the contents of file. */
// Lets clean up at the end
file.close();
return 0;
}
In this example, a file is created and the contents g_szTestData are added, you can verify this by opening the file (before pressing 'y').
The user is then asked if they would like to delete a string of 10 characters $$$$###### from the file. If the user wishes to proceed, a new file is opened temp.dat. The program gradually walks through the existing new.dat file (10 characters at a time). If the string the program reads from new.dat is not the target string, the string is written to the temp file.
If the target string is found, both files are closed, the old file is deleted and the new file is renamed to the name of the old file. The new file is then opened so the program can do additional work on its contents.
Instead of having a fixed 10 character string, it is possible to ask the user for the string they wish to remove using cin >> szString but the string would need to be 10 characters long.
Your code work as expected, it only display deleted because disp() isn't called anywhere.
#include <iostream>
#include <string.h>
#include <fstream>
#include <stdio.h>
using namespace std;
typedef struct {
char str[16];
} ch;
static void disp(ch d) {
cout<<d.str<<"\n";
}
int main(int argc, char **argv) {
fstream file;
ch dta;
file.open("new.dat",ios::in|ios::out|ios::trunc);
for (int i=0; i<3; i++) {
snprintf((char *)&dta.str, sizeof(dta.str)-1, "rec%d", i);
file.write((char *)&dta,sizeof(dta));
}
//delete part
{
char s[16] = "rec1";
file.seekg(0);
int found=0;
fstream temp("temp.dat",ios::out);
while(file.read((char *)&dta,sizeof(dta))) {
if(strcmp(dta.str, s)==0) {
found=1;
cout<<"deleted * ";
disp(dta);
} else {
temp.write((char *)&dta,sizeof(dta));
disp(dta);
}
}
if(!found)
cout<<"not found";
file.close();
remove("new.dat");
rename("temp.dat","new.dat");
temp.close();
}
}