Can anyone please tell my why this method won't compile?
void Statistics::readFromFile(string filename)
{
string line;
ifstream myfile (filename);
if (myfile.is_open())
{
while (! myfile.eof() )
{
getline (myfile,line);
cout << line << endl;
}
myfile.close();
}
else cout << "Unable to open file";
}
Should work, right? Yet, I always get the following error message:
Line Location Statistics.cpp:15: error:
no matching function for call to
'std::basic_ifstream<char, std::char_traits<char> >::
basic_ifstream(std::string*)'
any help would be greatly appreciated.
ifstream myfile (filename);
should be:
ifstream myfile (filename.c_str() );
Also, your read-loop logic is wrong. It should be:
while ( getline( myfile,line ) ){
cout << line << endl;
}
The eof() function that you are using is only meaningful after you have tried to read read something.
To see why this makes a difference, consider the simple code:
int main() {
string s;
while( ! cin.eof() ) {
getline( cin, s );
cout << "line is "<< s << endl;
}
}
If you run this and type ctrl-Z or ctrl-D to indicate EOF immediately, the cout will be performed even though no line has actually been input (because of the EOF). In general, the eof() function is not very useful, and you should instead test the return value of functions like getline() or the stream extraction operators.
Read the compiler error:
no matching function for call to 'std::basic_ifstream >::basic_ifstream(std::string*)
No matching function for call to: It can't find the function you're trying to call
std::basic_ifstream >:: - a member function of ifstream
:basic_ifstream(std::string*) - the constructor which takes a string pointer as its argument
So you try to create an ifstream by passing a string pointer to its constructor. And it can't find a constructor that accepts such an argument.
Since you're not passing a string pointer in the above, the code you've posted must be different from your actual code. Always copy/paste when asking about code. Typos make it impossible to figure out the problem. In any case, as I recall, the constructor does not accept a string argument, but only a const char*. So filename.c_str() should do the trick
Apart from that, you can do this a lot simpler:
ifstream myfile (filename);
std::copy(std::istream_itrator<std::string>(myfile),
std::istream_itrator<std::string>(),
std::ostream_iterator<std::string>(std::cout));
}
You should use fileName.c_str() so that you pass the const char* pointer to the myFile construction.
The ifstream constructor has the following signature
explicit ifstream ( const char * filename, ios_base::openmode mode = ios_base::in );
You need to pass in a constant char* and a mode, for example:
ifstream ifs ( "test.txt" , ifstream::in );
The mode is optional, since it has a default value defined, so you can just use:
ifstream myfile ( filename.c_str() );
The C++11 standard has resolved this defect. std::ifstream myfile(filename); should now compile, when filename has type std::string.
Related
I am trying to write a program where I read a text file and then take each line in the textfile and store them in a string vector. I think I am able to open the textfile however I noticed that after I open the textfile anything after that point does not execute. For example I have a cout statement at the end of my main function that outputs when I enter the name of a file that doesn't exist. However if I type in a file name does exists I get no output from the last cout statement. Anyone know why this is? Thanks!
int main()
{
vector<string>line;
string fileName = "test.txt";
ifstream myFile(fileName.c_str());
int i = 0;
int count = 0;
vector<string>lines;
cout << "test" << endl;
if (myFile.is_open())
{
cout << "test2" << endl;
while (!myFile.eof())
{
getline(myFile, lines[i],'\n');
i++;
}
myFile.close();
}
if (!myFile.is_open())
{
cout<< "File not open"<< endl;
}
myFile.close();
cout << "Test3" <<endl;
return 0;
}
Try this:
string fileName = "test.txt";
ifstream myFile(fileName); // .c_str() not needed - ifstream can take an actual string
vector<string> lines;
string line; // temporary variable for std::getline
while (getline(myFile, line)) {
lines.push_back(line); // use push_back to add new elements to the vector
}
As pointed out in the comments, the most likely reason that your program seems to "end" prematurely is that it's crashing. std::getline takes a reference-to-string as its second argument. In your code, your vector is empty; therefore lines[i] for any i returns a reference to invalid memory. When getline tries to access that memory, the program crashes.
If you want an exception thrown when you try to access an out-of-bounds index of a vector, use lines.at(i) instead of lines[i].
You need to use push_back() because your initial vector is empty and, you can not use indexes on empty vector. If you do so, it will leads to undefined behavior.
std::ifstream input( "filename.ext" );
std::vector<std::string> lines;
for( std::string line; getline( input, line ); )
{
lines.push_back(line);
}
I have looked at a couple of links such as this and this.
Unfortunately I'm just to new of a programmer to figure it out. I would like to have the following as the line while( getline(getline(fin, line) ) because I'm trying to read in the entire line of text from a file. Then I'm trying to figure out if there are any similar words or numbers in that file. I'm writing this in Microsoft visual studio 2012.
#include <iostream>
#include <fstream>
#include <sstream>
#include <cctype>
#include <string>
using namespace std;
// main application entry point
int main(int argc, char * argv[])
{
string filename;
ifstream inFile;
// request the file name from the user
cout << "Please enter a filename: ";
// stores the users response in the string called filename
cin >> (std::cin, filename);
// opens the file
inFile.open(filename.c_str());
// if the file doesn't open
if (!inFile)
{
cout << "Unable to open file: " << filename << endl;
return -1;
} // end of if( !inFile )
// while( getline(getline(fin, line) ) gives me the same error
while (getline())
{}
// close the file
inFile.close();
} // end of int main( int argc, char* argv[])
why am I getting a error: no instance of an overloaded function “getline” matches the argument list here?
Because you called std::getline() without any arguments, while std::getline() does require arguments:
while( getline() )
{
}
What std::getline() takes, however, is
an stream& (where the input comes from)
an std::string& (where the input ends up)
optionally a char (a delimiter, the default is '\n')
Something like this should do:
std::string line;
while( std::getline(inFile, line) ) {
// process line
}
Note that your code is quite a mess. Let's walk through it:
int main(int argc, char * argv[])
Since you are not using argc and argv, why pass them? Your compiler should warn you that they aren't used – which is just noise that might distract you from a compiler diagnostic that points at a real issue. Do this instead:
int main()
and the warning is gone.
string filename;
ifstream inFile;
Why define these at the top of the function, when they are used only further down? In C++, it is considered good style to define objects as late as possible, preferably when they can be initialized.
using namespace std;
This is a bad idea that might hurt you badly. Just don't do it.
cin >> ( std::cin, filename );
I have no idea what this is supposed to do, let alone what it actually does, assuming it compiles. What you want instead, is this: std::cin >> filename. Note, however, that this prevents file names containing whitespace. Should that be a problem, employ std::getline() instead.
inFile.open( filename.c_str() );
This is where inFile should have been defined:
std::ifstream inFile( filename.c_str() );
Finally, your explicit closing of the file
inFile.close();
is unnecessary. The destructor of std::ifstream takes care of that anyway.
Following is the code to have output file. What if I want to give this output file different name each time, i.e., as demanded by the user. What kind of getline command would help.
I know I can simply cin a string name my_file but the desired name is in the input not in the string name.
void save(cdStruct *ptr) //Function that saves database info to file
{
ofstream dataFile;
dataFile.open("output.txt", ios::out | ios::app);
dataFile << ptr->title << endl;
dataFile << ptr->artist << endl;
dataFile << ptr->numberOfSongs << endl;
dataFile << ptr->number << endl;
dataFile.close();
}
You want to change this line:
dataFile.open("output.txt", ios::out | ios::app);
To something like this??
dataFile.open(my_name_string, ios::out | ios::app);
If yes, you have only to read this string before, add ".txt" and it's everything.
Check this code:
string name;
cin >name;
name.append(".txt");
ofstream dataFile;
dataFile.open(name.c_str(), ios::out | ios::app);
dataFile.close();
From your comments on other answers it sounds like you are passing the file name as a std::string to std::ofstream::open. Before C++11 it only accepted a const char * parameter, not a std::string (see this reference).
To fix this use filename.c_str() as the first parameter instead of filename. This returns a null-terminated char array, the type expected by std::ofstream::open
Your error message tells the following: you are using std::string at some point when you should be using char const *. Now we only need to find the proper place where the error occurs.
A quick look into online documentation of std::getline tells us, that this function is not the problem: the signature allows std::string. The only other thing that has changed is the std::ofstream(filename, std::ios::out | std::ios::ate), so we check the documentation of std::ofstream; indeed a char const *.
This problem should be quickly solved by replacing
std::ofstream dataFile(filename, std::ios::out | std::ios::ate);
with
std::ofstream dataFile(filename.data(), std::ios::out | std::ios::ate);
and then it should compile.
It is very important that you try to understand the error messages that your compiler is giving you and search for references where the problem may lie.
Your specific problem is not "Give output file desired name as desired by the user", but "How to read user input in command line program". For this, you can use std::getline:
#include <iostream>
#include <string>
int main() {
std::string filename;
getline(std::cin, filename);
}
One could be tempted to use the operator<< overloads,
#include <iostream>
#include <string>
int main () {
std::string filename;
std::cin >> filename;
}
however, they would give wrong results if your filename contains whitespace characters.
Sidenote: Don't pass nullable pointers when you want to enforce non-null values:
// don't: void save(cdStruct *ptr)
void save(cdStruct const &ptr) // <- ah, better
i have the next code:
std::string line;
std::ifstream myfile ("text.txt");
if (myfile.is_open())
{
while ( myfile.good() )
{
getline (myfile,line);
std::cout << line << std::endl;
}
myfile.close();
}
is there a way to do it, and use char* instead of string?
Yes, if you really insist. There's a version of getline that's a member of std::istream that will do it:
char buffer[1024];
std::ifstream myfile("text.txt");
while (myfile.getline(buffer, sizeof(buffer))
std::cout << buffer << "\n";
myfile.close();
Note, however, that most C++ programmers would consider this obsolescent at best. Oh, and for the record, the loop in your question isn't really correct either. Using string, you'd typically want something like:
std::string line;
std::ifstream myfile("text.txt");
while (std::getline(myfile, line))
std::cout << line << "\n";
myfile.close();
or, you could use the line proxy from one of my previous answers, in which case it becomes simpler still:
std::copy(std::istream_iterator<line>(myfile),
std::istream_iterator<line>(),
std::ostream_iterator<std::string>(std::cout, "\n"));
So you're looking for a more "C-like" solution?
#include<cstdio>
#define ENOUGH 1000
int main() {
char buffer[ENOUGH];
FILE* f = fopen("text.txt", "r");
while (true) {
if (fgets(buffer, ENOUGH, f) == NULL) break;
puts(buffer);
}
fclose(f);
return 0;
}
...plus some check whether the file was correctly opened. In this case, you use fgets() on the file f, reading into the char* buffer. However, buffer has only ENOUGH space allocated and this limit is also an important parameter to the fgets() function. It will stop reading the line when reaching ENOUGH - 1 characters, so you should make sure the ENOUGH constant is large enough.
But if you didn't mean to solve this in a "C-like" way, but are still going to use <iostream>, then you probably just want to know that the c_str() method of std::string returns the char* representation of that std::string.
I am trying to read from a text file and tokenize the input. I was getting a segmentation fault until I realized I forgot to close my ifstream. I added the close call and now it loops infinitely. I'm just trying to learn how to use strtok for now, that is why the code doesn't really look complete.
void loadInstructions(char* fileName)
{
ifstream input;
input.open(fileName);
while(!input.eof());
{
string line;
getline (input,line);
char * lineChar = &line[0];
//instruction cmd; //This will be used later to store instructions from the parse
char * token;
token = strtok (lineChar," ");
// just trying to get the line number for now
int lineNumber = atoi(token);
cout << lineNumber << "\n";
}
input.close();
}
input file:(one line)
5 +8 0 0 25
This while(input.good()); is probably not what you intended...
Use this:
string line;
while(getline (input,line))
{
If the getline() works then the loop is entered.
If you try and read past the EOF then it will fail and the loop will exit.
So this should word as expected.
Rather than using strtok() (which damages the string) and atoi() which is non portable.
Use std::stringstream
std::stringstream linestream(line);
int lineNumber;
linestream >> lineNumber; // reads a number from the line.
Don't explicitly close() the stream (unless you want to detect and correct for any problems). The file will be closed when the object goes out of scope at the end of the function.
You want to use eof() not good().
Avoid strtok. There are other ways to tokenize a string that do not require the called function to modify your string. The fact that it modifies the string it tokenizes could also be what causes the loop here.
But more likely, the good() member is not the right one. Try !input.eof() or similar, depending on what you need.
While you've already gotten some answers to the question you asked, perhaps it's worth answering some you should have about the code that you didn't ask:
void loadInstructions(char* fileName)
Since the function isn't going to modify the file name, you almost certainly want to change this to:
void loadInstructions(char const *fileName)
or
void loadInstructions(std::string const &fileName)
ifstream input;
input.open(fileName);
It's much cleaner to combine these:
ifstream input(fileName);
or (if you passed a string instead):
ifstream input(fileName.c_str());
while(!input.eof());
This has already been covered.
string line;
getline (input,line);
char * lineChar = &line[0];
//instruction cmd; //This will be used later to store instructions from the parse
char * token;
token = strtok (lineChar," ");
// just trying to get the line number for now
int lineNumber = atoi(token);
Most of this is just extraneous. You can just let atoi convert directly from the original input:
string line;
getline(input, line);
int lineNumber = atoi(line);
If you're going to tokenize more later, you can use strtol instead:
char *end_ptr;
int lineNumber = strtol(line, &end_ptr, 10);
This will set end_ptr to point just past the end of the part that strtol converted.
I'd also consider an alternative though: moving your code for reading and parsing a line into a class, and define operator>> to read those:
struct line {
int number;
operator int() { return number; }
};
std::istream &operator>>(std::istream &is, line &l) {
// Just for fun, we'll read the data in an alternative fashion.
// Instead of read a line into a buffer, then parse out the first number,
// we'll read a number from the stream, then ignore the rest of the line.
// I usually prefer the other way, but this is worth knowing as well.
is >> l.number;
// When you're ready to parse more, add the extra parsing code here.
is.ignore(std::numeric_limits<std::istream::pos_type>::max, '\n');
return is;
}
With this in place, we can print out the line numbers pretty easily:
std::copy(std::istream_iterator<line>(input),
std::istream_iterator<line>(),
std::ostream_iterator<int>(std::cout, "\n"));
input.close();
I'd usually just let the stream close automatically when it goes out of scope.