Memory Management : scope and local pointer variable
Q. In terms of Memory Management, What is the error in the following code?
char* secret_message()
{
char message_buffer[100];
char* text = "Hey man!";
int n = 0;
while (text[n] != '\0')
n++;
for (int i = 0; i <= n ; i++)
message_buffer[i] = text[i];
return message_buffer;
}
Answer.
I think message_buffer is local variable
that is automatically reclaimed after function ends.
This function returns a reference to an invalid memory location
, since message_buffer disappears right after return statement.
Is it correct?
Please let me know.
Thanks,
Answer. I think message_buffer is local variable that is automatically reclaimed after function ends. This function returns a reference to an invalid memory location , since message_buffer disappears right after return statement.
Yes, it is correct. message_buffer is allocated on stack, its memory will be deallocated when the function exits. the pointer will points to release memory.
BTW:
char* text = "Hey man!";
should be
const char* text = "Hey man!";
in modern C++.
message_buffer is automatic variable whose scope is within the function only.
this variable either should be declared in main function or declared as static variable within the function.
You are correct. This produces undefined behaviour.
Related
int* areaofsquare(int len,int width){
int value = len*width;
return &value;
}
int main() {
printf("area=%i\n",*areaofsquare(1,2));
return 0;
}
Why I get memory error from this code? As per my understanding I did not get any error in this code block so why does it not run properly?
Help me out.
Thank you.
You can't just return pointer to stack variable, as it's getting invalidated as the function returns. You can use dynamic memory allocation instead:
int* area(int leangth,int width){
int * area = malloc(sizeof(int));
*area = leangth*width;
return area;
}
int main() {
printf("area=%i\n",*area(5,6));
}
Please note that you create memory leak and it would be better to handle it some way, but in this tiny example it doesn't matter.
You are returning the address of a local function variable in your function area. When the function returns, its stack space is no longer valid, so attempting to access an address to a local variable from that function is undefined behavior.
I don't see why you need to make area return a pointer to an int. Just return area's value and have area's return type just be int instead.
If for some reason you are required to return a pointer to an int (i.e. assignment or deliverable specifications), you have some options:
Use heap memory. Allocate area with malloc, and free it in main after you've printed its value.
Use static to put area into the process' data section rather than in stack memory, so that it persists beyond its scope and an address-of operation on it will continue to work after the function returns.
I'm trying to initialize the values of an object, then pass it into a function, but visual studio tells me at this point that my two variables (question and answer) inside my object have "bad pointers" and cannot be evaluated. Unfortunately, I need to access both later on.
I've tried displaying question[i] and answer[i] right before calling enqueue() and it echoes correctly.
It's as if when I call the enqueue() function it doesn't remember what values I gave the card object when I called the constructor right before.
I'm not sure why my code breaks here, do I need to make a dynamic object?
card::card(char *q_input, char *a_input)
{
char * question = new char [75];
char * answer = new char [25];
strncpy(question,q_input,strlen(q_input)+1);
strncpy(answer,a_input,strlen(a_input)+1);
}
...
int queue::fill_deck(char **question, char **answer)
{
for(int i = 0; i < 9; i++)
{
card Card(question[i],answer[i]);
enqueue(Card); //ERROR!
}
return 0;
}
Thank you for the help!
Please let me know if you need more information.
EDIT: the problem was that I was redeclaring two variables with my constructor. A syntax mistake on my part!
One huge issue: This code does nothing except cause a memory leak:
card::card(char *q_input, char *a_input)
{
char * question = new char [75];
char * answer = new char [25];
strncpy(question,q_input,strlen(q_input)+1);
strncpy(answer,a_input,strlen(a_input)+1);
}
question and answer are local variables. Not only that, you then allocate memory and assign the returned pointer to these local variables. When that function exits, those locals go away, plus any chance of deallocating the memory you allocated goes away with it, causing a memory leak.
Before doing anything else, why are you using new[] instead of std::string? You tagged this as C++, but all of your coding is 'C'.
I was trying to brush up my c++ skills.
I got 2 functions:
concat_HeapVal() returns the output heap variable by value
concat_HeapRef() returns the output heap variable by reference
When main() runs it will be on stack,s1 and s2 will be on stack,
I pass the value by ref only and in each of the below functions, I create a variable on heap and concat them.
When concat_HeapVal() is called it returns me the correct output.
When concat_HeapRef() is called it returns me some memory address (wrong output). Why?
I use new operator in both the functions. Hence it allocates on heap.
So when I return by reference, heap will still be VALID even when my main() stack memory goes out of scope.
So it's left to OS to cleanup the memory. Right?
string& concat_HeapRef(const string& s1, const string& s2)
{
string *temp = new string();
temp->append(s1);
temp->append(s2);
return *temp;
}
string* concat_HeapVal(const string& s1, const string& s2)
{
string *temp = new string();
temp->append(s1);
temp->append(s2);
return temp;
}
int main()
{
string s1,s2;
string heapOPRef;
string *heapOPVal;
cout<<"String Conact Experimentations\n";
cout<<"Enter s-1 : ";
cin>>s1;
cout<<"Enter s-2 : ";
cin>>s2;
heapOPRef = concat_HeapRef(s1,s2);
heapOPVal = concat_HeapVal(s1,s2);
cout<<heapOPRef<<" "<<heapOPVal<<" "<<endl;
return -9;
}
Both your functions are legal and fine, apart from that you're later leaking the free store objects from both functions.
The first function returns a reference to the value on the free store, which is copied into your local variable in main.
The second function returns a pointer to the instance on the free store, which is stored into a pointer variable in main.
Your problem is in that you do not print the second string, you print the address of it, thanks to that there's an operator<< that prints the address a pointer contains as a number.
If you intend to access the contents of the second variable, you should dereference it when using it.
When you return by reference, you signify (among other things) that the caller does not become owner of the data and is not responsible for freeing it.
You've allocated new block and the only remaining reference to it is the one you returned. So it cannot be by reference.
But it does not apply to all heap-allocated blocks. If you have heap-allocated block to which you hold pointer in member variable to be released later e.g. in destructor, you may and often will return it by reference.
But really, pointer to std::string is a code smell. std::string should most of the time should be returned by value. That is as string, string * is by pointer, not by value.
So it's left to OS to cleanup the memory. Right?
Right.
You leak the memory.
Your OS will have to reclaim the memory itself when your process ends, or it'll remain allocated until power down.
Please don't do this.
Stop using new immediately: just create a friendly new std::string object and return it. Let the compiler's optimisations and/or move semantics sort everything out.
I'm writing a function to output a basic hours & minutes string in 24 hour format from two global int's containing hours and minutes.
I've defined these during initialization:
int g_alarmHours = 7;
int g_alarmMinutes = 0;
The function to return the string is:
char* getAlarmTime() {
int hours = g_alarmHours;
int minutes = g_alarmMinutes;
char t[6];
t[0] = (hours/10) + '0';
t[1] = (hours%10) + '0';
t[2] = ':';
t[3] = (minutes/10) + '0';
t[4] = (minutes%10) + '0';
t[5] = 0;
return t;
}
The global variables are stubs to be replaced when serial comms to another device are added where those values will be retrieved from.
Calling the function generates the following hex values at the character pointer:
0x20 0x4b 0x00
When I replace the top two lines of the getAlarmTime() function with the following
int hours = 7;
int minutes = 0;
The output is then what I expect, of:
07:00\0
Why is using those global variables causing the output of getAlarmTime() to go so wonky?
You are returning a pointer to a local variable on the stack. The memory the pointer is pointing at is no longer valid and accessing that memory invokes undefined behavior. The reason why you are seeing such strange behavior is because anything can happen when you invoke undefined behavior.
The solution to your problem would be to code in C++ and use std::string.
std::string t;
t.push_back((hours/10) + '0');
...
return t;
You are returning a pointer to an array that is local to your function only. Thus when your function exits the array that was created in your function no longer exists and any attempt to access that memory will result in undefined behaviour.
Why is using those global variables causing the output of getAlarmTime() to go so wonky?
You are actually looking at undefined behavior here, because you are returning the address of a local (stack) variable.
The following sequence takes place:
You call getAlarmTime.
compiler allocates stack space for it's variables (hours, minutes and t).
Then t is filled
you return t's address.
control exits function and the address you returned points to unused stack space.
Subsequent stack data (variables declared afterwards or other function calls) will overwrite this space.
Solution: Consider returning a std::string instead of a char*.
You're returning a pointer to a local array. It is destroyed before the caller can access it, giving undefined behaviour; in practice it may or may not be overwritten with someone else's data.
The usual solution would be to return a dynamic array (such as std::string); but since you say you have extreme memory restrictions that would be a bad idea here.
I would modify the function so that the caller supplies the buffer:
void getAlarmTime(char t[6]) {
int hours = g_alarmHours;
int minutes = g_alarmMinutes;
t[0] = (hours/10) + '0';
t[1] = (hours%10) + '0';
t[2] = ':';
t[3] = (minutes/10) + '0';
t[4] = (minutes%10) + '0';
t[5] = 0;
}
Beware that the caller is now responsible for making sure the buffer is large enough. Even though I declared the parameter as char[6], that serves only as documentation; to the compiler it's the same as char*.
Another possibility is to make the local buffer static; but beware that the function will no longer be reentrant or thread-safe, which could lead to weird bugs.
Why is using those global variables causing the output of getAlarmTime() to go so wonky?
My guess would be that, when you initialise the local variables with constants, the compiler eliminates them and uses the constants instead. This moves the array to somewhere else in the stack, where it happens not to be overwritten before you examine it. But this is all in the realms of undefined behaviour, so the exact details aren't of any practical interest.
You are returning a Local variable as pointer.
return t;
The Ideone compiler returned the following error while compiling:
prog.cpp: In function ‘char* getAlarmTime()’: prog.cpp:8:8: warning:
address of local variable ‘t’ returned [-Wreturn-local-addr] char
t[6];
But i don't understand how it works when you replace the 1st 2 lines with
int hours = 7;
int minutes = 0;
Use string or pass by deference to solve your issue. Or even a Global variable can solve your issue.
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.