What is wrong with this char array to std::string conversion? - c++

I'm trying to convert a char array to an std::string, but I only get gibberish in the std::string. What is wrong?
char char_buff[40];
sprintf_s(char_buff, 40, "test" );
printf("%s\n", char_buff); // prints "test"
std::string str(char_buff);
printf("%s\n", str); // prints random nonsense

Passing a std::string to printf gives undefined behavior.
When you try to print out the string instance, try using std::cout instead:
char char_buff[40];
sprintf_s(char_buff, 40, "test" );
std::cout << char_buff << "\n";
std::string str(char_buff);
std::cout << str << "\n";

std::string str(char_buff);
printf("%s\n", str); // prints random nonsense
The problem is that %s makes printf() expect a const char*; in other words, %s is a placeholder for const char*.
Instead, you passed str, which is an instance of std::string, not a const char*.
To fix that, just use the c_str() method of std::string:
printf("%s\n", str.c_str());
c_str() returns a C-style pointer to a NUL-terminated string, as expected from C functions like printf().
As a side note:
char char_buff[40];
sprintf_s(char_buff, 40, "test" );
Note that sprintf_s() can be used in a simpler form, making it to automatically deduce the destination buffer length, thanks to some template "magic":
sprintf_s(char_buff, "test"); // char_buff size automatically deduced
See this sprintf_s() template from MSDN documentation:
template <size_t size>
int sprintf_s(
char (&buffer)[size],
const char *format [,
argument] ...
); // C++ only

Unfortunately, printf is an old c function and is not type safe. It just interprets the given arguments as you tell it to.
By using the %s as the first occurring format specifier you tell printf to interpret the first argument as a char *, causing gibberish to be printed.
In order to have the contents of the string be printed you need to get to the char* data that the std::string wraps. You can do this using .c_str().

Related

why string has to be converted to c_str (c string) when passing to printf?

I am new to C++
and I know I shouldn't be using printf in c++ while I have cout but this was for experiment sake.
My Question here is Why we have to convert a string to c_str (c string) while passing to printf in c++ while it works fine without converting in cout.
Below is my code
#include<iostream>
#include<stdio.h>
using namespace std;
class A{
int i;
string str;
public:
A (int value, const string & s) : i(value), str(s){};// constructor
// setters
void setvalue(int value) {i = value;}
void setstr(const string & s) {str = s;}
//geters
int get_value() {return i;}
string get_str() {return str;}
const char *get_str_cstr() {return str.c_str();}// I didn't get why we have to declare constant
};
int main(){
// new code
A obj1 = {11, "Jill"};
cout<<"value is : "<<obj1.get_value()<<" string is "<<obj1.get_str()<<endl;
// Now we wil change the values in A
obj1.setvalue(2);
obj1.setstr("Jack");
cout<<"value after change is : "<<obj1.get_value()<<" string after change is "<<obj1.get_str()<<endl;
// now we will use printf where get_str dosen't not work
//Error: for below commented printf function
/*In function 'int main()':|
error: cannot pass objects of non-trivially-copyable type 'std::string {aka class std::basic_string<char>}' through '...'|
||=== Build finished: 1 errors, 0 warnings (0 minutes, 0 seconds) ===|
*/
//printf("Value is %d and String is %s",obj1.get_value(),obj1.get_str());
// hence we declare a new char * get_str_cstr to make it work in printf;
printf("Value is %d and String is %s",obj1.get_value(),obj1.get_str_cstr());
return 0;}
I have also provided the error in program comments.
Thank you!
printf comes from C library, which predates objects, templates, and function overloading. When you specify %s format, the function takes an address of a null-terminated character sequence, and prints it. printf has no idea where the string comes from. In fact, it has no idea of its parameter types, because it uses variable-length parameter list feature.
std::string is a C++ string. Calling c_str() on it produces a pointer to the beginning of a C string, which is suitable for passing to printf and other functions expecting a C string.
cout, on the other hand, has been built with classes and overloading in mind. There is a special overload for operator << for std::string, which lets cout and other output streams extract characters from a C++ string.
printf is originally from C, which does not have std::string, so the analogous argument type is const char* which is what you get when you call .c_str()
The reason std::cout works with std::string is because operator<< is defined for that class.
Because printf() has no idea what a std::string is. The protypes for printf() are
int printf( const char* format, ... );
int fprintf( std::FILE* stream, const char* format, ... );
int sprintf( char* buffer, const char* format, ... );
int snprintf( char* buffer, std::size_t buf_size, const char* format, ... );
The reason std::string works with cout is that std::string provieds operator << which works with cout
string is a class in c++ stl.
c_str() is a member function of class string .
The signature is:
const _CharT* c_str() const { return _M_start; }
now, coming to printf, its signature is:
int printf ( const char * format, ... );
now, as long as you give it an argument that meets const char * format, it accepts it.

Initializing std::string with const char * results in gibberish

I use rapidjson to read JSON files, and some of the values are string. Now, rapidjson's GetString() method returns a const char *. I'd like to store this in std::string, though. I've tried this:
const char* foo = d["foo"].GetString();
printf("Foo: %s\n", foo); // Prints correctly
std::string fooStr(foo);
printf("FooString: %s\n", fooStr); // Gibberish
How do I get the correct std::string?
You can't pass std::string directly to printf. It's a C-style variadic function, that only works with C-compatible types, not (non-trivial) C++ classes. In particular, the %s specifier requires its matching argument to be a pointer to C-style string (a zero-terminated character array), of type const char *.
You can either use a C++ stream:
std::cout << "FooString: " << fooStr << '\n';
or extract a C-style pointer from the string:
printf("FooString: %s\n", fooStr.c_str());
You should also enable compiler warnings; that should tell you exactly what's wrong.
To convert string to const char* use string::c_str()

Converting double to string. Boost Libraries appear not to work, and sstream causes "SEG FAULT"

I have a simple problem, and I think I'm just doing something stupid which is causing a SEGFAULT.
I simply want to convert a double variable to a string, and then 'strcat()' them both together and put the resultant concatenated string in a GTK Label. (It should be simple, surely?!)
Here is a section of my code:
double fps_target = 2.71828
std::string fps_target_string;
std::stringstream convert;
convert << fps_target;
fps_target_string = convert.str();
g_print("seg fault occurs below");
label_fps_target = gtk_label_new(strcat("FPS Target: ",
(const char*) fps_target_string.c_str()));
Why cannot it work?! :(
I tried using the Boost::Lexical_Cast thing, but that didn't work:
double fps_target = 3.14159;
const char* fps_target_string = (const char*) (boost::lexical_cast<std::string>(fps_target));
Any help is greatly appreciated. If either method works that would be awesome, but I'm not really bothered about how to do it, so long as I can get a double to cat with a string!
It shouldn't even compile. Make sure you have your compiler's warning and conformance levels set to high. That will save you much trouble in the long run.
Let us look at strcat's signature:
char *strcat( char *dest, const char *src );
So, it takes a char* as first parameter. But "FPS Target: " has type char const[13] which decays to char const*, which cannot be passed as a char*. char* allows modification, but char const* doesn't (string literals are not mutable!). This first parameter is char* because that's the buffer where the result will be put. You can't put it in that string literal because:
String literals are read-only;
That string literal is not large enough.
The second argument doesn't need a cast, as the return type of c_str() is already char const*.
The simplest way to concatenate strings is to use std::string and not bother with the C library string manipulation functions.
std::string result = "FPS Target: " + fps_target_string;
g_print("seg fault doesn't occur below");
label_fps_target = gtk_label_new(result.c_str());
Since the code is already using a stringstream, an even easier way would be to just insert both parts into the stream.
std::stringstream convert;
convert << "FPS Target: " << fps_target;
std::string result = convert.str();
g_print("seg fault doesn't occur below");
label_fps_target = gtk_label_new(result.c_str());
strcat() uses the first parameter as the output buffer. Of course, strcat("FPS Target: "...) will crash. Allocate a buffer and pass it as a first parameter.
const char* fps_target_string = (const char*) boost::lexical_cast<std::string>(fps_target) won't compile, because there's no conversion from std::string to const char*.

How to use a std::string for a char* output parameter

For any function that is declared to take a char* output parameter, is there a way to specify the "char" part of s std::string as the function's output?
I began with:
// EDIT: ADDED THESE TWO LINES FOR CLARITY
sprintf(buf, "top -n 1 -p %s" , commaSeparatedListOfPIDs.c_str() );
fp = popen(buf, "r");
std::string replyStr;
char reply[100];
rc = scanf( fp, "%s", reply );
replyStr = reply;
but that seems a bit, well, clumsy.
So, is there a way to say:
rc = scanf( fp, "%s", &replyStr.c_str() );
or something like that?
Thanks!
Yes this is possible:
std::string replyStr(100, '\0');
//Requires C++11 (to guarantee that strings hold their characters
//in contiguous memory), and some way to ensure that the string in the file
//is less than 100 characters long.
rc = fscanf( fp, "%s", &reply.front() );
replyStr.erase(replyStr.find('\0'));
The second condition is very difficult to satisfy, and if it is not satisfied this program has undefined behaviour.
Up until c++0x, &str[0] wasn't required to return a pointer to contiguous storage. The conventional way would be to use std::vector, which is guaranteed to have contiguous storage even before c++0x:
std::vector<char> reply(100);
rc = scanf(fp, "%s", &reply[0]);
In c++0x, however, std::string is also guaranteed to work instead of std::vector.
If you want to use strings, why not use the C++ way of i/o as well? Take a look at this link
std::string replyStr(reply); will make a string of your char array.
EDIT:
but... that doesn't do anything different.
Use the c++ style in/out to not have to use char*.
cin >> replyStr; will get the next string until whitespace.
getline(cin,reply); will set the string to an entire line of input
The char* that comes from std::String is only valid as long as the string is valid. If the std::String goes out of scope then the it is no longer a valid char pointer.
const char* bar;
{
std::String foo = "Hello";
bar = foo.c_str();
printf("%s", bar); //SAFE since the String foo is still in scope
}
printf("%s", bar); //UNSAFE String foo is no longer in scope
As long as the std::String variable exists you can use the const char* if it goes out of scope the memory is released and the const char* pointer becomes a dangling pointer that is no longer safe to use.
if you need it to exist after the std::String foo has gone out of scope then you must copy the string into a char*
char bar[100];
{
std::String foo = "Hello";
strncpy(bar, foo.c_str(), 100);
bar[100] = '\0'; //make sure string is null-terminated
printf("%s", bar); //SAFE
}
printf("%s", bar); //SAFE even though the std::String has gone out of scope.
If your string is inside a function it will not exist when the function returns.

got <null> using printf with string

When using printf for string, I got :
string key = "123";
printf("Value is %s \n", key);
// output is: Value is < null >
But if I do it like this:
string key = "123";
printf("Value is: ");
printf(key.c_str());
then I get:
// output is: Value is 123
So what I did wrong with
printf %s
?
Thanks in advance.
std::string is a C++ class. So this doesn't work because:
printf is a pure C function, which only knows how to deal with primitive types (int, double, char *, etc.).
printf is a variadic function. Passing a class type to a variadic function leads to undefined behaviour.1
If you want to display a string, use std::cout:
std::cout << key << "\n";
If you simply must use printf, then this should work:
printf("%s\n", key.c_str());
c_str is a member function which returns a C-style string (i.e. a const char *). Bear in mind that it has some restrictions; you cannot modify or delete the string object in-between calling c_str() and using the result:
const char *p = key.c_str();
key = "something else";
printf("%s\n", p); // Undefined behaviour
1. Or possibly implementation-defined, I don't recall. Either way, it's not going to end well.
The token %s tells printf to expect a null terminating const char*, and you're passing it a std::string.
The correct way would be:
printf("Value is %s \n", key.c_str());
The C++ way would be to use std::cout.
printf is C library function and requires C "string" (char*) for %s format. You have already discovered, that you can do cppstring.c_str() to get this.
Also see this question.
The C style would be
printf("Value is %s \n", key.c_str()); // printf does need a nullterminated char*
The C++ style would be
cout << "Value is %s " << key << endl; // cout can use std::string directly
In addition to the other answers: printf is a variadic function, and passing an object of class type which is not a POD is undefined behavior, and std::string is a class type which is not a POD. Undefined behavior means, of course, that anything can happen, but this one is easy to detect, and a good compiler will at least warn about the error.
cout<< string can work is bacasue of the String class has overloaded the operator "<<",so printf() certainly can't work!