Getting garbage out from getline - c++

I'm getting garbage out from getline but I'm not sure what I'm doing wrong.
Here is the code:
std::string str = "/command?device=c53b1f8&zoom=24&tilt=80";
std::istringstream ss(str);
std::string buf;
while (std::getline(ss, buf, '&'))
{
printf("%s\n", buf);
}
Output:
á╚╢ºA
á╚╢ºA
á╚╢ºA

Your bug is here:
printf("%s\n", buf);
std::printf() is a C language function, it is meant for C-style null-terminated strings. It does not understand std::string at all. Using it the way you are is undefined behavior. Your weird result is caused by printing the internal structure of the std::string up to the first 0x00 byte encountered in memory.
The correct solution is to use std::cout instead:
std::cout << buf << '\n';
However, if you want to stick to using printf() then you can have std::string output a C-style string using its c_str() method, like this:
std::printf("%s\n", buf.c_str());

Related

Why am I getting these symbols in console, using printf()? [duplicate]

This question already has answers here:
printf with std::string?
(9 answers)
Read into std::string using scanf
(7 answers)
Closed 10 months ago.
I have question about output in console
string str;
scanf("%s", str);
printf("%s", str);
Why do I get strange symbols, which have trouble with encoding?
std::string is a class (user-defined type). On the other hand, the conversion specifier s is designed to input or output character arrays. So the code snippet has undefined behavior.
Instead you could use operators >> and << overloaded for the class std::string to input or output data from/to streams like
std::string str;
std::cin >> str;
std::cout << str << '\n';
If you want to use the functions scanf and printf then use character arrays as for example
char str[100];
scanf( "%99s", str );
printf( "%s\n", str );
If as you wrote in a comment
I have a task, out string with help printf.
then in this case you should check whether string is indeed the standard C++ type or an alias for the type char * introduced like for example
typedef char *string;
or like
using string = char *;
printf and scanf expect variables of type [const] char * with an "%s" format specifier.
In general, the other answer to use std::cin / std::cout instead is preferrable.
If you absolutely must use printf to output a std::string, use the c_str() method to get access to a const char * representing the same string as in the std::string; example:
string str;
std::cin >> str;
printf("%s", str.c_str());
Note the const in const char* c_str() - meaning you are not allowed to change the returned string. So, it cannot be used for scanf. There, you'd have to stick to a char *...

Why does returning a C-string from a function result in random characters?

I've had to stop coding so many projects because of this weird quirk that I'm fed up enough to ask and risk looking like an idiot, so here goes...
I wrote a function like this:
const char* readFileToString(const char* filename) {
const char* result;
std::ifstream t(filename);
std::stringstream buffer;
buffer << t.rdbuf();
result = buffer.str().c_str();
return result;
}
I would expect that, if file.txt contains hello, that readFileToString("file.txt") should return hello. Instead, it returns garbled text, something along the lines of H�rv�0. However, if I put a std::cout << result; just before the return, it'll print hello.
Is this some weird, impossible quirk with C++? How do I fix it?
It's neither weird nor impossible; you returned a pointer to a buffer that went out of scope. The const char* doesn't "own" the string data, it only refers to it. Or, it used to! Once returned, that pointer is now invalid. You shall not dereference it.
I suggest you stick with std::string instead of venturing into advanced pointer techniques.
std::string readFileToString(const char* filename)
{
std::ifstream t(filename);
std::stringstream buffer;
buffer << t.rdbuf();
return buffer.str();
}
Unfortunately, I am not aware of any way to avoid a copy here.
If you don't mind shuffling your design about a little, and if you have some way to avoid a stream-to-string copy down the line, you could do this instead:
void readFileToStream(const char* filename, std::ostream& os)
{
std::ifstream t(filename);
os << t.rdbuf();
}
You may wish to return bool signifying the stream's state, but again you can do that at the callsite anyway.
Please see the commentary below:
const char* readFileToString(const char* filename) {
const char* result;
std::ifstream t(filename);
std::stringstream buffer; // Behind the scenes some memory will/is allocated
buffer << t.rdbuf(); // Memory is getting filled
result = buffer.str().c_str(); // Getting the address of that memory
return result;
// Buffer getting destroyed along with the allocated memory (what result points to)
}
.. Here results points to an invalid memory location
So hence it being corrupted

sprintf' : cannot convert parameter 1 from 'const char *' to 'char *'

std::string mystring;
sprintf(mystring.c_str(), "%s %d", "Helloworld", 2014);
Its is giving a compiler error to me:
'sprintf' : cannot convert parameter 1 from 'const char *' to 'char *'
It shouldn't be a warning, it should be an error. The pointer
returned by std::string::c_str() points to read-only memory;
any attempt to write through it is undefined behavior. (In your
case, if you use a const_cast to shut up the compiler, you're
code will probably crash, since you're calling c_str() on an
empty strying.)
Generally speaking, what you probably want is
std::ostringstream:
std::ostringstream formatter;
formatter << "Helloworld" << ' ' << 2014;
std::string myString = formatter.str();
FWIW: sprintf is one of the most dangerous functions in the
standard library, and only present for historical reasons. It's
almost impossible to use safely; even in C, you should prefer
snprintf (but in C++, std::ostringstream is far better).
your warning gives you all information you need.
std::string::c_str() returns a const char* and sprintf requires a char* since it modiefies the buffer.
But you are writing c++ and should avoid sprintf. Use a ostringstream to write formated data to a string.
std::string manages underlying C-style buffer. c_str returns const char* because it shouldn't be modified by anything other then string's methods.
You should rather use ostringstream. See this question: C++ equivalent of sprintf?
You are telling sprintf to store the result in mystring.c_str(). This is a readonly view of the underlying representation of mystring. Since it is readonly (or const char *), you can't write the result to it.
If you need to use sprintf, you will have to create a writable character buffer for it to use, and then assign that buffer to mystring.
A different way of performing this sort of operation without having to create character buffers and deal with possible overflow would be to use a stringstream:
std::stringstream buffer;
buffer << "Helloworld " << 2014;
mystring = buffer.str();
Alternatively, use old C snprintf into a temporary buffer, then assign into the string :
std::string mystring;
char buf[64];
snprintf(buf, sizeof(buf), "%s %d", "Helloworld", 2014);
mystring.assign(buf);
snprintf is always safer than sprintf since it avoids buffer overflow.
But of course using an ostringstream like answered here by James Kanze is better.
#include <iostream>
#include <string>
#include <sstream>
std::stringstream ss;
ss << "Helloworld";
ss << " ";
ss << "2014";
ss << std::endl;
std::string str = ss.str();
std::cout << str;
const char * mystring= str.c_str();
In this way also you can append int or long number into the string.
Example:
long year = 2014;
std::stringstream ss;
ss << "Helloworld";
ss << " ";
ss << year;
ss << std::endl;
std::string str = ss.str();
std::cout << str;
const char * mystring= str.c_str();

std::ostringstream isn't returning a valid string

I'm trying to use std::ostringstream to convert a number into a string (char *), but it doesn't seem to be working. Here's the code I have:
#include <windows.h>
#include <sstream>
int main()
{
std::ostringstream out;
out << 1234;
const char *intString = out.str().c_str();
MessageBox(NULL, intString, intString, MB_OK|MB_ICONEXCLAMATION);
return 0;
}
The resulting message box simply has no text in it.
This leads me to believe that the call to out.str().c_str() is returning an invalid string, but I'm not sure. Since I've trimmed this program down so far an am still getting the problem, I must have made an embarrassingly simple mistake. Help is appreciated!
out.str() returns a std::string by value, which means that you are calling .c_str() on a temporary. Consequently, by the time intString is initialized, it is already pointing at invalid (destroyed) data.
Cache the result of .str() and work with that:
std::string const& str = out.str();
char const* intString = str.c_str();

How to pass variable in C++ Sprintf 2nd(format) argument?

I've been cracking heads on how to achieve this in C++:
string format = "what is your %s";
new_string = sprintf(buffer, format, name);
Any help would be very much appreciated.
Thanks!
Use format.c_str():
string format = "what is your %s";
int total = sprintf(buffer, format.c_str(), name);
Also note the returned value is not the new string, it is the buffer which is the output string. The returned value is actually the total number of characters written. This count does not include the additional null-character automatically appended at the end of the string. On failure, a negative number is returned (see doc here).
But in C++, std::ostringstream is better and typesafe, as #Joachim explained in his answer.
Use ostringstream:
std::ostringstream os;
os << "what is your " << name;
std::string new_string = os.str();
You could always do something like:
char buffer[100];
string format = "what is your %s";
sprintf(buffer, format.c_str(), name.c_str());
string new_string(buffer);
Alternatively, use a stringstream:
stringstream buf;
buf << "what is your " << name;
string new_string = buf.str();
The format passed to sprintf must be a char*, not a std::string.
sprintf also returns the number of characters written, not a pointer to the constructed buffer.
int len = sprintf(buffer, "what is your%s", name);
std::string new_string(buffer, len);
Another possibility would be to use std::ostringstream to perform your formatting.
I'm not sure I understand the problem here - sprintf is a function that takes in a char* as its first argument, and a const char* as its second. These are both C data types, and so I don't know if using a C++ string will be recognised by the compiler as valid.
Also, the function returns an int (the number of characters written), not a string, which it looks like you're expecting with a return value like new_string.
For more information, you can look at http://www.cplusplus.com/reference/clibrary/cstdio/sprintf/
You may use stringstream form the C++ STL which is more OO.
Check out the documentation.
sprintf is part of the C library, and thus don't know anything about std::string. Use char* instead if you still want to use it.
To get the C char* string from an std::string, uses c_str method.