got <null> using printf with string - c++

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!

Related

Gibberish is printed while reading from a file and writing to another [duplicate]

In the following code:
#include <string>
using namespace std;
int main(){
char command[300];
string stringz = "mystringy";
sprintf(command,"echo \"something with a string %s\" ", stringz);
system(command);
return 0;
}
why is the output
something with a string 8�
rather than the expected
something with a string mystringy
A silly question, but I couldn't find an answer around.
The '%s' modifier of printf takes a char*, not a std::string.
You can write:
sprintf(command,"echo \"something with a string %s\" ", stringz.c_str());
Which gives you a const char* to the contents of a std::string. This shows one of the major weaknesses of sprintf -- no type checking!
sprintf format %s expects a C string, that's a 0-terminated array of char, not a std::string.
stringz.c_str() and since C++11 &stringz[0] and stringz.data() are a few ways to get at the C string held by the std::string.
To add on Deduplicator answer, try putting
sprintf(command,"echo \"something with a string %s\" ", stringz.c_str());
and you should be set.
This is because sprintf is expecting a char * as an argument to expand the %s token. It would work like
sprintf(command,"echo \"something with a string %s\" ", stringz.c_str());
Which passes the "char *" version of the string to sprintf.
The reason why it shows those strange characters is because the whole std::string object is copied into sprintf's stack frame. Then, sprintf, which accepts variable number of arguments, looks into its own stack space and assumes that what it is going to find there is a char *, but actually is some garbage that results from reinterpreting the string data as char *, and when it is dereferenced, it results into that sequence. It could as well segfault if you are unlucky.
You should not use sprintf in the first place. This is C++, not C. std::string supports concatenation in a very natural way, with the + operator, like in some other programming languages:
#include <string>
int main(){
std::string stringz = "mystringy";
std::string command = "echo \"something with a string " + stringz + "\" ";
system(command.c_str());
return 0;
}
If you insist on using char-array functions like sprintf, use stringz.c_str(). As a matter of fact, this is also what system requires. But note how my example converts the string only at the last possible occasion.
You can use:
sprintf(command,"echo \"something with a string %s\" ", stringz.c_str());
Note that %s takes the C strings and not std::string.
Better still use, iostreams:
string stringDemo("MYSTRING");
std::cout << stringDemo << "\n";

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()

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

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().

printf() confusion - printing (null) when trying to print string and printing correct value when printing buffer

see simplified code - I'm confused...
#include <stdio.h>
#include <string>
#include <cstdlib> // includes the standard library and overarchs over stdlib.h
using namespace std;
void main()
{
char buffer[10];
string theString;
int i = 997799; //(simplified)
itoa(i,buffer,10);
theString = buffer;
printf("\n string is: %s of length %d \n", theString, theString.length());
printf("\n buffer is: %s of length %d \n", buffer, theString.length());
return;
}
The Output I get is unexpected:
string is: (null) of length 926366009
buffer is: 997799 of length 6
(1) why is the string printing as null?
(2) why is theString.length() not printing properly in the first printf() but is right in the 2nd?
(3) if I set breakpoints in visual studio 'buffer' appears as "997799" while 'theString' appears as {"997799"} - something weird going on here?
Thanks folks!
Edit I greatly appreciate the level of detail of the provided answers - they all added clarity and helped me go beyond my issue - many thanks for the time you spent helping out :)
When you use the %s specifier with printf() you promise to pass a char const* as the corresponding argument. Passing anything except a char const* or something which decays into a char const* is undefined behavior. Certainly, passing a C++ object will have undefined behavior.
The proper way to pass a std::string to printf() is to use the %s format specifier and use the c_str() member, e.g.:
printf("string=%s\n", s.c_str());
You are using %d as a format specifier for std::string::size_type. That will probably work but it isn't guaranteed to work! Although std::string::size_type is guaranteed to be std::size_t, this type may be unsigned int, unsigned long, unsigned long long, or even some non-standard built-in integral type! The proper way to spell the format specifier for std::size_t is %zu (and certainly not %ul as in another post: it was probably meant to be %lu which is, however, still wrong:
printf("string.size()=%zu\n", s.size());
Since you are using C++, you are probably better off having the compiler figure out what formatting to call:
std::cout << "\n string is: " << theString << " of length " << theString.length() << " \n";
std::cout << "\n buffer is: " << buffer << " of length " << theString.length() << " \n";
The program has undefined behaviour because function printf is unable to output objects of type std::string. When format symbol %s is used the function supposes that the corresponding argument is a pointer of a string literal. So the function tries to output the object of type std::string as a string literal.
To use correctly function printf with objects of type std::string you should convert them to strings using member function c_str() or data() (for C++ 2011). For example
printf("\n string is: %s of length %ul \n", theString.c_str(), theString.length());
As another answer pointed out, the reason for the (null) value is because the (formal) printf %s expects a const char* for its input, a std::string is not a const char* and results in undefined behavior... The reason for the random number when you do your first theString.length() has to do with your compiler.
On OpenBSD 5.1 with g++ 4.2.1, when I compile the code I get numerous warnings; one in particular is use of itoa, I had to change to sprintf, I also get the following warning about %s with printf on a std::string: warning: cannot pass objects of non-POD type 'struct std::string' through '...'; call will abort at runtime.
When I run the compiled code it aborts and core dumps at the first printf because of the call to %s on a std::string 'object' (which is the 'correct' behavior though technically still 'undefined behavior')
However, when I compile the above code (without edits) on an MS compiler, I actually get the following output:
string is: 997799 of length 6
buffer is: 997799 of length 6
Which is still 'undefined' but the 'expected' results.
So apparently the MS compiler recognizes the std::string on a printf and 'changes' it to a string.c_str() call OR the printf in the MS C/C++ library accepts a std::string and calls the .c_str() for you.
So to be 100% 'compatible' and C++ 'compliant' consider the following:
#include <iostream>
#include <sstream>
int main(int argc, char **argv)
{
std::stringstream theString;
int i = 997799; //(simplified)
theString << i;
std::cout << "string is: " << theString.str() << " of length " << theString.str().length() << std::endl;
// printf("string is: %s of length %d \n", theString.str().c_str(), theString.str().length());
return 0;
}
It's usually not good practice to mix C++ and C calls/styles, but IMHO I use printf a lot for it's 'convenience' but usually take it out or use some #defines for debug build use only.
I hope that can help answer the 'why for #2'
My compiler (clang on os x) reports the following errors:
c++ foo.cc -o foo
foo.cc:6:1: error: 'main' must return 'int'
void main()
^~~~
int
foo.cc:11:5: error: use of undeclared identifier 'itoa'
itoa(i,buffer,10);
^
foo.cc:14:48: error: cannot pass non-POD object of type 'string' (aka
'basic_string<char, char_traits<char>, allocator<char> >') to variadic
function; expected type from format string was 'char *'
[-Wnon-pod-varargs]
printf("\n string is: %s of length %d \n", theString, theString.length());
~~ ^~~~~~~~~
foo.cc:14:48: note: did you mean to call the c_str() method?
printf("\n string is: %s of length %d \n", theString, theString.length());
^
.c_str()
foo.cc:14:59: warning: format specifies type 'int' but the argument has type
'size_type' (aka 'unsigned long') [-Wformat]
printf("\n string is: %s of length %d \n", theString, theString.length());
~~ ^~~~~~~~~~~~~~~~~~
%lu
foo.cc:15:56: warning: format specifies type 'int' but the argument has type
'size_type' (aka 'unsigned long') [-Wformat]
printf("\n buffer is: %s of length %d \n", buffer, theString.length());
~~ ^~~~~~~~~~~~~~~~~~
%lu
Let's fix them:
void main() { ... } should be int main() { ... }.
itoa() is not standard in C++. There is std::stoi() though, so let's use that instead. We could also use std::snprintf if we are writing to a character array, and not a std::string.
If we're going to use printf() with a std::string, we will need to use the std::string::c_str() method to return a character array and print that instead. printf itself doesn't understand C++ objects. (We could also use cout, which does understand c++ objects).
These changes cause the code to look like:
#include <cstdio>
#include <string>
#include <cstdlib>
using namespace std;
int main()
{
char buffer[10];
string theString;
int i = 997799; //(simplified)
snprintf(buffer, sizeof(buffer), "%d", i);
theString = buffer;
printf("string is: %s of length %lu\n", theString.c_str(), theString.length());
printf("buffer is: %s of length %lu\n", buffer, strlen(buffer));
}
And this code outputs:
[4:46pm][wlynch#watermelon /tmp] ./foo
string is: 997799 of length 6
buffer is: 997799 of length 6

Converting sqlite result to std::string in C++

Im querying a sqlite db, but i need to convert the result (a TEXT attribute) to a C++ std::string. I feel like this should not be hard to accomplish, but im having trouble.
sqlite3_open("sqlite.db", &db);
std::string str = "SELECT something FROM table";
sqlite3_prepare_v2(db,
str.c_str(),
-1,
&m_statement,
0);
sqlite3_step(m_statement);
// OBS: 3rd party printf, cannot use std::cout in this environment
printf("Result1: %s",sqlite3_column_text(m_statement,0)); // OK! Result is printed
string try1 = string(
reinterpret_cast<const char*>(sqlite3_column_text(m_statement,0)));
printf("Result2: %s",try1); // null
stringstream ss;
ss << sqlite3_column_text(m_statement,0);
printf("Result3: %s",ss.str()); // null
Your problem isn't related to sqlite. When you use %s with printf, printf expects a char * NOT a std::string.
For example change this:
printf("Result2: %s",try1); // null
to
printf("Result2: %s",try1.c_str());
and see what happens.
C++ has two primary ways of implementing strings. The legacy C string (char*) and the std::string class found in the C++ standard library. If you deal with C APIs, you'll be dealing mostly with the former. printf and sqlite* are both from C APIs, so expect to deal with char*.
The problem is not with sqlite3_column_text.
printf format specifier %s expects a C string (char pointer).
As printf can't inspect what values are passed on the stack, so it has to trust the format specifier. Because the format specifier is %s, it reads an argument as it was a char pointer (it's not), but by coincidence, it's printing the wrong result, rather than crashing.
std::string exposes a function that gets you a read-only corresponding C string, so, for example, your the second case will be:
// Get a C string from std::string
printf("Result2: %s", try1.c_str());