C++ Static variable inside function cannot be changes - c++

Can someone please explain to me the following.
static_outer works as expected. When the print_str() function is called, static_outer is assigned the value from the parameter and then printed to output.
static_inner "misbehaves" a little. It is also assigned the value from the parameter, when the function is called. But when the function is called for the second time, the printed value is the same as in the first call.
Why doesn't the assignment change the value? My only intuition is that the line is ignored because the static_inner is already declared but compiler does not complain.
static const char* static_outer;
void print_str(const char* const str) {
static const char* static_inner = str;
cout << static_inner << "\r\n";
static_outer = str;
cout << static_outer << "\r\n";
}
int main() {
const char str1[] = "Foo";
const char str2[] = "Bar";
cout << "First call" << "\r\n";
print_str(str1);
cout << "\r\n" << "Second call" << "\r\n";
print_str(str2);
}
// Output:
// First call
// Foo
// Foo
//
// Second call
// Foo <--- this is the line in question... why not "Bar"?
// Bar
Live demo: https://onlinegdb.com/-OnqgsLTn

Once a function static variable is initialized, the line static const char* static_inner = str; has no further effects.
If you want the variable to change every time it is called, you would need to have a line of code performing assignment:
void print_str(const char* const str) {
static const char* static_inner;
static_inner = str;
cout << static_inner << "\r\n";
static_outer = str;
cout << static_outer << "\r\n";
}

My only intuition is that the line is ignored because the static_inner is already declared
Your intuition is correct, that is exactly what happens. You are assigning the str parameter to static_inner in its declaration. A static local variable is initialized only one time, the first time the function is called. On subsequent calls, the variable retains its previous value. That is the whole point of declaring a local variable as static.
To do what you want, you need to separate the static local variable's declaration from its assignment, eg:
static const char* static_inner;
static_inner = str;

Related

How can you change the value of a string pointer that is passed to a function in C++?

I need to change the value of a std::string using a function.
The function must be void, and the parameter must be a pointer to a string as shown.
#include <iostream>
void changeToBanana(std::string *s) {
std::string strGet = "banana";
std::string strVal = strGet;
s = &strVal;
}
int main() {
std::cout << "Hello, World!" << std::endl;
std::string strInit = "apple";
std::string* strPtr;
strPtr = &strInit;
changeToBanana(strPtr);
std::cout << *strPtr << std::endl;
return 0;
}
I would like the resulting print to say "banana"
Other answers involve changing parameter.
I have tried assigning the string using a for loop, and going element by element, but that did not work. The value remained the same.
The function must be void, and the parameter must be a pointer to a string as shown.
With this requirements you cannot change the value of the pointer that is passed to the function, because it is passed by value.
Don't confuse the pointer with what it points to. Parameters are passed by value (unless you pass them by reference). A copy is made and any changes you make to s in the function do not apply to the pointer in main.
However, you can change the string pointed to by the pointer (because s points to the same string as the pointer in main):
void changeToBanana(std::string *s) {
std::string str = "banana";
*s = str;
}
However, this is not idiomatic C++. You should rather pass a a reference void changeToBanana(std::string& s) or return the string std::string returnBanana().
void changeToBanana(std::string *s) {
std::string strGet = "banana";
std::string strVal = strGet;
// the following line doesn't do anything
// useful, explanation below
s = &strVal;
}
s = &strVal assigns the address of the strVal to s. Then the function ends and any modifications made to s are "forgotton", becase s is a local variable of changeToBanana.
So calling changeToBanana(&foo) does nothing.
You either want this:
void changeToBanana(std::string *s) {
*s = "banana";
}
...
std::string strInit = "apple";
changeToBanana(&strInit);
or this (preferred because you don't need pointers):
void changeToBanana(std::string & s) {
s = "banana";
}
...
std::string strInit = "apple";
changeToBanana(strInit);

char * not returned correctly from overloaded operator or memory managment issue

I try to read a file decompress it and parse it to a tree in C++. Everything works fine with one excaption: For some reason I can construct a char[] string and use a pointer on it to output it with the help of cout inside a befriended overloaded <<-operator, but can't use the pointer returned by the operator to cout the string. I was thinking it might have to do with visibility of the string-memory, but that makes no sense to me since with "new" allocated memory should be visible to everyone since its on the heap of the program and not somekind of object or class heap. This all sounds rather confusing, let me show you a striped down version of the source and I'm pretty sure everything becomes clear (probably some really stupid mistake on my end... but I try since two days and don't find the mistake):
main:
#include "dekompstream.h"
#include <iostream>
int main(void) {
char *testString;
DekompStream ds(nullptr, 0);
std::cout << "TEST" << std::endl;
testString << ds;
std::cout << "Outside operator: " << testString << std::endl; // Fails misarably. Some weird randome memory-slice looking output
//delete [] testString;
return 0;
}
dekompstream.cpp:
#include "dekompstream.h"
DekompStream::DekompStream(uint8_t *kompDaten, unsigned int anzahlBytes) {
}
DekompStream::~DekompStream() {
}
uint8_t *DekompStream::dekompremieren() {
char *test = new char[4];
test[0] = 'A';
test[1] = 'B';
test[2] = 'C';
test[3] = '\0';
return (uint8_t *)test;
}
char *operator<<(char *zeichenkette, DekompStream &dekompStream) {
zeichenkette = (char *)dekompStream.dekompremieren();
std::cout << "Inside operator: " << zeichenkette << std::endl; // Works fine
return zeichenkette;
}
dekompstream.h:
#ifndef DEKOMPSTREAM_H
#define DEKOMPSTREAM_H
#include <cstdint>
#include <iostream>
class DekompStream {
public:
DekompStream(uint8_t *kompDaten, unsigned int anzahlBytes);
~DekompStream(void);
friend char *operator<<(char *zeichenkette, DekompStream &dekompStream);
private:
uint8_t *dekompremieren();
};
#endif
Thanks in advance :-)
testString << ds doesn't do what you think it does.
If we take a look at the code for operator<<:
char *operator<<(char *zeichenkette, DekompStream &dekompStream) {
zeichenkette = (char *)dekompStream.dekompremieren();
return zeichenkette;
}
The function reassigns the char* argument to a new value, then returns the new value. Fine. OK. But how does the compiler use this?
When we write:
testString << ds;
The compiler turns it into:
operator<<(testString, ds);
See the error?
You returned a new value, but because the operator overload was turned into a function call, the allocated pointer was lost. In addition, because the char* argument was simply reassigned, the original pointer value wasn't changed, meaning you got whatever was on the stack previously.
If we look at the declarations for the STL functions for iostream, we'll see the way to fix it:
ostream& operator<< (ostream& os, const char* s);
Notice the first parameter is passed by reference - this ensures any modifications to the stream made by the function persist in the calling context.
Simply change your function definition to:
char *operator<<(char *&zeichenkette, DekompStream &dekompStream){
...
}
and the issue will disappear.

How to understand the const variable between different block scopes

I'm beginner in C++. I learned from the book "accelerated c++" about a const variable inside a block scope. It means that the "const variable will be destroyed when the scope ends at }.
But in the test: the const string variable s is defined inside the first block. In the second block, the s is also defined. When the second s is printed out the first block's s hasn't been destroyed.
I think the program is invalid, but the result is totally true when I compile the program. I don't known why it is. please help me to understand the code.
#include <iostream>
#include <string>
int main()
{
const std::string s = "a string";
std::cout << s << std::endl;
{
const std::string s = "another string";
std::cout << s << std::endl;
}
return 0;
}
the result is
a string
another string
Enlarge your program the following way
#include<iostream>
#include<string>
const std::string s = "a first string";
int main()
{
std::cout << s << std::endl;
const std::string s = "a string";
std::cout << s << std::endl;
{
const std::string s = "another string";
std::cout << s << std::endl;
}
std::cout << s << std::endl;
std::cout << ::s << std::endl;
return 0;
}
The program output is
a first string
a string
another string
a string
a first string
Each declaration in an internal scope hides a declaration in the outer scope with the same name (except function names that can be overloaded). But the variable declared in the outer scope is still alive. If a variable is declared within a namespace as the first variable s that is declared before main and belongs to the global namespace then you can use its qualified name to access the variable.
When an unqualified name is used then the compiler searches its declaration starting with the nearest scope.

What happens when I assign an object the value of a reference in C++?

#include <iostream>
void test(std::string &s) {
std::string p = s;
std::cout << p.length() << " " << p;
}
int main() {
std::string s = "Hello world";
test(s);
return 0;
}
So, the function test receives a reference to my string s from my main function.
My question is, what does this line do:
std::string p = s;
Does it shallow copy the reference and put it in p, thereby defeating the purpose of using a reference in the first place?
Or does it (p) just act as a reference?
It creates a copy of the value of the reference, it doesn't allow you to edit the content of s with p, to make p act as a reference and be able to edit s from p, you have to declare it as a reference:
std::string& p = s;
thereby defeating the purpose of using a reference in the first place?
Why does it defeat the purpose of reference, you have declared s as reference, isn't it? Not p. So as noted indeed it will copy the value which s contains.
What happens when I assign an object the value of a reference in C++?
You cannot assign the value of a reference, or at least you should not think in such terms. A reference is not a pointer. What happens is that you assign the value of an object, because a reference is the object, accessed via a different name.
void test(std::string &s) {
The fact that you are dealing with a reference is only really relevant at the point of declaration. All code in this function which uses s uses a std::string, not a std::string &.
My question is, what does this line do:
std::string p = s;
It assigns your std::string object to p, no more, no less. In other words, it does the same as it would in this program:
int main() {
std::string s = "Hello world";
std::string &s_with_different_name = s;
std::string p = s_with_different_name;
std::cout << p.length() << " " << p;
}
Or, even more simply, in this:
int main() {
std::string s = "Hello world";
std::string p = s;
std::cout << p.length() << " " << p;
}

Unable to return the contents of a vector<char> as a char* pointer

I am trying to store a char* into a struct's char* field. I have tried different things but none of them worked. The problematic piece of code is shown below:
pInfo is the object of the struct PlayerInfo.
PlayerInfo *pInfo = (PlayerInfo*)malloc(sizeof(PlayerInfo));
The char* I get from GetAddress is stored in the Address field of PlayerInfo.
pInfo->Address = GetAddress(pInfo->playerId);
The GetAddress function is shown below. It converts integers to strings, stores them in a vector and returns the vector as a char* using &retChar[0].
char* GetAddress(int playerId)
{
std::string strPlayerId = std::to_string(playerId);
std::string strGroupId = std::to_string(group.GetGroupId());
std::string retAddress = strPlayerId + ":" + strGroupId + ":" + GenRandomChar();
//From -- http://stackoverflow.com/questions/347949/convert-stdstring-to-const-char-or-char
std::vector<char> retChar(retAddress.begin(), retAddress.end());
retChar.push_back('\0');
for(std::vector<char>::const_iterator i = retChar.begin(); i != retChar.end(); ++i)
std::cout << "retChar is " << *i << std::endl;
return &retChar[0];
}
When I print the contents, only garbage is printed. I tried printing the memory contents from gdb, but that also did not help.
char* address = GetAddress(pInfo->playerId);
std::cout << "address is " << *address << std::endl;
std::cout << "address is " << pInfo->Address << std::endl;
std::cout << "address is " << *(pInfo->Address) << std::endl;
The problem is, that your function scope local variable
std::vector<char> retChar;
goes out of scope and is destroyed after your function returned.
Thus using the returned pointer return &retChar[0]; is calling undefined behavior.
The better choice would be to pass the pointer where to copy the data as a reference
void GetAddress(int playerId, char*& result) {
std::vector<char> retChar;
// ...
std::copy(retChar.begin(),result);
}
and ensure result buffer is big enough to receive the copied data.
NOTE:
The above suggestion just solves the 1st level of your current problem. The probably better idea is to change your function simply to deal with std::string instead of using std::vector<char> and raw char* pointers (if your use case allows to refactor this):
Make PlayerInfo::Address member a std::string type
struct PlayerInfo {
// ...
std::string Address;
};
and define your GetAddress() function as follows
std::string GetAddress(int playerId) {
std::ostringstream result;
result << playerId << ":" group.GetGroupId() << ":" << GenRandomChar();
return result.str();
}
and use the results std::string::c_str() method if you really need a const char* value to pass it elsewhere.
I think the idea of using std::vector<char> in the selected answer to How to convert a std::string to const char* or char*? is that the std::vector<char> is your writable character array, not that you should extract a char * from it. (You can, however, copy the contents into a different memory location identified by a char *, as you have already seen.)
But I would ask why you are storing a char * in the Address member of PlayerInfo. Why don't you make that member an std::string and change the return type of getAddress() to std::string, in which case getAddress can simply return retAddress?
Alternatively, you can declare getAddress like this: void getAddress(int playerId, std::string& retAddress) and the code inside the function is even simpler, because you don't have to declare retAddress as a local variable inside the function.