Returned pointers in functions
Is the following code legal?
char* randomMethod1() {
char* ret = "hello";
return ret;
}
and this one?
char* randomMethod2() {
char* ret = new char[10];
for (int i = 0; i < 9; ++i) {
ret[i] = (char)(65 + i);
}
ret[9] = '\0';
return ret;
}
I would say the former is legal, as what you are actually doing is returning a pointer to a string literal, which I believe is being loaded from the program's string table. However, I would say the second is not. I would say that in the second method, you allocate memory on the stack, which, once you leave this function, can be used by another method, turning to garbage the pointer you are returning. How it works?
edit: Ok, here's the parsed code. Can anyone please explain to me how I can see it being allocated on the heap?
char* randomMethod2() {
000536E0 push ebp
000536E1 mov ebp,esp
000536E3 sub esp,0E4h
000536E9 push ebx
000536EA push esi
000536EB push edi
000536EC lea edi,[ebp-0E4h]
000536F2 mov ecx,39h
000536F7 mov eax,0CCCCCCCCh
000536FC rep stos dword ptr es:[edi]
char* ret = new char[10];
000536FE push 0Ah
00053700 call operator new (511E0h)
00053705 add esp,4
00053708 mov dword ptr [ebp-0E0h],eax
0005370E mov eax,dword ptr [ebp-0E0h]
00053714 mov dword ptr [ret],eax
for (int i = 0; i < 9; ++i) {
00053717 mov dword ptr [i],0
0005371E jmp randomMethod2+49h (53729h)
00053720 mov eax,dword ptr [i]
00053723 add eax,1
00053726 mov dword ptr [i],eax
00053729 cmp dword ptr [i],9
0005372D jge randomMethod2+5Fh (5373Fh)
ret[i] = (char)(65 + i);
0005372F mov eax,dword ptr [i]
00053732 add eax,41h
00053735 mov ecx,dword ptr [ret]
00053738 add ecx,dword ptr [i]
0005373B mov byte ptr [ecx],al
}
0005373D jmp randomMethod2+40h (53720h)
ret[9] = '\0';
0005373F mov eax,dword ptr [ret]
00053742 mov byte ptr [eax+9],0
return ret;
00053746 mov eax,dword ptr [ret]
}
00053749 pop edi
0005374A pop esi
0005374B pop ebx
0005374C add esp,0E4h
00053752 cmp ebp,esp
00053754 call @ILT+320(__RTC_CheckEsp) (51145h)
00053759 mov esp,ebp
0005375B pop ebp
0005375C ret
source to share
Both are legal. In the second, you don't allocate memory from the stack. You are using new
and allocating memory from the heap. If you do not release the pointer returned from the second method using delete
, you will have a memory leak .
By the way, stack allocated arrays are declared like this:
char x[10]; // note that there no `new`.
Update:
This line calls operator new
, which allocates memory from the heap and initializes the object.
00053700 call operator new (511E0h)
source to share
In fact, both are legal. In the second case, you are allocating memory on the heap, not on the stack. This line:
00053700 call operator new (511E0h)
- the call operator new
that is responsible for memory allocation.
Stack allocation:
char* randomMethod2() {
char ret[10];
....
return ret;
}
will indeed result in undefined behavior.
However, don't forget that in the first case, trying to modify memory via the returned pointer will also cause undefined behavior. And in the second case, the caller is responsible for freeing memory (calling delete[]
).
source to share
With a fairly modern compiler, one should not compile first (or at least give a warning), then the fixed version is:
const char* randomMethod1() {
const char* ret = "hello";
return ret;
}
Since "hello" is a constant (in a static initialization space), it makes sense to use the address (but read-only). The second example is completely legal: you can pass (and use!) A pointer allocated with a new one as long as it is not called on it delete
. In this case, think about what you need to use delete []
(with the parenthesis operators when you allocated the array)
source to share
Both assign variables on the heap, so when you return control from the function, both pointers will be alive.
In the second function
00053700 operator call new (511E0h)
calls new to allocate memory space.
The second would be illegal if you free ret using delete [] ret before returning the control;
To allocate a variable on the heap, you need to write: int ret [10]; now you cannot return a ret pointer because it will be destroyed at the end of the function.
source to share
Both are legal. But, in my opinion, the former can lead to head scratches. And semantically this is very different from the second.
The first
It is a string literal and it will survive outside the function and last the entire duration of the program, so it is declared on the heap.
My initial reaction to the first method was wrong. I thought it was declared on the stack as it is a local variable, but not precise. Since it is a string literal, this value is stored on the heap. However, the pointer that you created and return from this function is on the stack.
Second
The second declares memory on the heap via new, but you must definitely free it later using delete to avoid a memory leak. Memory is invalid after calling free.
Yes, every call to a new one allocates memory on the heap, not the stack.
Edit: Updated based on Pete's comment below and this question .
source to share