How does using a variable for file paths work? - c++

ifstream inFile;
inFile.open("C:/FilePathThatWorks");
The above seems to work in C++. But if I try and take a String, or CString, or anything else, and plug it in for inFile.open(ExampleString), it fails at compile time (error at the bottom of this question). The question is not about my code, but how to make C++ accept a variable for inFile.
If it only ever accepts char* variables, then is there perhaps a method that takes input from the user in the form of a char* with the null terminator and everything.
error: no matching function for call to 'std::basic_ifstream<char>::open(std::__cxx11::string&)'

The method open in fstream does not accept std::string. You need to pass a char*.
So just call c_str() on string.

ifstream requires a char* param for the filename. see http://www.cplusplus.com/reference/fstream/ifstream/ifstream/
most string classes have some way to convert to this kind of string (e.g. c_str())

If you want to use CString:
CString path = "c:\\FilePathThatWorks";
ifstream inFile;
inFile.open(static_cast<const char*>(path));
The cast is not needed here.
CString can represent two different strings depending on the project settings. If it is a string of char the code should compile, if the character type is wchar_t compiling should fail.

Related

Using PUNICODE_STRING with regex_match in C++

I am trying to use the PasswordFilter function, and need to get Password variable value, which is a PUNICODE_STRING, then use regex_match to match a password policy.
The problem is that regex_match cannot recognize the PUNICODE_STRING.
What can I do?
Strings stored as a LSA_UNICODE_STRING (or its typedefs) might not be null-terminated so passing the Buffer pointer to a function that is expecting a null-terminated string (or a std::wstring) is not guaranteed to be safe.
Instead, convert it to a std::wstring using the Length field to specify the length of the string:
PUNICODE_STRING pStringIn; // this comes from somewhere
std::wstring strOut(pStringIn->Buffer, pStringIn->Length / sizeof(wchar_t));
You can then use strOut.c_str() or pass it directly to functions that accept a std::wstring.

Trouble with logfile output - difference between string and c_str - C++

I am trying to finalize my logging class. I have written it from scratch and do not wish to use an alternative library of any kind. My problem lies within the fact that my logger has trouble outputting std::strings and only works when I denote it with the string.c_str() function.
Here is my logfile output function:
void Log::writeSuccess(char * text,...)
{
// Grab the variables and insert them
va_list ap;
va_start(ap, text);
char buff[BUFFER_SIZE];
vsnprintf(buff, sizeof(buff), text, ap);
// Output to the log
logfile << "<-!-> " << buff << endl;
}
Here is a sample call to my log class object (ignore the uselessness of the call):
string test("This is a test string!");
errorLog.writeSuccess("Output: %s", test);
I end up with random characters and garbled output.
However, when I append the string, test with .c_str(), it outputs the text correctly.
The whole reason I am trying to avoid cstrings is because I understand they are not cross platform and am developing my client to support all the major operating systems.
To summarize:
What is wrong with my log output function? Do you see any way it could be improved?
Should I generally avoid c_strings?
You're getting random garble when passing an std::string to vsnprintf because the format specifier "%s" is that of a C-string - a char*.
std::string is not of type char*, but std::string.c_str() is of type char*. vsnprintf will basically read chars pointed to by the address that it presumes is that of a start of a C-string, up until the NUL character '\0'.
An std::string pushed onto the stack and passed as an argument to vsnprintf is not a pointer to a char, however vsnprintf will just treat these bytes as an address and start reading chars/bytes from this address, causing undefined behaviour.
The printf family of functions are not typesafe, since they rely on a format string and variable argument list, which is why your code will compile but you'll get unexpected results.
Bottom line is the printf family of functions expect a char* when you use the format specifier "%s".
I also think you're confusing C style strings (char[]) with the Microsoft-specific CString class. C style strings won't cause you problems on different platforms at all; the literal "This is a test string!" is a C style string (const char[]).
When calling function with variable parameters you must use simple types. For string you must use c_str(). There's no workaround. MFC's CString is designed so that you can get away with using it directly, but that was Microsoft's decision, and part of their design.
EDIT: As I said when calling function with variable parameters you must use string::c_str(). However, instead of C-like functions with variable parameters you can use something like boost::format() and it's parameter feeding operator %. This also gives you more control over ordering of parameters, which is very handy for i18n.

compile error: ifstream::open only accepts string values in quotes "" and not string variables

Does open function have some sort of restriction as to what kind of string value is passed in?
ifstream file;
string filename = "output.txt";
file.open(filename);
I tried to pass a string value with a string variable, but when it tries to compile, the result is...
agent.cpp:2:20: error: ofstream: No such file or directory
agent.cpp: In function ‘std::string readingline(std::string)’:
agent.cpp:11: error: aggregate ‘std::ifstream file’ has incomplete type and cannot be defined
agent.cpp: In function ‘int main()’:
agent.cpp:44: error: aggregate ‘std::ofstream writefile’ has incomplete type and cannot be defined
On the other hand, when I just pass a string value in quotes like "filename.txt" , it compile fine and runs fine.
ifstream file;
file.open("output.txt");
Why is this the case?
Is there a way to solve this problem?
Sadly, this is how the constructor and open of std::(i|o)fstream are defined by the standard. Use file.open(filename.c_str()).
Some standard libraries provide an extension that allows std::string as a parameter, e.g. Visual Studio.
I got the problem to go away by including fstream and passing filename.c_str() instead of just filename.
The message about an incomplete type is because you are missing a header (probably anyway, you didn't show a full example).
And open takes a c-style string, not the string class.
I think your error messages may be unrelated to the code in question, but open takes a C-style const char* and not a C++ string. You'll need to use filename.c_str() in the call to make it work correctly.

getline in istream and getline in basic_string

string text;
getline(text.c_str(),256);
1) I am getting an error "error: no matching function for call to 'getline(const char*, int)"
What's wrong in the above since text.c_str() also returns a pointer to array of characters.
If I write like this
char text[256]
cin.getline(text, 256 ,'\n');
it works fine. What's the difference between cin.getline and getline?
2) How come
text string;
getline(cin,text,'\n')
accepts the whole line as the input. Where is the pointer to array of characters in this one?
text.c_str() returns a const char *. You may not use it to modify the contents of the string, in any way. It only exists so that you can pass the string data to old C API functions without having to make a copy. You are not allowed to make changes because there is no way that the string object that holds the data could possibly find out about them, and therefore this would allow you to break the string's invariants.
Furthermore, std::getline accepts completely different parameters. (You would know this if you took two seconds to type 'std::getline' into Google.) The error means exactly what it says: "no matching function for call" means "you can't call the function with these kinds of parameters", because every overload of the function accepts something different (and incompatible).
std::getline accepts these parameters:
A stream. You have to pass this because otherwise it doesn't know where to read from.
A string object to read into. NOT a char buffer.
Optionally, a line delimiter char (same as the stream getline member function).
There is not really any such function as "cin.getline". What you are calling is the member function "getline" of the object "cin" - a global variable that gets defined for you when you #include <iostream>. We normally refer to this according to what class the function is defined in - thus, std::istream::getline.
std::istream::getline accepts these parameters:
A char buffer.
Optionally, a line delimiter char.
It does not need a stream parameter because it is a member function of the stream: it uses whatever stream we called it with.
I don't really get what the questioner is trying to do.
C++ allows function overloading, so the compiler is looking for a free function called getline that matches the parameters you have passed, and no such function exists, nor should it exist (what would getline(const char*, int) do anyway?)
The question has been asked many times why getline(istream&, string&) is a "free" function and not part of the iostream interface. Answers suggested have been that iostream outdates STL or that iostream has no dependent on the basic_string class (anywhere, which is also why opening files is done with raw pointers), and Herb Sutter would commend making getline a free-function because he feels class member functions should be minimal (and std::string has far too many, eg the find functions which could be free ones that use the class).
One thing about that function though is how useful it is as you do not need to pre-allocate a buffer and "guess" how big to make it. (Having said that if you read from a big file into a std::string you could bad_alloc if there are no newlines to be found!).
string::c_str() returns a const char *, not a char *. getline works with a string, so what you want is
string text;
getline(cin, text, '\n');
This version of getline allows the string to grow as much as needed. If you need to limit it to a certain number of characters, you would need to use a vector<char> as in the previous answer.
text.c_str() is an array of const characters. The const means neither you nor any function (including any sort of getline) may write into it.
There's no portable way to use a string as a writeable array of characters. But when necessary, you can use a vector<char> instead:
std::vector<char> buffer(256);
std::size_t len = cin.getline(&buffer[0], buffer.size());
std::string text(&buffer[0], len);
But just using the string overload of getline is probably best here.

Opening a file with std::string

This should be a fairly trivial problem. I'm trying to open an ofstream using a std::string (or std::wstring) and having problems getting this to work without a messy conversion.
std::string path = ".../file.txt";
ofstream output;
output.open(path);
Ideally I don't want to have to convert this by hand or involve c-style char pointers if there's a nicer way of doing this?
In the path string, use two dots instead of three.
Also you may use 'c_str()' method on string to get the underlying C string.
output.open(path.c_str());
this should work:
output.open(path.c_str())
I'm afraid it's simply not possible. You have to use c_str, and yes, it sucks.
Incidentally, using char* also means fstream has no support for Unicode file names... a shame.