0

Having simple code like below:

using namespace std;
...
string str = "Abc";
string* str_ptr = &str;
str_ptr[0] = 'D';

sprintf_s(MsgBuff, 300, "%s", str_ptr);
OutputDebugStringA(MsgBuff);

The output is just D, not as i expected Dbc?

Doing the similar things with C style strings:

char str[] = "Abc";
char* str_ptr = str;
str_ptr[0] = 'D';

Indead returns Dbc.

Mooing Duck
  • 64,318
  • 19
  • 100
  • 158
Derek81
  • 145
  • 9

3 Answers3

0

%s in sprintfs format string expects a C-style string and nothing else. Your code should therefore be something like:

string str = "Abc";
char *char_ptr = str.data ();
char_ptr[0] = 'D';
sprintf_s(MsgBuff, 300, "%s", char_ptr);
OutputDebugStringA(MsgBuff);
Paul Sanders
  • 24,133
  • 4
  • 26
  • 48
  • OK, that works, but what when i'd like to use string data type pointer (`string* str_ptr = &str`)? – Derek81 Aug 29 '20 at 21:30
  • Well, you can't. You could, however, do `str [0] = 'D';` – Paul Sanders Aug 29 '20 at 21:30
  • So doing `string* str_ptr = &str` we just creating a pointer to the "string" class an is completly different what the C style poiner (`char str[] = "Abc"; char* str_ptr = str;`) to char is? – Derek81 Aug 29 '20 at 21:38
  • @Derek81: The first is a pointer to `std::string`. the second one you would expect to be a pointer to `char[]`, but due to quirks in C, the `char[]` sometimes pretends to be a `char*`, so `str_ptr` ends up a pointer to the _characters_, instead of a pointer to a C-String like you'd expect. It's not `std::string`, behaving weird, it's `char[]` that behaves weird. – Mooing Duck Aug 29 '20 at 21:44
0

First of all, pointers of string type are not the same as pointers of char type. You can refer to the following code.

#include <iostream>
using namespace std;
int main(int argc, const char* argv[])
{
    string* s = new string("Abc");
    cout << s << endl;
    cout << *s << endl;
    return 0;
}

Output:

enter image description here

And *s is the same as str[0], so the str_ptr[0] ='D' you write will overwrite the original string.

Also, when you use str_ptr directly, you are using its address instead of its elements, which is different from using:

char* str_ptr = str;
str_ptr[0] = 'D';

The string is different from the char type string in the C language. The string pointer points to a class object. If you want to modify the content of the string through the string pointer, you can try the following code:

string* str_ptr = &str;
str_ptr->at(0) = 'D';

And you cannot directly use str_ptr as the parameter of %s, it should be str_ptr->c_str().

Here is the complete sample:

#include <iostream>
#include <windows.h>
#include <WinUser.h>
using namespace std;

int main(int argc, const char* argv[])
{
    string str = "Abc";
    string* str_ptr = &str;
    str_ptr->at(0) = 'D';

    char MsgBuff[300];
    sprintf_s(MsgBuff, 300, "\nMSG = %s\n", str_ptr->c_str());
    OutputDebugStringA(MsgBuff);

    return 0;
}

And it works for me:

enter image description here

Zeus
  • 3,703
  • 3
  • 7
  • 20
-1
string str = "Abc";
string* str_ptr = &str;
str_ptr[0] = 'D';

is the same as

string str = "Abc";
string* str_ptr = &str;
*str_ptr = 'D';

is the same as

string str = "Abc";
str = 'D';

std::string has an overloaded operator= for assigning a char value, which is why the string becomes "D" and not "Dbc".

However, sprintf_s(MsgBuff, 300, "%s", str_ptr); is undefined behavior, as %s expects a char* pointer to a null-terminated C string, which str_ptr is not.

So, the only possible way that str_ptr could produce a viable null-terminated C string when misinterpreted as a char* in this example is if your compiler's std::string class implements Short String Optimization, and its SSO buffer is the 1st data member in the class. Both of which are implementation details that you can't rely on when writing standards-compliant code.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770