1

I have the following code:

char szBuf[256] = "";
std::string szFmt = "You have recieved %s item."
string szName = "Fork";
snprintf(szBuf, sizeof(szBuf), szFmt.c_str(), szName);

I'm trying to combine szFmt with szBuf while combining szFmt with szName according to.However, when I execute this code in win10, I getting such an weird output:

You've received the LÃý item.

And when I try to execute the code in OSX El Capitan, I'm getting the following error

cannot pass object of non-trivial type 'string' throgh variadic function; call will about at runtime

So what is the problem, and how can I solve this?

Note: I checked this question, but in the answer, they are passing directly "Fork", which also works in me; however it doesn't work when I pass it as szName.

Our
  • 986
  • 12
  • 22
  • The second argument to [`snprintf`](http://en.cppreference.com/w/c/io/fprintf) should be the size of the *destination buffer*. In your case it should be `sizeof szBuf`. When you get the size of a `std::string` object, you get the actual size of the `std::string` object, not the size of the string it contains (that would be e.g. `szFmt.length()`). – Some programmer dude Aug 23 '17 at 12:03
  • 2
    You are mixing C and C++ idioms here, which is why you're having a problem. `sizeof(szFmt)` is never going to give you the length of the string; that would be `szFmt.length()`. But really, just drop `snprintf` altogether and use streams. – Cody Gray - on strike Aug 23 '17 at 12:04
  • @Someprogrammerdude Thanks for pointing out, I corrected it but, as you might guess, the problems remains. – Our Aug 23 '17 at 12:05
  • 1
    As for your problem, I recommend you look into [`std::ostringstream`](http://en.cppreference.com/w/cpp/io/basic_ostringstream) instead. – Some programmer dude Aug 23 '17 at 12:05
  • Any reason you're not just using something like: `std::string text = "You have recieved " + name + " item.";`? (name must be a `std::string`) – NathanOliver Aug 23 '17 at 12:07
  • @CodyGray Thanks for suggestiong, but I do not have the freedom to use whatever I want in the project that I'm working with, so ı need to stick to these. – Our Aug 23 '17 at 12:08
  • @NathanOliver Becuase in the original code, the string in szFmt retracted from a .tbl file, so I cannot do that, unless, of course, first split the string in to two and then add szName while combining again, but this is a rather ugly method. – Our Aug 23 '17 at 12:09
  • 2
    You forgot the `.c_str()` part of `szName`. – Andre Kampling Aug 23 '17 at 12:09
  • @AndreKampling Thanks a lot. – Our Aug 23 '17 at 12:11

2 Answers2

5

Better solutions were mentioned in the comments (ostringstream) but for further educational value, I'll address the immediate problem here.

Varargs (the mechanism through which the printf family of functions can accept a variable number of arguments) are not as strictly type checked as the rest. In this case, snprintf is expecting a char* to the string, but you're passing szName which is a string object. So you need to call .c_str() on that as well:

snprintf(szBuf, sizeof(szBuf), szFmt.c_str(), szName.c_str());
Thomas
  • 174,939
  • 50
  • 355
  • 478
1

Using std::ostringstream will simplify things, especially since it's more type-safe than the printf functions inherited from C, but also since it can handle all standard types and with proper overloading of the output operator << you can also use it very easily for custom classes.

The important thing to remember with std::ostringstream is that it is an ordinary output stream, just like std::cout, and if you can use std::cout then you can also use std::ostringstream (or any other standard output stream).

Now for how to use it:

std::ostringstream ostr;  // Define the stream object
ostr << "You have recieved " << szName << " item.";

And that's about it.

To access the string you use the str function:

std::cout << "The output is " << ostr.str() << '\n';

And if you want to copy it into a char buffer for some reason:

// Use `strncpy` to not overflow the destination buffer
std::strncpy(szBuf, ostr.str().c_str(), sizeof szBuf - 1);

// Remember that `strncpy` might not terminate the destination, so do it explicitly
szBuf[sizeof szBuf - 1] = '\0';
Some programmer dude
  • 400,186
  • 35
  • 402
  • 621