How to update a C++ string within a function? [duplicate] - c++

This question already has answers here:
When I change a parameter inside a function, does it change for the caller, too?
(4 answers)
Closed 5 years ago.
Suppose I want to write a C++ function foo() that updates the value of an input string. How do I do it? The code should probably look something like I have below but I don't know how to properly pass the string such that it is updated by the function.
void foo(String x) // Not sure if I should put an & or * before x
{
x += " Goodbye";
}
void main()
{
String x = "Hello World";
cout << "x = " << x << endl;
foo(x); // Not sure if I should pass a pointer to x,
// a reference to x or what?
cout << "After foo (), x = " << x << endl;
}
(FYI, I'm writing this for an Arduino processor)

Pass by reference:
void foo(String& x)
{
x += " Goodbye";
}
The & means the parameter is a reference to the String outside the function rather than a copy.

In order to update the string from within the function, you need to pass a reference to the string as input:
void foo(String& x)
{
x += " Goodbye";
}
This SO post explains the difference between pass-by-reference and pass-by-value.
Regarding your confusion between using & or * in the function signature, you can either
use & as described above OR
you could define foo as void foo(String *x). However, in this case, when you call foo, you would need to call it as foo(&x);.
In the first case, you're passing the input as a reference variable while in the second case, you're passing it in as a pointer variable. The differences between them are explained in this post.

You can use either of the following methods: -
void foo(String *x) in function header and foo(&x); in main().
or,
void foo(String &x) in function header and foo(x); in main().

Related

Confusing behavior of C++ string returns and c_str() casts [duplicate]

This question already has answers here:
Why does calling std::string.c_str() on a function that returns a string not work?
(3 answers)
Closed 2 years ago.
I am new to C++ programming (work with Java mostly), and this behavior of C++ classes, member strings and string conversions to const char* with c_str() is confusing me.
I have a header, a class and main function as follows:
sample.h
class Sample
{
private:
int id;
std::string text;
public:
Sample(int id);
void setId(int id);
int getId();
void setText(std::string txt);
std::string getText();
void loadText();
~Sample();
}
sample.cpp
Sample::Sample(int id)
{
this->id = id;
}
void Sample::setId(int id)
{
this->id = id;
}
int Sample::getId()
{
return this->id;
}
void Sample::setText(std::string txt)
{
this->text = txt;
}
std::string Sample::getText()
{
return this->text;
}
void Sample::loadText()
{
this->text = "Loaded";
}
Sample::~Sample()
{
std::cout << "Destructor is called." << std::endl;
}
main.cpp
void main()
{
int id = 1;
Sample* sample = new Sample(id);
// Case: 1 - If I do this, it does not work. Prints gibberish.
sample->loadText();
const char* text = sample->getText().c_str();
std::cout << text << std::endl;
// Case: 2 - Otherwise, this works.
sample->loadText();
std::cout << sample->getText().c_str() << std::endl;
// Case: 3 - Or, this works
sample->loadText();
std::string txtCpy = sample->getText();
const char* text = textCpy.c_str();
std::cout << text << std::endl;
}
All three cases are done one at a time.
Case 3 does satisfy my use case (which is, passing the string to a C library that expects a const char*. But, I can't figure out the difference between Case: 1 and Case: 3? If we are returning the string by value, how does copying it to an intermediate variable make it kosher for the run-time?
The result of c_str() is only valid while the string you called it on still exists. In case 3, txtCpy still exists at the point you are writing cout << text. But in Case 1, the string was the return value of sample->getText which is temporary and stop existing at the end of that line .
This issue always will exist if you take pointers or references to other objects. A naked pointer or reference has its own lifetime which may differ from the lifetime of the targeted object. This is unlike Java where object references all participate in the lifetime of the object.
As such, you always need to think about object lifetimes when using these features, and it's commonly recommended to instead use higher level features or other code styles that do not permit lifetime management errors.
You could consider adding a member function to Sample which gets a const char * pointing at the original string (although this is a wee violation of encapsulation, and still has a similar class of problem if you hold onto the pointer and then modify the underlying string). Better would be to just avoid working with the naked pointers entirely.
In this code snippet
const char* text = sample->getText().c_str();
std::cout << text << std::endl;
the variable text is assigned by a pointer (c_str()) of a temporary object returned from the member function getText. After this statement the temporary object will nit be alive, So the variable text has an invalid pointer,
The code snippet could be valid if the member function returned reference to the data member text like for example
const std::string & Sample::getText() const
{
return this->text;
}
Pay attention to that this declaration of main
void main()
is not a standard declaration.
The standard declaration of main without parameters is
int main()

Temporary in a function call: UB? [duplicate]

This question already has answers here:
is there issue will stringstream.str().c_str()? [duplicate]
(3 answers)
Closed 6 years ago.
Consider the following code, based on this answer:
#include <iostream>
#include <sstream>
class StringBuilder {
public:
template <typename T> inline StringBuilder &operator<<(T const &t) {
ss << t;
return *this;
}
inline char const * c_str() {
return ss.str().c_str();
}
private:
std::stringstream ss;
};
void foo(const char *x) {
std::cout << x << std::endl;
}
int main() {
foo((StringBuilder() << "testing " << 12 << 3 << 4).c_str());
return 0;
}
Does calling foo() with the temporary StringBuilder's return value cause UB in any way?
The reason I'm asking is that the example above works great, but in real life I'm using a library that, amongst other things, contains logging facilities, and using this library I'll get incorrect output (the logging function takes my char* correctly but overwrites it internally, which caused me to believe that the memory is no longer valid).
Yes, but not because of what you perhaps think.
The temporary StringBuilder in the function call is not destroyed until after foo returns, so that's fine.
However, the c_str() method returns the result of calling .str().c_str(), and the temporary string returned by this str() is destroyed as StringBuilder::c_str() returns, which means that the pointer returned is invalid outside. Using this pointer causes UB.

Specifying class variables vs. method variables C++

Here's an extremely basic example of my question.
#include <iostream>
#include <string>
using namespace std;
int x;
void test(int x) {
x += 3;
cout << x << endl;
}
int main() {
test(x);
cout << x << endl;
return 0;
}
the output is:
"3" (new line) "0"
How can I specify inside of the "test()" function that I want the class's 'x' variable to have the 3 added to it instead of the temp variable inside of the function?
In java you specify that you're dealing with the function/method's variable by using '"this". Is there a similar way to do this in C++?
In your case you can use :: to specify to use global variable,
instead of local one:
void test(int x) {
::x += 3;
cout << ::x << endl;
}
And it is not class member or so on just global and local.
In the C++ language, create a class or struct and you can use this->x the same as this.x in the Java language.
First of all, thank you for stating that you come from Java. This will help us a lot in terms of helping you!
Now, let's analyze your code
#include <iostream>
#include <string>
using namespace std;
Including some headers, using the std namespace (not recommended, BTW), everything's okay here.
int x;
You declare a variable named x of type int at global scope, with an initial value of zero (this only applies to objects at global scope!).
void test(int x) {
x += 3;
cout << x << endl;
}
You declare a function test that takes a parameter x of type int and returns void (a.k.a: nothing). The function increments the value of its intenral x variable by 3, then prints that to standard output by means of std::cout. Just to be clear, once you declare the int x parameter, it "hides" the int x at global scope, thus if you want to access the later, you have to use another way (see below).
int main() {
test(x);
cout << x << endl;
return 0;
}
You declare the special main function, taking no parameters and returning int. The function calls test with the global int x as argument, then prints the value of the global x to the standard output by means of std::cout, and finally returns zero, indicating successful execution.
Now, you have a big misconception, that you can attribute to the single-paradigm design of the Java language. In Java, there's no concept of "global functions", not to even say there are no "functions" at all. You only have "classes" with "methods".
In C++, this is not the case. The C++ language is a multi-paradigm one; it allows you to do imperative programming, structured programming, object-oriented programming, and even functional programming (you're not expected to have understood that last sentence completely)! When you declare anything without specifying an scope, it's said to lie in the global scope. The global scope can be accessed by anything, anywhere. In the example you presented there are no classes involved!
In the global scope, something like void test(int) is not a method, but a function. There's no class "owning" that function; let's say it's of "everyone" ;). A function is just a block of code that you can reuse by giving it arguments, if the function has them at all. In C++, you use classes to encapsulate data and corresponding code in a single "packed" black-box entity, not for, well, anything, like in Java.
Now, (this is somewhat like Java, but be careful!), when you pass a "plain" object, such as an int or something more funky and complex like std:: (you were not expected to understand that...) to a function, that function gets a copy of that object. The int x in test is not the same as the one main passed to it. If you assign to it inside test, you'll notice main "sees no difference". In Java, this applies too, but only to the fundamental types like int, but in C++ it does for all types.
If you want to be able to change the variable you got, just use references. You get a reference of any type T by typing T&. So, if you assign to a int& x inside the now modified test, main will "see" all changes.
Finally, there's the :: operator. It's used to access stuff in some scope from, well, other scopes. It has the form namespace-or-class::stuff. So for example, std::cout refers to identifier cout in namespace std. There's a special case: if the left operand is not given, :: accesses the global scope. This is useful whenever you "hide" something from the global scope. So, for example, in test, you could say ::x, and that would refer to the x in the global scope!
void test(int x) {
// ...
::x += 123;
}
Edit: If you're curious, you can take a glance at how classes in C++ work with this (I won't explain it, because that's off-topic)...
#include <iostream>
int x = 0;
class MyClass {
private:
int x;
public:
MyClass() : x(0) {}
void test(int x) {
this->report(x);
std::cout << "Doing some magic...\n";
this->x += x;
this->report(x);
}
void report(int x) {
std::cout << "this->x = " << this->x << '\n';
std::cout << "x = " << x << '\n';
}
};
int main() {
MyClass c;
c.report();
x += 123;
c.test(x);
x += 456;
c.test(x);
c.report();
}

C++ - Can the following code cause undefined behavior? [duplicate]

This question already has answers here:
Calling a function pointer whose assigned function has less arguments then the pointer type
(2 answers)
Closed 7 years ago.
take a look at the following example:
#include <iostream>
#include <string.h>
void Func1(int x)
{
std::cout << "I'm function 1: " << x << std::endl;
}
void Func2(int x, const char* str)
{
std::cout << "I'm function 2: (this is arg1: " << x << " - args2: " << str << ")" << std::endl;
}
uintptr_t GetProcAddress(const char* _str)
{
if (strcmp(_str, "func1") == 0)
{
return reinterpret_cast<uintptr_t>(Func1);
}
else
{
return reinterpret_cast<uintptr_t>(Func2);
}
}
int main()
{
typedef void(*PROCADDR)(int, const char*);
PROCADDR ext_addr = nullptr;
ext_addr = (PROCADDR)GetProcAddress((const char*)"func1");
//call the function
ext_addr(10, "arg");
std::cin.get();
return 0;
}
We are basically calling Func1 with 2 arguments and can switch to call Func2 with the same args and everything works as intended.
Of course the address of both the arguments are always pushed on to the stack even though the second one is never used by the function itself.
Now I understand that the above code should never be used in production-code but my main question is, can the above code cause UB or is the code always expected to act like that?
Best regards
xx
Yes, it's undefined behavior. From [expr.reinterpret.cast]:
A function pointer can be explicitly converted to a function pointer of a different type. The effect of calling
a function through a pointer to a function type (8.3.5) that is not the same as the type used in the definition of the function is undefined.

How to make an ambiguous call distinct in C++?

void outputString(const string &ss) {
cout << "outputString(const string& ) " + ss << endl;
}
void outputString(const string ss) {
cout << "outputString(const string ) " + ss << endl;
}
int main(void) {
//! outputString("ambigiousmethod");
const string constStr = "ambigiousmethod2";
//! outputString(constStr);
} ///:~
How to make distinct call?
EDIT: This piece of code could be compiled with g++ and MSVC.
thanks.
C++ does not allow you to overload functions where the only difference in the function signature is that one takes an object and another takes reference to an object. So something like:
void foo(int);
and
void foo(int&);
is not allowed.
You need to change the number and/or the type of the parameter.
In your case the function that accepts a reference, you can make it accept a pointer, if you want to allow the function to change its argument.
You could change the signature of one of the methods. It may not look pretty, however it is the simplest way.
So you could in principle have
void outputString(const string &ss, int notneeded) {
cout << "outputString(const string& ) " + ss << endl;
}
void outputString(const string ss) {
cout << "outputString(const string ) " + ss << endl;
}
and when you want to call the first function just call it with:
outputString("ambigiousmethod", 0);
which will result in a distinguishing call.
There is no other way (I'd love to be proven wrong on this one) since C++ does not allow overloading where passing (by value or by reference) is the only difference in signature.
Edit: as pointed out by bzabhi, you could also change the signature by changing the reference to a pointer. In the example you gave that would work, however you may have to change function code on some occasions.
According to your code, u need only
void outputString(const string &ss).
Because both methods cannot change the argument to the caller (because it's const reference or by-value passing).
Why do you need those 2 methods?
I recommend using the techinque of giving each and every function a unique name., i.e., do not use syntax overloading. I have been using it for years and I've only found advantages in it.