Could somebody possibly breakdown the proper way to pass a string to a function, have that function put it into a vector and another function print contents of the vector? I'm sure there are tons of duplicates and I have looked at them all(mostly) and still have not been able to apply any of it to this problem, or at least it seems that way to me.
#include <cstdio>
#include <string>
#include <vector>
using namespace std;
static vector<string> added_messages;
static void addMessage(string message);
static void displayMessages();
int main()
{
string message = "Testing 1 2 3";
addMessage(message);
//printf("%s\n", message);
return 0;
}
void addMessage(string s)
{
added_messages.push_back(s);
//printf("%s\n", s);
}
void displayMessages()
{
if (added_messages.size() != 0) {
for (string i : added_messages)
printf("%s\n", i);
}
added_messages.clear();
}
It mostly prints out garbage:4÷/4⌠/
I'm fairly new to C++ and coming from Java, I just can't figure this out. Thanks.
Get in the habit of declaring string parameters as const reference.
Instead of this:
void addMessage(string s)
{
...
}
This:
void addMessage(const string& s)
{
...
}
Not only does this avoid making a copy of the string, it also lets you pass string instances as well as string literals and char* variables that point to strings. That is, the above enables all of the following:
addMessage("Foobar");
const char* psz = <some other string>
addMessage(psz);
std::string s = "A string";
addMessage(s);
And then to print the string correctly with printf, use the .c_str() member function to get the pointer address of the contents.
Instead of this:
printf("%s\n", s);
This:
printf("%s\n", s.c_str());
And it goes without saying that cout is preferred over printf:
cout << s << endl;
Putting it altogether:
static vector<string> added_messages;
static void addMessage(const string& message);
static void displayMessages();
int main()
{
string message = "Testing 1 2 3";
const char* psz = "Yet, another messsage);
addMessage(message);
addMessage("Another Message as a string literal);
addMessage(psz);
// sample printf statements
printf("%s\n", message.c_str());
printf("%s\n", psz);
// sample cout statements - notice it can handle both pointers and string instances
cout << message << endl;
cout << psz << endl;
cout << "Hello World" << endl;
return 0;
}
void addMessage(const string& s)
{
added_messages.push_back(s);
printf("%s\n", s.c_str());
}
void displayMessages()
{
for (const string& i : added_messages)
{
printf("%s\n", i.c_str());
}
added_messages.clear();
}
You can't use printf("%s") on string() object - this is the reason you are having the garbage in the output. "%s" expects C string, ie a pointer to char ended with a zero byte.
If you need to print a string() object, use c_str() method to get a C string representation, ie in your case i.c_str(). C++ is mixing C concepts with C++ concepts, so be aware. Use iostream header and std::cout << i to output your object is a C++ way.
About argument passing. In your example, you are doing it okay, but keep in mind that in your case you are doing it by value, ie a copy of the object is created. More efficient is passing by reference.
This should work:
for(std::size_t i = 0; i < added_messages.size(); i++)
printf("%s\n",added_messages[i].c_str());
Related
I've tried to convert an integer to a hex null-terminated (or "C-style") string but I cannot use it with printf or my custom log function. It only works if I convert it to an std::string then use .c_str() when passing it as a parameter, which produces ugly, hard-to-understand code.
It's important to know that using std::string and appending to it with "str +=" does work.
const char* IntToHexString(int nDecimalNumber) {
int nTemp = 0;
char szHex[128] = { 0 };
char hex[] = { '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' };
while (nDecimalNumber > 0) {
nTemp = nDecimalNumber % 16;
sprintf(szHex, "%s%s", hex[nTemp], szHex);
nDecimalNumber = nDecimalNumber / 16;
}
sprintf(szHex, "0x%s", szHex);
return szHex;
}
I've tried to use Visual Studio Debugger but it doesn't show any error messages, because crashes somewhere in a DLL that has no symbols loaded
Your main problem is that you define a variable on the stack, locally in the function, and then return it.
After the function returns, the char* will point to "somewhere", to an undefined position. That is a major bug. You have also other bugs that have been commented on already. Like sprintf(szHex, "0x%s", szHex);, which is undefined behaviour (UB) or sprintf(szHex, "%s%s", hex[nTemp], szHex); which has the same problem + additionally a wrong format string.
The more C++ solution would be, as already shown in many posts:
#include <iostream>
#include <string>
#include <iomanip>
#include <sstream>
std::string toHexString(unsigned int hexValue)
{
std::ostringstream oss;
oss << "0x" << std::hex << hexValue;
return std::string(oss.str());
}
int main()
{
std::cout << toHexString(15) << '\n';
// or directly
std::cout << "0x" << std::hex << 15 << '\n';
return 0;
}
Of course a C-Style solution is also possible.
But all the following I would not recommend:
If you want to stick to C like solution with char *, you could make the char szHex[128] = { 0 }; static. Or, even better, pass in the pointer to a buffer and return its address, like in
#include <stdio.h>
#include <iostream>
char* toHexCharP(unsigned int hexValue, char *outBuffer, const size_t maxSizeOutBuffer)
{
snprintf(outBuffer,maxSizeOutBuffer-1,"0x%X",hexValue);
return outBuffer;
}
constexpr size_t MaxBufSize = 100U;
int main()
{
char buf[MaxBufSize];
std::cout << toHexCharP(15, buf, MaxBufSize) << '\n';
return 0;
}
But as said, I would not recomend. Too dangerous.
Your solution should look as follows:
std::string IntToHexString(int nDecimalNumber) {
std::ostringstream str;
str << std::hex << nDecimalNumber;
return str.str();
}
// ...
std::string transformed = IntToHexString(123);
You can then use transformed.c_str() to get your string as const char*.
Unless you have reasons to do so, you should never work with const char* in modern C++. Use std::string::c_str() if you need to.
What is the right way of passing NULL string to a function without creating a variable?
I see compilation error with following code and I don't want to change the definition. Also may have to make change to string so don't want to mark it a constant type.
#include <iostream>
#include <string>
using namespace std;
void
myfunc(int i, string &my) {
if (my.empty()) {
cout << "Empty" << endl;
} else {
cout << "String is " << my <<endl;
}
}
int main ()
{
std::string str1 ("Test string");
myfunc(1, str1);
std::string str2 ("");
myfunc(2, "");
return 0;
}`
my1.cpp:18: error: invalid initialization of non-const reference of type ‘std::string&’ from a temporary of type ‘const char*’
my1.cpp:6: error: in passing argument 2 of ‘void myfunc(int, std::string&)
’
Following compiles but I dont want to create local variable
#include <iostream>
#include <string>
using namespace std;
void
myfunc(int i, string &my) {
if (my.empty()) {
cout << "Empty" << endl;
} else {
cout << "String is " << my <<endl;
}
}
int main ()
{
std::string str1 ("Test string");
myfunc(1, str1);
std::string str2 ("");
myfunc(2, str2);
return 0;
}
The solution here is to have an overload that doesn't have the string parameter.
void myfunc(int i, string &my) {
cout << "String is " << my <<endl;
}
void myfunc(int i) {
cout << "Empty" << endl;
}
int main ()
{
std::string str1 ("Test string");
myfunc(1, str1);
myfunc(2);
}
This is the most simple and clear solution that conveys exactly your intent and functionality.
You shouldn't try to do it your way because if you want to modify the argument then the parameter should be "non-const reference" and so it cannot bind to temporaries. Thus you can't pass a string literal to it.
If you want to make it explicit that you don't pass a string, you could create a tag ala nullptr, although I do not recommend the extra complication when the above variant is clear and understood by everybody at first glance.
struct no_string_tag_t {};
constexpr no_string_tag_t no_string_tag;
void myfunc(int i, string &my) {
cout << "String is " << my <<endl;
}
void myfunc(int i, no_string_tag_t) {
cout << "Empty" << endl;
}
int main ()
{
std::string str1 ("Test string");
myfunc(1, str1);
myfunc(2, no_string_tag);
}
If you really want a single function, then the semantically correct version would have an optional reference.
auto foo(int i, std::optional<std::reference_wrapper<std::string>> my)
{
if (my)
cout << "String is " << my <<endl;
else
cout << "no string" << endl;
}
int main ()
{
std::string str1 ("Test string");
myfunc(1, str1);
myfunc(2, std::nullopt);
}
If you want to keep the function signature and still be able to pass it a temporary, then you are out of luck. C++ has a safety feature in that it does not allow a non-const lreferece to bind to a temporary. The reason for this restriction is that attempting to modify a temporary via a lreference would most likely be bug and not the programmers's intent since the temporary dies out anyway.
You can't pass a temporary to a non-const reference parameter. The object, being temporary, will be destroyed as soon as the function returns. Any changes that the function did to the object would be lost.
If you want to have the chance to modify the string, you can take the string by const reference and return a modified string.
string myfunc( int i, string const &s );
:
str1 = myfunc( 1, str1 );
auto result2 = myfunc( 2, "" );
Your other option is to use a pointer to a string that can be null.
void myfunc( int i, string *s ) {
if (!s) {
cout << "Empty" << endl;
} else {
cout << "String is " << *s <<endl;
}
}
myfunc( 1, &str1 );
myfunc( 2, nullptr );
You can ommit 1 or more arguments in functions calls as long those argument(s) are the last ones in the order or the args prototyped in that function.
You can also give a padron value if the argument is ommited when calling the function.
using namespace std;
void sTest(int a, string x ="TEST", int z=0);
void sTest(int a, string x, int z)
{
cout << x;
}
int main()
{
sTest(5); // displayed “TEST”
}
This question already has answers here:
How do you reverse a string in place in C or C++?
(21 answers)
Closed 8 years ago.
"Write a function that takes a string (character pointer) as input and returns the string reversed. The function should reverse the string in place and return it as the return value of the function."
char *strrev(char *str) {
char* end = str;
char tmp = 0;
if(str) {
while(*end) {
end++;
}
--end;
while(end > str) {
tmp = *end;
*end-- = *str;
*str++ = tmp;
}
}
}
I am new to C++. I am facing difficulty with this. Can you please correct my code.
Here's one for fun:
You will NOT want to turn this in as your assignment :/
See it Live On Coliru
#include <string>
std::string rev(std::string x)
{
auto a=x.begin();
auto b=x.rbegin();
while (a<b.base())
std::swap(*a++, *b++);
return x;
}
#include <iostream>
int main()
{
std::cout << rev("") << "\n";
std::cout << rev("1") << "\n";
std::cout << rev("12") << "\n";
std::cout << rev("123") << "\n";
std::cout << rev("Hello world!") << "\n";
}
Output:
1
21
321
!dlrow olleH
So your function, strrev claims to return a char * but it returns... well... nothing. That means that if you use the return value of this function, you're reading some random memory. You're in the realm of undefined behavior at that point and anything goes.
Your compiler should have warned you about this and you should learn to read and understand those warnings - they're there for a reason. If, perchance, it did not warn you, you need to crank up the warnings your compiler generates.
Once you fix your function to return the correct value, it will work as expected. Here's a hint: if you want to reverse the string in place then where would the start of the string be located in memory?
There is a standard algorithm in the STL which reverses a range.
char *strrev(char *str) {
const size_t n = strlen(str);
std::reverse(str, str+n);
return str;
}
Or better using C++ strings
void reverse(std::string& s) {
std::reverse(s.begin(), s.end());
}
I was looking for solutions to appending strings with other primitives and found that stringstream was the easiest solution. However, I wanted to streamline the process so I wanted to make a function to ease its use. In case you are proposing alternate methods for concatenation, i need the final result to be char*. I used a loop (i) with:
std::stringstream ss;
ss << "test" << i;
char* name = new char[ss.str().size() + 1];//allocate
strcpy(name, ss.str().c_str());//copy and put (char*)c_str in name
So the output is something link test1test2test3... This was the most reasonable solution I could muster. I was trying to put it into a function for ease of use, but am running into problems. I wanted to do something like:
char* string_to_pointer( char* dest, std::stringstream* _ss ) {
char* result = new char[_ss->str().size() + 1];
strcpy(result, _ss->str().c_str());
return result;
}
I could then do something like:
std::stringstream ss;
ss << "test" << i;
char* name = string_to_pointer( name, &ss );
I'm pretty new to c++ and this seems like the correct use syntactically, but I am running into runtime issues and would welcome solutions on how to get this in an easy to use function without resulting to Boost.
What about something like this:
#include <string>
#include <sstream>
class ToString {
std::ostringstream stream;
public:
template<typename T>
inline ToString &operator<<(const T&val) {
stream << val;
return *this;
}
inline operator std::string() const {
return stream.str();
}
};
You can use it like this:
std::string str = ToString() << "Test " << 5 << " and " << 4.2;
Use the std::stringstream::str() function to retrieve the contents of the string.
Example:
int foo = 42;
double bar = 12.67;
std::stringstream ss;
ss << "foo bar - " << foo << ' ' << bar;
std::string result = ss.str();
If you dont want to modify the string further, you can now simple call result.c_str() to acquire a const char*. However, if you really need a modifyable char* you have to copy the contents of the string to a cstring:
std::unique_ptr<char[]> cstring = new char[result.size() + 1];
strcpy(cstring.get(), result.c_str());
char* string_to_cstring ( const std::string &_ss )
Would be cleaner! Use with string_to_cstring(ss.str())
Need the returned C-String to be changeble? Because if not, just use ss.str().c_str() wherever you need it!
Or use:
char* result = new char[ss.str().size() + 1] (); // value initialized
ss.str().copy(result,std::string::npos);
This is what I'm trying to do:
showMessage("ERROR: THE MAX IS:" + max);
Basically I want to concatenate a variable (in this case an int) with a string to pass it as a parameter.
How can I do this in C++?
Here's one way:
std::ostringstream msg;
msg << "ERROR: THE MAX IS: " << max;
showMessage(msg.str());
Personally, if you're going that route for displaying something, no need to have the user do extra work:
#include <iostream>
template<typename T>
void showMessage(T &&t) {
std::cout << t << "\n";
}
template<typename Head, typename... Tail>
void showMessage(Head &&head, Tail&&... tail) {
std::cout << head;
showMessage(std::forward<Tail>(tail)...);
}
int main() {
showMessage("value1: ", 5, " and value2: ", 'a');
}
Here's a live example. Any stream should work, including a string stream and file stream. Keep in mind this is very similar to just using a stream and only really worth it if you do other stuff along with displaying it.
A combination of std::string and std::to_string() gives a touch of C++11 goodness:
#include <iostream>
#include <string>
using namespace std;
int main() {
int max = 42;
std::string mess("ERROR: THE MAX IS: ");
mess += std::to_string(max);
std::cout << mess;
}
LIVE EXAMPLE
If you want to use the string as an argument to a function accepting a const char*, you can use std::string::c_str() to get the C-style string of the std::string:
func(mess.c_str());
There isn't a stock C++ way to do this, string literals are that, and they're generally constant. You'll either need to use an overloaded string class or you'll need to make showMessage take arguments and do some kind of formatting for you.
// simple version - take a single string.
void showMessage(const std::string& message) {
// your old code, e.g. MessageBoxA(NULL, message.c_str(), "Message", MB_OK);
}
// complex version, take lots of strings.
void showMessage(std::initializer_list<std::string> args) {
std::string message = "";
for (auto str : args)
message += str;
showMessage(message);
}
int main(int argc, const char* argv[]) {
showMessage("Simple version");
showMessage({ "This program is: ", argv[0], ". Argument count is: ", std::to_string(argc) });
return 0;
}