Use string or array of char for filename? - c++

I have come across something online about strings. It says to use an array of chars for a filename input and not string. Why is that?

You seem to be using an older version of C++, where std::ifstream::open accepts only a const char *, not a std::string (see docs):
void open (const char* filename, ios_base::openmode mode = ios_base::in);
As you can see, you cannot pass a std::string here.
In C++11 and newer, you can pass a std::string as well:
void open (const string& filename, ios_base::openmode mode = ios_base::in);
A better approach: use std::string to input the file name and the do File.open(filename.c_str()); to open the file.

That advice is basically wrong. The problem it is attempting to get around is that back in the olden days, file streams took const char* as the argument for the file name, so you couldn't directly use a std::string for the name. Of course, the answer to that is to use std::string, and call c_str() to pass the file name:
std::string name = "test.txt";
std::ofstream out(name.c_str());
These days, file streams also have a constructor that takes std::string, so you can do this:
std::string name = "test.txt";
std::ofstream out(name);

I suspect it is because of the prototype of ifstream::open(const char*). Personally, I would have written the code as:
string filename;
cin >> filename;
ifstream testmarks;
testmarks.open(filename.c_str());
But that is yet more complexity to explain, and this is obviously aimed at someone very new to C++.

This is wrong, and it's a wonderful way to write programs vulnerable to buffer overflows, at least as written in the example.

The "open" function expect char pointer.
However it is fine to do this:
std::string filename;
std::cin >> filename;
std::ifsteam f;
f.open(filename.c_str());

Related

C++ syntax to name file via variable and text

I have a program that takes in the name of a file as an argument (example: books.txt), runs, and then outputs the results to a new text file. I need to name the output file with an addendum (example: books_output.txt).
The method that I tried was
ofstream outputFile;
outputFile.open(argv[1] + "_output.txt", ofstream::out);
but this didn't compile.
How can I make this work?
Your statement should look like this (as mentioned in my comment):
outputFile.open(std::string(argv[1]) + "_output.txt", ofstream::out);
// ^^^^^^^^^^^^ ^
assumed argv[1] comes from the standard main() signature
int main(int argc, char* argv[])
argv[1] is a char* pointer and you can't concatenate char* pointers that way.
As some people bother regarding support of obsolete C++ standard versions, the std::ofstream::open() signatures of earlier versions didn't support a const std::string parameter directly, but only const char*. In case you have that situation your statement should look like
outputFile.open((std::string(argv[1]) + "_output.txt").c_str(), ofstream::out);
you cannot put a + between 2 C strings. Use std::string instead. Do this
ofstream outputFile;
std::string fname = std::string(argv[1]) + "_output.txt";
outputFile.open(fname.c_str(), ofstream::out);
More recent c++ versions allow
outputFile.open(fname, ofstream::out);
which reads nicer but means the same thing

C++: cin >> *char

So, I'm currently writing a line editor as a learning project on I/O, writing files, and the like. It is written in C++, and I am currently trying to write out to a file of the user's choosing. I have CLI arguments implemented, but I currently have no idea how to implement an in program way of specifying the file to write to.
char *filename;
if (argc >= 2){
filename = argv[1];
} else{
cout << "file>";
cin >> filename;
cin.ignore();
}
This works perfectly well when I use command line arguments; however, whenever I do not, as soon as I start the program, it Segmentation Faults. The place where I use the actual filename is in the save command:
void save(char filename[], int textlen, string file[]){
ofstream out(filename);
out << filestring(textlen, file);
out.close();
}
Which also works perfectly well. Is there any way you can help me? Full source code, for review, is up on https://github.com/GBGamer/SLED
The problem is that char* filename is just a pointer to some memory containing characters. It does not own any memory itself.
When you use the command line argument, the program handles storing that string somewhere, and you get a pointer to it. When you try to read using cin >> filename there isn't actually anywhere to store the read data.
Solution: Replace char* filename with std::string filename (and #include <string>).
Then to open the output file, you need a c-style string (null terminated char array). std::string has a function for this. You would write
std::ofstream out(filename.c_str());
^^^^^
Or, in fact, if you can use a recent compiler with c++11 features, you don't even need to use c_str(). A new std::ofstream constructor has been added to accept a std::string.
Your filename variable points to argv[1] when command line argument is provided, it does not need memory to be allocated but when going in else block, you have not allocated memory to filename. Its just a pointer.
Use malloc to assign filename some memory then take user input.
filename = (char *)malloc(sizeof(char)*(FILE_NAME_LENGTH+1))

using string to pass filename to fstream

I am using the following method to read a txt file
modelStream.open("file.txt", ios::in);
if (modelStream.fail())
exit(1);
model = new Model(modelStream);
but i want to know how i can pass in a string as a parameter
string STRING;
modelStream.open(STRING, ios::in);
if (modelStream.fail())
exit(1);
model = new Model(modelStream);
does anyone know if this is possible and if it is how would I do it?
For legacy reasons, iostreams in C++03 expects a C-style, null-terminated string as argument and doesn't understand std::string. Fortunately, std::string can produce a C-style, null-terminated string, with the function std::string::c_str():
modelStream.open(STRING.c_str(), ios::in);
This was actually "fixed" in C++11, so if you were using it your original code would be functional.
Also, an all-caps variable name is not recommended; neither is a variable called "string". Make the name describe the meaning.
Simply use c_str () method of std::string
modelStream.open(STRING.c_str (), ios::in);
the standard streams doesn't accept a standard string, only c-string! So pass the string using c_str():
modelStream.open(STRING.c_str(), ios::in);

c++: Reading a file line by line

I'm wondering if there's a C++ way of opening a file and reading the input line by line.
I encountered the following code that accomplishes the task:
#include <iostream>
#include <fstream>
using namespace std;
int main () {
ifstream myfile;
myfile.open ("example.txt");
return 0;
}
I'm encouraged to not use any C functions or commands.
The thing is, my "example.txt" is in the form of a string, and using str.c_str() is a C function, so I guess I have two ways to solve the issue.
Is there another way to read input from a file line by line? Perhaps using something that will accept a string as a parameter for the filepath? Is there a C++ way of doing things? :)
Or, is there another way to convert the string in to a const char *, which is what the myfile.open() function needs?
Many thanks in advance!
EDIT: My lack of practivity and research led me to think c_str() was a C function, and it isn't. My apologies. Since it isn't I have found my answer.
C++11's fstream constructor accepts string. In most cases, you want to use fstream's constructor, rather than .open() - you save one line and one function call.
For reading the file line-by-line, you should use std::getline().
Also note that string::c_str() is still C++ function, not C one, as well as fstream's constructor taking const char *. Most of (if not all, I'm not 100% sure) C standard library function are also included in C++ standard.
Since the issue about str.c_str() is already answered, I'm just gonna add a bit about getting inputs line by line. for example, you wanna take 2 ints input per line, extract them, and put it into a vector.
fstream fs(filename.c_str(), ios_base::in);
string line;
stringstream ss;
int a,b;
vector<int> d;
int numlines;
int i;
for (i = 0; getline(fs, line); i++) {
for (ss.str(line); ss >> a >> b; d.push_back(a), d.push_back(b)) {}
ss.clear();
}
numlines = i;
Hope you get the idea of using getline() and fstream()
It's going to look very similar. You'll want an ifstream instead of an ofstream, you'll want the >> operator, and assuming your file has more than one line, you'll need a loop and the ifstream::feof() function.

Pass path to file / filename as argument to a function that prints the file to screen in C++

As the title says, is there any way to pass the path to the file / filename to open as an argument in the function?
I've written a short code for printing a .txt-file to the screen in C++, but instead of having all the code in the main(), I'd rather have it as an own function that I can call with the filename of the file to open as the only input argument.
Basically the beginning of the function would look like
void printFileToScreen()
{
ifstream fin;
char c;
fin.open("FILE_TO_OPEN.txt", ios::in);
blablabla
}
Now is there any way to pass "FILE_TO_OPEN.txt" when I call the function?
I've tried
void printFileToScreen(string str)
{
ifstream fin;
char c;
fin.open(str, ios::in);
blablabla
}
where I call the function like printFileToScreen("FILENAME.txt"), but with no luck, so I'm not sure how to do this.
Hope anyone can help :)
Unfortunately, the iostream functions deal with const char* types rather than with std::string (the iostream functions were developed independently of the STL). You instead could use std::string::c_str() to obtain a const char*:
fin.open(str.c_str(), ios::in);
As a general design rule, I would not pass the file name to the called function. I would pass the already opened std::istream object to read from. This allows you to do the job of printing in a function, and to do the job of opening the file and dealing with non-existent files in another. This has the bonus of being able to pass std::cin to your function!
Try changing your function to look like this :
void printFileToScreen(const string &str);
//If you pass a const char*, a string will be constructed
or this :
void printFileToScreen(const char *);
The function you wrote expects an instance of std::string to be passed by value.
Never mind, after some more trying and failing I found out that I needed to pass a char pointer, and not a string. :)
Of course you can pass the filename as a function parameter. If in doubt, pass a "const char*" rather than a string. I should work.