After reading this article I understand the methods for returning multiple values using structs or pointers (the first two). However, after describing the third method (using a temp array), the author writes:
We should not use this approach as the variable information is not
passed to the caller function. For example, we’re using the array’s
index to retrieve the values of our variables. Also, note that we have
to allocate the array dynamically in a heap. If we use the static
array, it ceases to exist when we exit the function, and accessing it
inside the caller function will result in undefined behavior.
This is the code example the author provides:
#include <stdio.h>
#include <stdlib.h>
// Function to return multiple values using an array
int* initialize()
{
// Important: Dynamically allocate memory
int *temp = (int*) malloc(sizeof(int) * 3);
*temp = 10;
*(temp + 1) = 20;
*(temp + 2) = 30;
return temp;
}
// Return multiple values from a function in C
int main(void)
{
int a, b, c;
int *arr = initialize();
a = arr[0];
b = arr[1];
c = arr[2];
printf("a = %d, b = %d, c = %d", a, b, c);
// free memory
return 0;
}
I don't understand what the author means, because I tried this method in a small program I wrote and it seems to works just fine, i.e. I can access the returned array's elements in the caller function. Why is this not recommended?
The referenced text is unclear and confusing at best. At worst, outright wrong.
We should not use this approach as the variable information is not passed to the caller function.
It's unclear what "variable information" means here. The actual values is getting back to the caller so that's not the problem. Maybe "variable information" is supposed to mean something like "information about number of variables" but that's unclear.
For example, we’re using the array’s index to retrieve the values of our variables.
Yes, well, of cause... If the values are being sent back in a (dynamic allocated) array, we have to use array indexing to get them. That's obvious and not really a problem.
Also, note that we have to allocate the array dynamically in a heap.
Finally something clear and correct.
If we use the static array, it ceases to exist when we exit the function, and accessing it inside the caller function will result in undefined behavior.
Here it's very unclear what "the static array" refers to. There is no static array in the code. It seems to be refering to some code only available in the authors head...
If the author is thinking about code like:
int temp[3]; // Instead of malloc
then the author is correct. But... that's not a static array so ....
If the author is thinking about code like:
static int temp[3]; // Instead of malloc
then the author is wrong. Due to static this array can be accessed from the caller.
So again... very confusing...
To answer your question:
Why is this not recommended?
Well, some concerns could be:
Dynamic allocation is an expensive operation. So don't use it unless you have a good reason.
Returning dynamic allocated memory from function and relying on the caller to free it later on is a source of many memory leak bugs. So avoid doing that.
BUT...
Good pratice rules nearly always comes with exceptions.
For instance consider a function that returns a rather huge and unknown number of results. For such a function it can be fine to return a pointer to dynamic allocated memory. But you would also need to return the actual number of results. It could look like:
int foo(int ** a)
{
// Generate results and use code like
*a = malloc(.. a lot ..)
...
// Perhaps some realloc(.. even more ..)
...
return number_of_results; // or perhaps -1 on error
}
int * a;
int results = foo(&a);
if (results > 0)
{
....
for (int i=0; i < results; ++i)
{
// Do something with a[i]
...
}
....
free(a);
}
...
If we use the static array, it ceases to exist when we exit the
function, and accessing it inside the caller function will result in
undefined behavior.
It is rubbish. static automatic array will still exist after the function return. It is because such array has static storage duration The function will be not reentrant.
The author probably meant automatic storage duration array.
Undefined behaviour (UB):
int *foo(void)
{
int array[10];
/* ... */
return array;
}
No undefined behaviour:
int *bar(void)
{
static int array[10];
/* ... */
return array;
}
Related
I've written the following simple program that sums up the numbers from 0 to 9:
#include <stdio.h>
#include <stdlib.h>
int* allocArray() {
int arr[10];
return arr;
}
int main(void){
int* p;
int summe = 0;
p = allocArray();
for(int i = 0; i != 10; ++i) {
p[i] = i;
}
for(int i = 0; i != 10; ++i) {
summe += p[i];
}
printf("Sum = %d\n", summe);
}
The code compiles and delivers the expected result "45". However I get the following warning: 'address of stack memory associated with local variable
'arr' returned'. What am I doing wrong?
This is undefined behaviour, plain and simple. The only reason it "works" is because with this particular compiler the stack hasn't been trashed yet, but it is living on borrowed time.
The lifetime of arr ends immediately when the function call is complete. After that point any pointers to arr are invalidated and cannot be used.1
Your compiler uses stack memory to store local variables, and the warning indicates that you're returning an address to a now-invalidated stack variable.
The only way to work around this is to allocate memory dynamically and return that:
int* allocArray() {
int* arr = calloc(10, sizeof(int));
return arr;
}
Where you're now responsible for releasing that memory later.
You can also use static to extend the lifetime of arr:
int* allocArray() {
static int arr[10];
return arr;
}
Though this is not without consequences, either, as now arr is shared, not unique to each function call.
1 Like a lot of things in C there's significant overlap between what you "cannot do" because they lead to undefined behaviour and/or crashes and what you "can do" because it's permitted by the syntax and compiler. It's often your responsibility to know the consequences of any code you write, implied or otherwise.
To keep it in your code:
int arr[10];
will allocate the memory on the stack. As soon as you are leaving the function, the content of that array will be overwritten pretty soon. You want to allocate this on the heap.
You would need to use
int* arr = malloc(sizeof(int)*10);
and in the main function, after you've used it (at the end of main), call
delete[] arr;
Nevertheless, this code could be better if the ownership of the array would be properly handled. You want to make yourself familiar with C++ containers and shared/unique pointers.
I'm trying to store 4 arrays in an array, and for some reason, the last value keeps overriding the previous three values. For example, if 123; 456; 789; 987 were inputted into the code below, ipadr[0] - ipadr[4] would all only store 123. I've tested to make sure that numConvert() is working, and within numConvert, 4 different arrays of ints are returned, but only numConvert(d) is the ipadr array (stored 4 times).
Also, is my syntax / code correct in order for this function to return ipadr as an array of arrays (int**)? Why do you need to make it static int* when initializing the array?
I'm new to C and this has been really frustrating me. Any help would be incredibly appreciated. Thank you in advance!!
int** ipConvert(int a, int b, int c, int d){
static int* ipadr[4];
ipadr[0]=numConvert(a);
ipadr[1]=numConvert(b);
ipadr[2]=numConvert(c);
ipadr[3]=numConvert(d);
return ipadr;
}
numConvert code:
int* numConvert(int dec) {
static int hold[8];
...
return hold;
}
The hold array is indeed overwritten after each call to numConvert, because it is a static area of 8 int.
Better use dynamic allocation with malloc, and have that function allocate 8 ints.
int* numConvert(int dec) {
int *hold = (int *)malloc(sizeof(int) * 8); // C++ need cast!
int x = dec;
for(int y=7;y>=0;y--){
if(x%2==0 || x==0){
hold[y]=0;
}
else{
hold[y]=1;
}
x=x/2;
}
printf("\ntest loop: ");
for(int i=0;i<8;i++){
printf("%i", hold[i]);
}
printf("\n");
return hold;
}
then the returned values will have to be freed, after you don't need them anymore.
As for static, this answer explains it in details.
Every time you write something in hold then return it, you basically overwrite the previous value. There is single instance of hold not multiple as you may be thinking.
static keyword you have used without knowing the full functionality. It is not the same as automatic storage duration.
int* numConvert(int dec) {
int *hold = malloc(sizeof *hold *8);
if( hold == NULL){
fprintf(stderr,"Error in malloc");
exit(1);
}
int x = dec;
....
....
return hold;
}
Free the dynamically allocated memory when you are done working with it.
What have we done here?
Dynamically allocated memory has lifetime beyond the scope of the function. So just like the static one it stays alive. But with contrary to the static variable each time a new chunk of memory is allocated. And for that we are not overwriting anything, which was the primary problem in your case.
One thing more..
hold is of automatic storage duration meaning every time we exit the function the hold is deallocated and then again when we call it we get to have a local variable named hold. So in each we get different instance. And that's why we return the address contained in hold. This memory whose address hold contains has lifetime beyond the scope of the function. So it stays unlike the local variable hold and we store this address in other function.
Declare your hold variable as instance variable rather then static variable like
int* numConvert(int dec) {
int hold[8];
I'm in the process of teaching myself C and I'm mistified as to what's causing the following issue: when I create an array in a method and return it as a pointer to the calling function, none of the content is correct. I've boiled down this problem to the following example:
char * makeArr(void){
char stuff[4];
stuff[0]='a';
stuff[1]='b';
stuff[2]='c';
stuff[3]='d';
printf("location of stuff:%p\n",stuff);
int i;
for(i = 0; i < 4; i++){
printf("%c\n",stuff[i]);
}
return stuff;
}
int main(void){
char* myarr;
myarr = makeArr();
int i;
printf("\n");
printf("location of myarr:%p\n", myarr);
for(i = 0; i < 4; i++){
printf("%c\n",myarr[i]);
}
}
The output returns the following:
location of stuff:0028FF08
a
b
c
d
location of myarr:0028FF08
Ä
ÿ
(
(a null character)
So I've verified that the locations between the two values are the same, however the values differ. I imagine that I'm missing some critical C caveat; I could speculate it's something to do with an array decaying into a pointer or a problem with the variable's scope, but and any light that could be shed on this would be much appreciated.
What you're attempting to do is return the address of a local variable, one that goes out of scope when the function exits, no different to:
char *fn(void) {
char xyzzy = '7';
return &xyzzy;
}
That's because, other than certain limited situations, an array will decay into a pointer to the first element of that array.
While you can technically return that pointer (it's not invalid in and of itself), what you can't do is dereference it afterwards with something like:
char *plugh = fn();
putchar (*plugh);
To do so is undefined behaviour, as per C11 6.5.3.2 Address and indirection operators /4 (my bold):
If an invalid value has been assigned to the pointer, the behaviour of the unary * operator is undefined.
Among the invalid values for dereferencing a pointer by the unary * operator are a null pointer, an address inappropriately aligned for the type of object pointed to, and the address of an object after the end of its lifetime.
Having stated the problem, there are (at least) two ways to fix it.
First, you can create the array outside of the function (expanding its scope), and pass its address into the function to be populated.
void makeArr (char *stuff) {
stuff[0]='a';
stuff[1]='b';
stuff[2]='c';
stuff[3]='d';
}
int main(void) {
char myarr[4];
makeArr (myarr);
// Use myarr here
}
Second, you can dynamically allocate the array inside the function and pass it back. Items created on the heap do not go out of scope when a function exits, but you should both ensure that the allocation succeeded before trying to use it, and that you free the memory when you're finished with it.
char *makeArr (void) {
char *stuff = malloc (4);
if (stuff != NULL) {
stuff[0]='a';
stuff[1]='b';
stuff[2]='c';
stuff[3]='d';
}
return stuff;
}
int main(void) {
char *myarr;
myarr = makeArr();
if (myarr != NULL) {
// Use myarr here
free (myarr);
}
}
stuff[] only exists on the stack during function call, it gets written over after return. If you want it to hold values declare it static and it will do what you want.
However, the whole idea is fundamentally lame, don't do that in real life. If you want a function to initialize arrays, declare an array outside of the function, pass a pointer to this array as a parameter to the function and then initialize an array via that pointer. You may also want to pass the size of the array as a second parameter.
Since you're learning, a sample code is omitted intentionally.
Your array stuff is defined locally to the function makeArr. You should not expect it to survive past the life of that function.
char * makeArr(void){
char stuff[4];
Instead, try this:
char * makeArr(void){
char *stuff=(char*)calloc(4, sizeof(char));
This dynamically creates an array which will survive until you free() it.
Update : Sorry, just a big mistake. It is meaningless to write int *a = 3; But please just think the analogy to the case like TCHAR *a = TEXT("text"); (I edited my question, so some answers and comments are strange, since they are for my original question which is not suitable)
In main function, suppose I have a pointer TCHAR *a = TEXT("text"); Then it excutes the following code:
int i;
for (i = 0; i < 1000; i++) {
a = test(i);
}
with the function TCHAR* test(int par) defined by:
TCHAR* test(int par)
{
TCHAR *b = TEXT("aaa");
return b;
}
My question is, after executing the above code, but before the program ends, in the memory:
1. the pointer `a` remains?
2. The 1000 pointers `b` are deleted each time the function test(...) exits ?
3. But there are still 1000 memory blocks there?
In fact, my question is motivated from the following code, which shows a tooltip when mouse is over a tab item in a tab control with the style TCS_TOOLTIPS:
case WM_NOTIFY
if (lpnmhdr->code == TTN_GETDISPINFO) {
LPNMTTDISPINFO lpnmtdi;
lpnmtdi = (LPNMTTDISPINFO)lParam;
int tabIndex = (int) wParam; // wParam is the index of the tab item.
lpnmtdi->lpszText = SetTabToolTipText(panel->gWin.At(tabIndex));
break;
}
I am thinking if the memory usage increases each time it calls
SetTabToolTipText(panel->gWin.At(tabIndex)), which manipulates with TCHAR and TCHAR* and return a value of type LPTSTR.
Yes, the pointer a remains till we return from the main function
The variable b (a 4-byte pointer) is automatic. It is created each time we call test function. Once we return from it, the variable disappears (the pointer). Please note, the value to which b points isn't affected.
No. In most of the cases, I think, there will be only one block allocated during compilation time (most likely in the read-only memory) and the function will be returning the same pointer on every invocation.
If SetTabToolTipText allocates a string inside using some memory management facilities new/malloc or some os-specific, you should do an additional cleanup. Otherwise there'll be a memory leak.
If nothing like this happens inside (it's not mentioned in the documentation or comments etc), it's most likely returning the pointer to some internal buffer which you typically use as readonly. In this case, there should be no concerns about a memory consumption increase.
You dont allocate any memory so you don't have to worry about memory being freed. When your vaiables go out of scope they will be freed automatically. In this function
int test(int par)
{
int *b = par;
}
you don't have a return value even though the function says that is will return an int, so you should probably do so as in this line
for (i = 0; i < 1000; i++) {
a = test(i);
}
you assign to a the value that is returned by test(). Also
int* a = 3;
int* b = par;
are asking for trouble. You are assigning integer values to a pointer variable. You should probably rethink your above code.
Pointer should contain adress... so int* a = 3 is something meaningless... And in function you don't allocate memory for int (only for par variable, which then destroy when the function ends), you allocate memory for storing adress in int* b, this memory also free when the funciton ends.
I'm about to debug someone else's code and I stumbled across a certain 'way' of handling with global arrays which I consider deeply bad, but the one who first used it swears to it.
I need to find arguments against it.
Here is the code written simplified (this is not the original code, just an abstracted version)
So my question: which arguments would you bring against (or maybe some code which brings down this method) this?
int test(int i, int v, int type, int** t)
{
static int *teeest;
int result = 0;
switch(type)
{
case (1):
{
int testarr[i];
teeest = testarr;
}
break;
case (2):
result = teeest[i];
break;
case (3):
teeest[i] = v;
break;
}
if (t != NULL)
{
*t = teeest;
}
return result;
}
int main()
{
int *te = (int*)1;
test(5, 0, 1, &te);
printf("%p\n", te);
int i=0;
for(;i<5;i++)
{
test(i, i, 3, NULL);
printf("Value: %d\n", test(i,0,2, NULL));
}
return 0;
}
local variables are dead after the block they declared in, so this code is undefined behavior. Like every accessing random address, it may work, but it also may not work.
Note that if you use malloc instead of int testarr[i], (and worry to free the previous array, and to initialize teeest), it will be correct. the problems of this code have nothing about static pointers.
This is really bad. Just because the pointer is static doesn't mean the data it points to will be around. For example, testarr disappears when the function exits and the returned pointer, if used, might cause dragons to appear.
It seems to me the big downfall of this style is that you are hiding the fact that you are accessing a locally declared array which is on the stack. Then you persist a pointer to your stack which will persist through calls, which will have different stacks each call.
Another thing I was thinking about is that you have hidden from the developer what the data structure is. Indexing an array is a normal operation. Indexing a pointer makes the developer acknowledge it is an array and not a more complex data type. This also adds confusion to bounds checking.
Another thing is, that all disadvantages of global variables apply directly. The code is not reentrant, and hard to make thread-safe (if that's a concern).