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());
Related
I am now using C++ to program a robot using PROS. Pros has a print function, which is taking in a const char*. Now, I'm using lvgl to create my own screen, and I want to replicate the print function. Like the printf() functions, I want it to include variadic params to do the %d effect (so it converts all the %? to the corresponding values). The problem now is about the conversions between functions. I wanted to make a convert function to convert a string and the variadic params into a complete string. I need to input is a string which is like "hey" and I'm unsure what the type name should be. I need to be able to get size, search in it for %ds but I need the function to return a const char* to pass onto the lvgl to pring on the screen. I am having a bad time trying to convert a string into an const char* for the out put of the convert function.
Also, I tried using the input type as a char*, and when I input a string like "hello" is says a error [ISO C++11 does not allow conversion from string literal to 'char ' [-Wwritable-strings]]. But instead, when is use a const char, the error disappears. Anyone knows why?
Thanks everyone for your kind help!
char* and const char* are two flavours of the same thing: C-style strings. These are a series of bytes with a NUL terminator (0-byte). To use these you need to use the C library functions like strdup, strlen and so on. These must be used very carefully as missing out on the terminator, which is all too easy to do by accident, can result in huge problems in the form of buffer-overflow bugs.
std::string is how strings are represented in C++. They're a lot more capable, they can support "wide" characters, or variable length character sets like UTF-8. As there's no NUL terminator in these, they can't be overflowed and are really quite safe to use. Memory allocation is handled by the Standard Library without you having to pay much attention to it.
You can convert back and forth as necessary, but it's usually best to stick to std::string inside of C++ as much as you can.
To convert from C++ to C:
std::string cppstring("test");
const char* c_string = cppstring.c_str();
To convert from C to C++:
const char* c_string = "test";
std::string cppstring(c_string);
Note you can convert from char* (mutable) to const char* (immutable) but not in reverse. Sometimes things are flagged const because you're not allowed to change them, or that changing them would cause huge problems.
You don't really have to "convert" though, you just use char* as you would const char*.
std::string A = "hello"; //< assignment from char* to string
const char* const B = A.c_str(); //< call c_str() method to access the C string
std::string C = B; //< assignment works just fine (with allocation though!)
printf("%s", C.c_str()); //< pass to printf via %s & c_str() method
I'm getting warnings when I compile something like this...
std::string something = "bacon";
sprintf("I love %s a lot", something.c_str());
Where it says "warning: deprecated conversion from string constant to 'char *'. I tried converting the text to be...
const char *
instead but I get a different error. I'm not committed to sprintf if there is a better option.
For sprintf to work, you need to provide an array of char big enough to write the result to as the first argument.
However, you can (and should!) just use the far easier operator+ for C++ strings:
std::string res = "I love " + something + " a lot";
sprintf("I love %s a lot", something.c_str);
In that code, you should call something.c_str() with proper function call () syntax.
Note also that the above use of sprintf() is wrong, since you didn't provide a valid destination string buffer for the resulting formatted string.
Moreover, for security reasons, you should use the safer snprintf() instead of sprintf(). In fact, with snprintf() you can specify the size of the destination buffer, to avoid buffer overruns.
The following compilable code is an example of snprintf() usage:
#include <stdio.h>
#include <string>
int main()
{
std::string something = "bacon";
char buf[128];
snprintf(buf, sizeof(buf), "I love %s a lot", something.c_str());
printf("%s\n", buf);
}
P.S.
In general, in C++ you may consider string concatenation using std::string::operator+, e.g.:
std::string result = "I love " + something + " a lot";
It doesn't look like a correct use of sprintf.
First parameter is supposed to be a char * with already a backing memory.
For example:
char *str = malloc (BUFSIZ);
sprintf (str, "I love %s a lot", something.c_str);
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()
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!
I understand c_str converts a string, that may or may not be null-terminated, to a null-terminated string.
Is this true? Can you give some examples?
c_str returns a const char* that points to a null-terminated string (i.e., a C-style string). It is useful when you want to pass the "contents"¹ of an std::string to a function that expects to work with a C-style string.
For example, consider this code:
std::string string("Hello, World!");
std::size_t pos1 = string.find_first_of('w');
std::size_t pos2 = static_cast<std::size_t>(std::strchr(string.c_str(), 'w') - string.c_str());
if (pos1 == pos2) {
std::printf("Both ways give the same result.\n");
}
See it in action.
Notes:
¹ This is not entirely true because an std::string (unlike a C string) can contain the \0 character. If it does, the code that receives the return value of c_str() will be fooled into thinking that the string is shorter than it really is, since it will interpret \0 as the end of the string.
In C++, you define your strings as
std::string MyString;
instead of
char MyString[20];.
While writing C++ code, you encounter some C functions which require C string as parameter.
Like below:
void IAmACFunction(int abc, float bcd, const char * cstring);
Now there is a problem. You are working with C++ and you are using std::string string variables. But this C function is asking for a C string. How do you convert your std::string to a standard C string?
Like this:
std::string MyString;
// ...
MyString = "Hello world!";
// ...
IAmACFunction(5, 2.45f, MyString.c_str());
This is what c_str() is for.
Note that, for std::wstring strings, c_str() returns a const w_char *.
Most old C++ and C functions, when dealing with strings, use const char*.
With STL and std::string, string.c_str() is introduced to be able to convert from std::string to const char*.
That means that if you promise not to change the buffer, you'll be able to use read-only string contents. PROMISE = const char*
In C/C++ programming there are two types of strings: the C strings and the standard strings. With the <string> header, we can use the standard strings. On the other hand, the C strings are just an array of normal chars. So, in order to convert a standard string to a C string, we use the c_str() function.
For example
// A string to a C-style string conversion //
const char *cstr1 = str1.c_str();
cout<<"Operation: *cstr1 = str1.c_str()"<<endl;
cout<<"The C-style string c_str1 is: "<<cstr1<<endl;
cout<<"\nOperation: strlen(cstr1)"<<endl;
cout<<"The length of C-style string str1 = "<<strlen(cstr1)<<endl;
And the output will be,
Operation: *cstr1 = str1.c_str()
The C-style string c_str1 is: Testing the c_str
Operation: strlen(cstr1)
The length of C-style string str1 = 17
c_str() converts a C++ string into a C-style string which is essentially a null terminated array of bytes. You use it when you want to pass a C++ string into a function that expects a C-style string (e.g., a lot of the Win32 API, POSIX style functions, etc.).
It's used to make std::string interoperable with C code that requires a null terminated char*.
You will use this when you encode/decode some string object you transfer between two programs.
Let’s say you use Base64 to encode some array in Python, and then you want to decode that into C++. Once you have the string you decode from Base64-decoded in C++. In order to get it back to an array of float, all you need to do here is:
float arr[1024];
memcpy(arr, ur_string.c_str(), sizeof(float) * 1024);
This is pretty common use, I suppose.
const char* c_str() const;
It returns a pointer to an array that contains a null-terminated sequence of characters (i.e., a C string), representing the current value of the string object.
This array includes the same sequence of characters that make up the value of the string object plus an additional terminating null - character ('\0') at the end.
std::string str = "hello";
std::cout << str; // hello
printf("%s", str); // ,²/☺
printf("%s", str.c_str()); // hello