This question already has answers here:
Can a local variable's memory be accessed outside its scope?
(20 answers)
How to return local array in C++?
(12 answers)
Closed 7 years ago.
Ill start with an example of source code (that i modified for clarity so ignore variables like "someLetter"):
wchar_t *someFunction()
{
wchar_t str[1024] = L"";
for (int i = 0; i < 50; i++)
{
str[i] = someLetter;
}
str[51] = L'\0';
return str;
}
The above code simply adds wchars to w_char array and when for loop is ended, it ends the array with L'\0'. Variable ret should hold the string.
However, when I execute the code below, i get nothing (empty string).
wchar_t *result = someFunction();
wcout << result << endl;
This is where it gets weird. If i execute the code mentioned all above, I get nothing. BUT if I add wcout << str << endl; in someFunction(), everything seems to be working fine i.e. code below does what its supposed to do.
wchar_t *result = someFunction();
wcout << result << endl;
TL:DR
Code below doesnt print out "result". Instead it prints out nothing and result is blank. The problem is fixed if I add wcout << str<< endl; to someFunction(). Why is that and how can I avoid that.
wchar_t *result = someFunction();
wcout << result << endl;
You are returning a pointer to automatic storage that goes out of scope when someFunction ends, so there is no correct behavior; it is undefined what will happen if you access a variable after it's gone out of scope. If you really need to return a wchar_t*, you'll need to either use a static array, pass a pointer to a buffer into someFunction, or dynamically allocate memory (and make the caller responsible for freeing that memory). The best thing to do would probably be to use std::wstring instead of raw wchar_t*s.
This code cannot work as you return the address of a local variable. The memory of wchar_t str[1024] is freed until someFunction() returns to the caller.
Sidenode: It should be str[50] = L'\0'; and not str[51] = L'\0'
To get you code working you might either use a std::wstring and return a copy of it or allocate the memory for str on the heap using new[] and delete[] it later on.
You should probably get a bit more familiar with C++ before asking questions like this.
Related
This question already has answers here:
Can a local variable's memory be accessed outside its scope?
(20 answers)
Closed 4 years ago.
I'm relatively new too C++ programming. While I was working on a code about arguments passing with an array of character pointers. I encountered a problem where the value of my pointers are changed after certain operations. Below is my code.
#include <iostream>
using namespace std;
void input(char* argv[], int &i)
{
char buff[10][20]; //buffer string array
while (cin.peek() != '\n') {
cin >> buff[i++];
}
for (int j = 0; j < i; j++) {
argv[j] = buff[j];
}
argv[i] = NULL; // putting a NULL at the end
}
int main(int argc, char* argv[])
{
char *arg[10];
int i = 0;
input(arg, i); //input the arguments
for (int j = 0; j < i; j++) {
cout << arg[j] << endl; //output the arguments entered
}
return 0;
}
The sub-function void input(char* argv[], int &i) is supposed to let me input my arguments as many as 9 times or when an enter key is pressed. While i indicates the total number of arguments.
The arguments are then stored as an array of character pointers and then pass it back to the main function's char *arg[10] to hold.
However, I found that after
cout << arg[j] << endl;
The values of arg are lost, and random values are being printed.
You're creating a two-dimensional array of characters buff on the stack, and then you're returning pointers into that array through the argv parameter. But buff lives on the stack and ceases to exist as soon as the input function exits. The memory used by buff will be overwritten by other functions that you call after calling input.
You should allocate buff in main and then pass it into input so it continues to live in the scope of main after input returns.
Another option would be to allocate heap space for buff in input. In this case the main function would be responsible for freeing the memory after it was done with it.
Obviously there are more advanced C++ features you could use to avoid some of this overhead. Though this is a C++ program, it's effectively written as C. But understanding how memory and pointers work is essential to understanding the problems that the newer C++ features solve.
the value of my pointers are changed
The pointers are the only things that weren't damaged. The problem is the memory they point to.
You can prove the first part by printing the value of each of these pointers, or just inspecting them in the debugger. (You can print the address rather than the C-string it points to by casting to void, like cout << static_cast<void*>(arg[j]) << '\n').
So what happened to your C strings? Well, you declared an automatic-scope array variable inside the function input. That array ceases to exist when the function exits, just like any other automatic-scope variable. Accessing the memory where a variable used to live, after the variable ceases to exist, is illegal.
The fact that you returned pointers into this array doesn't make it legal to read through (dereference) them after the array itself goes out of scope, and this is in fact undefined behaviour.
The contents being overwritten is actually the best case, because it meant you noticed the bug: it could legally have crashed or, even worse, appeared to work flawlessly until after you submitted/deployed/sold the program, and crashed every run thereafter.
Think of the stack as being a large (but not unlimited) amount of memory. It is allocated and freed simply be moving the stack pointer down and up (the directions will depend on the hardware).
Here's your code with some annotations.
input(arg, i);
// when you get here the stack pointer will have been moved up, freeing the space
// that was allocated for 'buf' in 'input'
// the space for 'j' could overwrite the space where 'buf' was
for (int j = 0; j < i; j++) {
// the calls to 'cout' and 'end;' could overwrite the space where 'buf was'
cout << arg[j] << endl;
}
This question already has answers here:
Can a local variable's memory be accessed outside its scope?
(20 answers)
Closed 6 years ago.
void changeString(const char* &s){
std::string str(s);
str.replace(0, 5, "Howdy");
s = str.c_str();
}
int main() {
const char *s = "Hello, world!";
changeString(s);
std::cout << s << "\n";
return 0;
}
When I run this code, it prints "Howdy, world!" I would think that str gets destroyed when changeString exits. Am I missing something with the way std::string gets allocated?
Yes, str is destroyed; but the memory of the string isn't cleared; your "s" pointer point to a free but non cleared memory. Very dangerous.
It's undefined behaviour when std::cout << s tries to access the pointer, because the destructor of the local std::string in changeString has freed the memory which the pointer still points to.
Your compiler is not required to diagnose the error but can instead generate a binary which can then do whatever it wants to.
The fact that you got the desired output was just bad luck because it made you think that your code was correct. For instance, I've just compiled your code on my machine and got empty output instead. It could also have crashed, or it may have done other, unrelated things.
This question already has answers here:
Can a local variable's memory be accessed outside its scope?
(20 answers)
Closed 8 years ago.
char* func()
{
const int size = 24;
char bin[size];
char *temp;
for(int i=0; i<23; i++)
bin[i] = '1';
bin[23] = '\0';
temp = bin;
return temp;
}
int main()
{
char *s;
s = func();
cout << s << endl; //prints out weird values
return 0;
}
When compiled and ran, it print random values. In the function func, I initialized a char array and tried to return it. Upon returning it and printing it in main, it prints out weird values. What is wrong? Any help would be appreciated.
char bin[size];
allocate memory on the stack, you cannot refer to that location after the function returns: "char *s" is assigned a value that refer to an invalid memory location.
You must not use pointers to freed space, like the stack of a function which has finished executing.
This Undefined Behavior means anything goes, even the proverbial demons flying out of your nose.
Your choices:
Use a caller-allocated buffer.
Use a static buffer (beware reentrancy problems and multithreading woes).
Use dynamic allocation (new, new[], malloc() and friends).
return a struct (standard container or otherwise) containing the data. Might use dynamic allocation. (Last point courtesy of Matt McNabb).
To make this as quick and concise as possible, this is my code:
char* aiMove = getAIMove();
cout << aiMove;
cout << "\n" << numMoves << ": " << aiMove << "\n\n";
return aiMove;
And this is my output:
a0 a1
0: �����������������������7
So, the first line calls getAIMove() and assigns the return value (char*) to aiMove.
The second line prints aiMove (a0 a1).
The third line takes numMoves and aiMove into cout and prints it, but it's printing some strange value instead.
The 4th line returns aiMove, which I've inspected to be the strange value printed.
Why has the value of aiMove changed? It seems to only happen when I pass an integer value into cout (in this case, numMoves).
Please help!
Thanks,
Patrick :)
edit: another thing that I forgot to mention is that this strange behaviour only happens when this block of code gets executed for the first time, every following time it gets run during the program it prints fine.
This is a clear indication that getAIMove returned a pointer to memory that the system felt free to reuse. A subsequent allocation, from either the stack or the heap, overwrote the returned pointer.
There are lots of ways this can happen, this is probably the most common:
char *GetAIMove()
{
char buf[128];
strcpy(buf, "a0");
strcat(buf, " ");
strcat(buf, "a1");
return buf; // oops, buf won't exist after we return
}
Oops. This code returns a pointer to a buffer that ceases to exist as soon as it returns. A typical fix for this issue would be return strdup(buf);. Just remember that the caller of the function needs to free the string when it's done with it.
Here's another way:
std::string GetAIMove()
{
// ...
return foo;
}
char* aiMov e= GetAIMove();
// aiMove points to the contents of the returned string, no longer in scope.
The fix for this is std::string aiMove = GetAIMove. Now aiMove keeps the string in scope.
But the best fix is to use a string class specifically designed to hold strings all the way through:
std::string GetAIMove()
{
std::string foo;
foo = "a1";
foo += " ";
foo += "a2";
return foo;
}
std::string aiMove = GetAIMove();
Note that while this code appears to involve a lot of copying, in practice, modern compilers will make it efficient. So don't feel bad about keeping your code simple, logical, and easy to understand and maintain.
No, cout doesn't change the contents of the parameter.
You're probably doing something wrong beforehand and running into undefined behavior.
This question already exists:
Closed 11 years ago.
Possible Duplicate:
c++ warning: address of local variable
char* strdup(const char* s)
{
char dup[strlen(s)];
for (int i = 0; i<strlen(s); i++)
{
dup[i]=s[i];
}
return dup;
}
This function is supposed to hold the new array that has been read backwards plus another slot. When I compile it I get the error "warning: address of local variable 'dup' returned" and when I run the program it returns the memory address.
char dup[strlen(s)] defines a local stack variable; this goes out of scope when the function ends, so any attempt to access it after that will result in undefined behaviour.
Your options are:
Use a heap variable (obtained using new). You will have to remember to delete it at some point.
Have the function write into an existing buffer, provided by the caller (e.g. void strdup(char *out, const char *in)).
Use C++ constructs like std::string, which do all the hard work for you.
As you have marked your question "C++", I strongly recommend Option #3.
Your definition specifies an char array pointer as its return type but you initialize a char array inside your function and try to return it. Try this:
char* strdup(const char* s)
{
char *dup = new char[strlen(s)];
for (int i = 0; i<strlen(s); i++)
{
dup[i]=s[i];
}
return dup;
}
The problem is that you never allocate dup on the heap, so when you exit the stack frame, dup will automatically be removed with the stack frame. This means that it's not possible to have a valid reference to dup, as it ceases to exist once you exit the function.
This should work:
char* strdup(const char* s)
{
char* dup = new char[strlen(s)];
for (int i = 0; i<strlen(s); i++)
{
dup[i]=s[i];
}
return dup;
}
EDIT: when you are done, don't forget to use 'delete' to free the memory ;)
you can't return dup[] because, as it is, it's a local variable and won't be valid outside the function (well, the memory it points to won't be valid anymore). You have to call something like malloc(), which allocates memory on the heap (space visible by all your app)
char* strdup(const char* s)
{
char dup[strlen(s)]; // defines *local* variable on *stack*
for (int i = 0; i<strlen(s); i++)
{
dup[i]=s[i];
}
return dup; // returning dup[0] = dup address
}
You are returning address of local variable, created on stack. When you return from the function the stack will be rewind and your dup variable gone.
The line
char dup[strlen(s)];
will not work in C++. Arrays need a constant size specified at compile time; strlen(s) is a variable.
As far as your actual warning is concerned, it is a bad practice to return a pointer to a local variable to the caller; since the local variable (in this case, the array dup) is allocated on the stack, when the function returns, it is deallocated, and hence, the returned pointer may be invalid. Compilers are designed to catch such errors and flag a warning saying that this could be a potential source of problems.
The dup variable is an array of char and is allocated on the stack rather than the heap (via new or malloc). As soon as the stack frame is left (that is: the function is left) this is undefined memory that will be overwritten by other things soon.
You need to turn dup into a char * and use new or malloc to allocate the necessary memory.