I read about substr from here
http://www.cplusplus.com/reference/string/string/substr/
Here is my code :
int main()
{
std::ifstream in ("c:\\users\\admin\\desktop\\aaa.txt");
std::ofstream out ("c:\\users\\admin\\desktop\\bbb.txt");
std::string s ;
while ( getline (in,s) )
{
std::size_t startpos = s.find("test");
std::string str = s.substr (startpos);
out << str << endl;
}
in.close();
out.close();
}
I get error : R6010 abort() has been called
Note : aaa.txt contains spaces/characters/html tags
Any idea ?
Since I dont know the content of the text file, could you try making the following changes and let me know if the error is still being shown:
#include <fstream>
#include <iostream>
#include <sstream>
using namespace std;
int main()
{
ifstream in("example.txt");
ofstream out("bbb.txt");
string s = std::string();
string str = std::string();
while (getline(in, s))
{
size_t startpos = s.find("test");
cout << s;
if (startpos != std::string::npos){
str = s.substr(startpos);
out << str << endl;
}
}
in.close();
out.close();
getchar();
return 0;
}
I am using if (startpos != std::string::npos) condition to check what to do when the find succeeds, this is missing in your code. adding this case will resolve your error.
Keep coding :)
While Code Frenzy answer is right, you can also use exceptions to help catch these kind of errors:
#include <fstream>
#include <iostream>
#include <sstream>
using namespace std;
int main()
{
std::ifstream in ("aaa.txt");
std::ofstream out ("bbb.txt");
std::string s ;
try
{
while ( getline (in,s) )
{
std::size_t startpos = s.find("test");
std::string str = s.substr (startpos);
out << str << endl;
}
in.close();
out.close();
}
catch(std::exception e)
{
// (1) it will catch the error show show
cerr << e.what() << endl;
}
catch(std::out_of_range e)
{
// (2) this will also catch the same error if (1) was not there but could
// get you more details if you wanted since its more specific but i have
// not digged into it further
cerr << e.what() << endl;
}
catch(...)
{
// (3) just for sanity check if first two didn't catch it
cerr << "something went wrong";
}
}
The exceptoin catches this error and prints the message:
invalid string position
Related
my code work good when the argc is 1 but when I try to read and write from files (when argc is 3)
the program not working well. Gcalc get the ostream (output file or cout) and current line in input file
or cin and decode the string to command on gcalc data.
#include <ostream>
#include <fstream>
#include <string>
#include <iostream>
#include "Gcalc.h"
using namespace std;
int main(int argc, char* argv[]) {
Gcalc gcalc;
string current_line;
ifstream input;
ofstream output;
if (argc != 1 && argc != 3) {
return 0;
}
if (argc == 3) {
input = ifstream(argv[1]);
cin.rdbuf(input.rdbuf());
output = ofstream(argv[2]);
cout.rdbuf(output.rdbuf());
}
while (cin.good()) {
if (argc == 1) {
cout << "Gcalc> ";
}
getline(cin, current_line);
try {
gcalc.implementCommand(cout, current_line);
}
catch (Quit_Program& error) {
break;
}
catch (std::bad_alloc& error) {
std::cerr << "Error: fatal error - bad allocation" << endl;
break;
}
catch (Exception& error) {
cout << error.what() << endl;
}
}
return 0;
}
Check that opening the files was done successfully.
Check that the istream you read from doesn't have the failbit set after you've read from it. Since an istream in a boolean context checks badbit and failbit and that std::getline returns the same istream you gave it, replace your while (cin.good()) with:
while(getline(cin, current_line)) {
// ... only entered if badbit and failbit are false ...
}
That said, it's usually better to create a separate function for reading/writing to generic istream/ostreams. This way you don't have to mess with the rdbufs of cin and cout.
#include <fstream>
#include <iostream>
#include <string>
#include "Gcalc.h"
void do_stuff(std::istream& is, std::ostream& os) {
Gcalc gcalc;
std::string current_line;
while(getline(is, current_line)) {
try {
gcalc.implementCommand(os, current_line);
} catch(Quit_Program& error) {
break;
} catch(const std::bad_alloc& error) {
std::cerr << "Error: fatal error - " << error.what() << std::endl;
break;
} catch(Exception& error) {
std::cout << error.what() << std::endl;
// or, if you really want it:
// os << error.what() << std::endl;
}
}
}
int main(int argc, char* argv[]) {
if(argc == 1) {
do_stuff(std::cin, std::cout);
} else if(argc == 3) {
std::ifstream input(argv[1]);
std::ofstream output(argv[2]);
if(input && output) do_stuff(input, output);
}
}
If you want to give the user a prompt when the program is running in interactive mode, you could add a function that prints the prompt and then calls std::getline. You can combine this inside the while loop, but it looks messy, so I would suggest something like this:
std::istream& prompt(std::istream& is, std::string& line) {
if(&is == &std::cin) std::cout << "Gcalc> ";
return std::getline(is, line);
}
// ...
while(prompt(is, current_line)) {
// ...
}
I have written a small C++ program to set a property in a text file. The implementation is as following:
#include <cstdio>
#include <fstream>
#include <iostream>
#include <string>
using namespace std;
const string PROPFILE = "./propfile";
const string TEMPFILE = PROPFILE + ".tmp";
int setProp(const string &key, const string &val) {
try {
ifstream original(PROPFILE, ios::in);
ofstream tempfile(TEMPFILE, ios::out | ios::trunc);
for (string line; getline(original, line); ) {
if (line.compare(0, key.size(), key) == 0 && line[key.size()] == '=') {
tempfile << key << '=' << val << endl;
} else {
tempfile << line << endl;
}
}
cout << "original.rdstate()" << original.rdstate() << endl;
original.close();
tempfile.close();
} catch (ifstream::failure e) {
cerr << e.what() << endl;
}
if (rename(TEMPFILE.c_str(), PROPFILE.c_str()) != 0) {
cout << "Could not move " + TEMPFILE << "to " << PROPFILE << endl;
return 1;
}
return 0;
}
int main(int argc, const char *argv[]) {
try {
return setProp(argv[1], argv[2]);
} catch (logic_error) {
cout << "Invalid args" << endl;
return 1;
}
}
However, when I try to compile and execute it from commandline via ./a.out TESTPROP TESTVALUE, the value IS set as expected in propfile but rdstate() returns 6 (which means failbit and eofbit are set), I can't understand why are they getting set, can somebody explain ?
Contents of propfile before running ./a.out TESTPROP TESTVALUE are:
TESTPROP=NOTHING
After running the progam:
TESTPROP=TESTVALUE
I'm just a student, please don't mind if it's a dumb question :)
This is expected behaviour, the failbit is set whenever there is a failure to read the expected value. Even if that failure is because of end of file.
For instance see here
If no characters were extracted for whatever reason (not even the
discarded delimiter), getline sets failbit and returns.
Properly testing function return values is fundamental, but it can quickly clutter the code and make it hard to read, like in the simple example below:
#include <iostream>
#include <fstream>
int main(int argc, char **argv)
{
std::string filename("/usr/include/malloc.h");
std::ifstream ifs(filename.c_str());
if (!ifs.is_open())
{
std::cerr << "Failed to open file " << filename << std::endl;
return 1;
}
ifs.close();
std::cout << "Passed the first error handling" << std::endl;
filename = "/this/file/does/not/exist";
ifs.open(filename.c_str());
if (!ifs.is_open())
{
std::cerr << "Failed to open file " << filename << std::endl;
return 1;
}
return 0;
}
I have thought of a solution reducing cluttering by using a macro and c++11 lambda functions like this:
#include <iostream>
#include <fstream>
#define RETURN_IF(X,Y,Z) if ( X ) { Y ; return Z; }
auto open_file_error = [](const std::string& filename)
{
std::cerr << "Failed to open file " << filename << std::endl;
};
int main(int argc, char **argv)
{
std::string filename("/usr/include/malloc.h");
std::ifstream ifs(filename.c_str());
RETURN_IF (!ifs.is_open(), open_file_error(filename), 1 );
ifs.close();
std::cout << "Passed the first error handling" << std::endl;
filename = "/this/file/does/not/exist";
ifs.open(filename.c_str());
RETURN_IF (!ifs.is_open(), open_file_error(filename), 1 );
return 0;
}
As you can see, the main function is less cluttered. Do you think that there are drawbacks to doing it like that or could it be a method to largely use?
Note that I use several macros to handle cases with or without a return value, for testing equality with a value, etc.
I propose the new version below to take into account two things:
- the answers and comments about the preference on using exceptions instead of return values;
- put away the emphasis on std::ifstream specific errors which are not the subject of the question.
#include <iostream>
#include <fstream>
#include <exception>
class OurExceptionForTheExternalLibraryFailure : public std::exception {};
#define CLEANUP_AND_THROW_IF(X,Y,Z) if ( X ) { Y ; throw Z; }
/* Return true in case of succes and false otherwise */
bool anyExternalFunction(const std::string& aString)
{
std::ifstream ifs(aString.c_str());
if (ifs.is_open())
{
ifs.close();
return true;
}
else
{
return false;
}
}
auto this_external_function_error_cleanup = [](const std::string& aString)
{
std::cerr << "The external function failed " << aString << std::endl;
// other stuff
};
int main(int argc, char **argv)
{
try
{
std::string aString = "/usr/include/malloc.h";
bool functionResult = anyExternalFunction(aString);
CLEANUP_AND_THROW_IF (!functionResult, this_external_function_error_cleanup(aString), OurExceptionForTheExternalLibraryFailure() );
std::cout << "Passed the first error handling" << std::endl;
aString = "/this/file/does/not/exist";
functionResult = anyExternalFunction(aString);
CLEANUP_AND_THROW_IF (!functionResult, this_external_function_error_cleanup(aString), OurExceptionForTheExternalLibraryFailure() );
}
catch (const OurExceptionForTheExternalLibraryFailure& e)
{
std::cerr << "Catched OurExceptionForTheExternalLibraryFailure. There was an error" << std::endl;
}
return 0;
}
What do you think about this new version (which still uses a macro, though...) ?
Well, if you are already using lambdas, and you don't want all that testing code everywhere, you could always do something like (NOTE: uncompiled/untested code,)
template <typename FileReader>
void with_file(std::string file, FileReader&& reader) {
std::ifstream in(file);
if (in) {
reader(in);
} else {
throw std::runtime_error("Failed to open file: " + file); // NOTE: I'm being lazy here
}
}
int main(...) {
with_file("foo.txt", [](auto& in) {
// do something with the stream
});
}
.. but it's a matter of preference, I like exceptions, lambdas and small utility functions, but some may not...
This is pretty much a textbook example of when to use exceptions.
You don't, however, have to write your own code to test for a file opening correctly, and throwing an exception (and so on) when it fails. Iostreams already support that fairly directly, so you can write code something like this:
#include <fstream>
#include <iostream>
int main() {
try {
std::ifstream in("/usr/include/malloc.h");
in.exceptions(std::ios::failbit);
in.close();
std::cout << "passed first test.\n";
std::ifstream in2("/this/file/does/not/exist");
in2.exceptions(std::ios::failbit);
in2.close();
std::cout << "Passed second test\n";
}
catch (std::system_error &f) {
std::cerr << "Failed to open file: " << f.what() << "\n";
}
}
Of course, if you want to get the try/catch out of main, you can do that as well. I'm not sure you gain much from doing so though.
More generally, however, exceptions are clearly the right tool for this job. For other functions that don't provide a way to get exceptions reported as exceptions, you may have to write a wrapper of your own. Either way, however, if you have a function that has some range of normal return values, and one (or a few) "special" values in indicate failure (and similar) that's a pretty decent indication that it's indicating an exceptional condition via the return value--and the right way to deal with exceptional conditions is via exceptions rather than return values.
Rather than try to reiterate the (long) list of why/when/how to use exception handling, I'll refer you (as a starting point) to Herb Sutter's old article on when and how to use exceptions.
Suggest this as a much cleaner example. NOW USING EXCEPTIONS...
I haven't tested that it's 100% the same behaviour as your example (which I appreciate is just that; an example).
By the way, MFC has a "SUCCESS" macro that does a similar check to your "RETURN_IF". I don't like that macro either...
#include <iostream>
#include <fstream>
#include <string>
void TestForFileOpen(const std::string& filename)
{
std::ifstream ifs(filename.c_str());
if (!ifs.is_open())
{
throw std::exception("Failed");
}
}
void ReportFileOpenFailure(const std::string& filename)
{
std::cerr << "Failed to open file " << filename << std::endl;
}
void NoisyTestForFileOpen(const std::string& filename)
{
try
{
TestForFileOpen(filename);
}
catch(...)
{
ReportFileOpenFailure(filename);
throw;
}
}
int main(int argc, char **argv)
{
std::string filename("/usr/include/malloc.h");
try
{
NoisyTestForFileOpen(filename);
std::cout << "Passed the first error handling" << std::endl;
filename = "/this/file/does/not/exist";
NoisyTestForFileOpen(filename);
}
catch (...)
{
return 1;
}
return 0;
}
A more general example with a custom API:
#include <iostream>
#include <fstream>
#include <string>
class IFileTester
{
public:
virtual ~IFileTester() {}
// throws if file cannot be opened
virtual void TestForFileOpen(const std::string& filename) const = 0;
};
class IfStreamFileTester : public IFileTester // implement as many versions as you need
{
public:
virtual void TestForFileOpen(const std::string& filename) const
{
// implement this in terms of ifstream
std::ifstream ifs(filename.c_str());
// thanks #Jerry-Coffin
ifs.exceptions(std::ios::failbit);
}
};
void ReportFileOpenFailure(const std::string& filename)
{
std::cerr << "Failed to open file " << filename << std::endl;
}
void NoisyTestForFileOpen(const IFileTester& fileTester, const std::string& filename)
{
try
{
fileTester.TestForFileOpen(filename);
}
catch(...)
{
ReportFileOpenFailure(filename);
throw;
}
}
int main(int argc, char **argv)
{
IFileTester& fileTester = IfStreamFileTester();
std::string filename("/usr/include/malloc.h");
try
{
NoisyTestForFileOpen(fileTester, filename);
std::cout << "Passed the first error handling" << std::endl;
filename = "/this/file/does/not/exist";
NoisyTestForFileOpen(fileTester, filename);
}
catch (...)
{
return 1;
}
return 0;
}
Looks okay to me. I wouldn't put all your eggs into this basket because you don't have to make it much more complicated to run into limitations with preprocessor syntax but, as it is, this is fine.
I've been trying to store the lines of a text file in a list in C++. Better, I've been trying to store each word of each line of the text file in a string that is part of a list of strings, but it seems that I'm doing it in the wrong way.
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <list>
using namespace std;
int main()
{
FILE *f= fopen("teste.txt", "r");
size_t len= 100; // valor arbitrário
char *line= (char*)malloc(len);
std::list<string> mylist;
if (!f)
{
perror("teste.txt");
exit(1);
}
while (getline(&line, &len, f) > 0)
{ //THE REAL PROBLEM
for (std::list<string>::iterator it = mylist.begin(); it != mylist.end(); it++){
*it=line;
cout << *it << '\n';
}
}
if (line)
free(line);
fclose(f);
return 0;
}
The exact problem is that this doesn't give any result. It compiles but nothing results from this.
Thanks in advance.
Change your while loop as follows:
while (getline(&line, &len, f) > 0)
{
mylist.push_back(line);
cout << mylist.back() << '\n';
}
You cannot access any non initialized items from a std::list<>.
Also NOTE you should make line a std::string, and omit the malloc() / free() calls from your code.
2nd NOTE: Use std::ifstream instead of FILE* for an input file stream.
Here's the fully fixed (no more errors/exceptions on ideone) code sample:
#include <iostream>
#include <fstream>
#include <string>
#include <list>
#include <exception>
#include <errno.h>
#include <stdlib.h>
int main()
{
try
{
std::ifstream f("teste.txt");
if(!f)
{
std::cerr << "ERROR: Cannot open 'teste.txt'!" << std::endl;
exit(1);
}
std::string line;
std::list<std::string> mylist;
while (std::getline(f,line))
{
mylist.push_back(line);
std::cout << mylist.back() << std::endl;
}
}
catch(const std::exception& ex)
{
std::cerr << "Exception: '" << ex.what() << "'!" << std::endl;
exit(1);
}
exit(0);
}
You can not assign a char* value to std::string by using '=' operator.
Change
*it=line to
it->assign(line,line+strlen(line);
I need to write two programs write.cpp & read.cpp to run simultaneously. One of them write(overwrite) to a file and the other one reads from it.
Basically, there is always only one line in the file.
write.cpp performs the operation successfully but read.cpp doesn't show anything. Using tail -f also shows incorrect result.
write.cpp:
#include <stdio.h>
#include <ctime>
#include <unistd.h>
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main () {
ofstream myfile;
int i = 70;
char c;
while(i <85)
{
myfile.open ("example.txt");
c = i++;
myfile << c << endl;
myfile.close();
sleep(1);
}
return 0;
}
read.cpp:
#include <iostream>
#include <fstream>
#include <string>
#include <unistd.h>
using namespace std;
int main () {
string line;
ifstream myfile ("example.txt");
if (myfile.is_open())
{
while ( myfile.good() )
{
sleep(1);
getline (myfile,line);
cout << line << endl;
}
myfile.close();
}
else cout << "Unable to open file";
return 0;
}
May I know which part of both programs causes the problem and how may I solve it?
You're doing the right thing in the writer, but once you've read to end of file, the input stream becomes unusable until the fail condition is set. The best solution is probably to do exactly what you're doing in the writer: open and close the file each time in the read loop.
Be aware that there will be a moment when the file is empty; when you open the file for writing in the writer, it will be truncated, and if the reader happens to try to read at precisely this moment, it will find an empty file. (It's no big problem; just be aware of it, maybe skipping the sleep if you find an empty line.)
To add some detail to my answer to your previous question, here is how you could use Boost's interprocess communication to achieve this if you insist on using a file for ipc.
A writer may look like this:
#include <boost/interprocess/sync/file_lock.hpp>
#include <boost/interprocess/sync/scoped_lock.hpp>
#include <fstream>
#include <iostream>
int main()
{
using namespace boost::interprocess;
std::string line, shared_filename = "shared";
{
std::ofstream create_shared_file(shared_filename.c_str());
}
for (;;)
{
std::cout << "Enter some text: ";
std::cin >> line;
try
{
file_lock lock(shared_filename.c_str());
scoped_lock<file_lock> lock_the_file(lock);
std::ofstream shared_file(shared_filename.c_str(), std::ofstream::trunc);
shared_file << line << std::endl;
shared_file.flush();
}
catch (interprocess_exception const& e)
{
std::cerr << e.what() << std::endl;
}
}
}
The corresponding reader:
#include <boost/interprocess/sync/file_lock.hpp>
#include <boost/interprocess/sync/sharable_lock.hpp>
#include <fstream>
#include <iostream>
#include <unistd.h>
int main()
{
using namespace boost::interprocess;
std::string line, shared_filename = "shared";
for (;;)
{
try
{
file_lock lock(shared_filename.c_str());
std::cout << "Waiting for file lock..." << std::endl;
sharable_lock<file_lock> lock_the_file(lock);
std::cout << "Acquired file lock..." << std::endl;
std::ifstream shared_file(shared_filename.c_str());
shared_file >> line;
if (line.empty())
{
std::cout << "Empty file" << line << std::endl;
}
else
{
std::cout << "Read: " << line << std::endl;
}
}
catch (interprocess_exception const& e)
{
std::cerr << "Could not lock " << shared_filename << ": " << e.what() << std::endl;
}
std::cout << "Sleeping..." << std::endl;
sleep(2);
}
}