C++ Correct Way to Return Pointer to Array from Function

C++ correct way to return pointer to array from function

Your code as it stands is correct but I am having a hard time figuring out how it could/would be used in a real world scenario. With that said, please be aware of a few caveats when returning pointers from functions:

  • When you create an array with syntax int arr[5];, it's allocated on the stack and is local to the function.
  • C++ allows you to return a pointer to this array, but it is undefined behavior to use the memory pointed to by this pointer outside of its local scope. Read this great answer using a real world analogy to get a much clear understanding than what I could ever explain.
  • You can still use the array outside the scope if you can guarantee that memory of the array has not be purged. In your case this is true when you pass arr to test().
  • If you want to pass around pointers to a dynamically allocated array without worrying about memory leaks, you should do some reading on std::unique_ptr/std::shared_ptr<>.

Edit - to answer the use-case of matrix multiplication

You have two options. The naive way is to use std::unique_ptr/std::shared_ptr<>. The Modern C++ way is to have a Matrix class where you overload operator * and you absolutely must use the new rvalue references if you want to avoid copying the result of the multiplication to get it out of the function. In addition to having your copy constructor, operator = and destructor, you also need to have move constructor and move assignment operator. Go through the questions and answers of this search to gain more insight on how to achieve this.

Edit 2 - answer to appended question

int* test (int a[5], int b[5]) {
int *c = new int[5];
for (int i = 0; i < 5; i++) c[i] = a[i]+b[i];
return c;
}

If you are using this as int *res = test(a,b);, then sometime later in your code, you should call delete []res to free the memory allocated in the test() function. You see now the problem is it is extremely hard to manually keep track of when to make the call to delete. Hence the approaches on how to deal with it where outlined in the answer.

How to return pointers to arrays from functions?

The correct definition of the function would be:

int (*returnPtrArray(int (*arr)[10]))[10]
{
return arr;
}

Breaking this down: returnPtrArray is a function:

returnPtrArray()

That takes a pointer to an array of 10 int:

returnPtrArray(int (*arr)[10])

And returns a pointer:

*returnPtrArray(int (*arr)[10])

To an array of size 10:

(*returnPtrArray(int (*arr)[10]))[10]

Of int:

int (*returnPtrArray(int (*arr)[10]))[10]

And you would call it like this:

int a[5][10];
int (*ptr)[10] = returnPtrArray(a);

Returning an array of pointers from a function

#include <stdio.h>

int** c2i(char *str) {

int i=0, *result, **ptr;
result = (int *)malloc(20*sizeof(int)) ;
ptr = (int **)malloc(10*sizeof(int *)) ;

while(*(str+i)!='\0'){
result[i]=*(str+i) & 0xff;
ptr[i]=&result[i];
i++;
}
printf("%d %d %d %d %p %p %p %p", *ptr[0], *ptr[1], *ptr[2], *ptr[3], ptr[0], ptr[1], ptr[2], ptr[3]);

return ptr;
}
int main(){

char s[20];
int **p, i;
printf("Enter your string:\n");
scanf("%s", s);
p=c2i(s);
for(i=0; i<4; i++){
printf("\n%d\t%p\n", **p, *p);
p++;
}

return 0;
}

double-pointer might solve your issue, look at your modified code..this gives you the desired result.here i'm attaching the screen shot of execution..Sample Image

Returning an array using C

You can't return arrays from functions in C. You also can't (shouldn't) do this:

char *returnArray(char array []){
char returned [10];
//methods to pull values from array, interpret them, and then create new array
return &(returned[0]); //is this correct?
}

returned is created with automatic storage duration and references to it will become invalid once it leaves its declaring scope, i.e., when the function returns.

You will need to dynamically allocate the memory inside of the function or fill a preallocated buffer provided by the caller.

Option 1:

dynamically allocate the memory inside of the function (caller responsible for deallocating ret)

char *foo(int count) {
char *ret = malloc(count);
if(!ret)
return NULL;

for(int i = 0; i < count; ++i)
ret[i] = i;

return ret;
}

Call it like so:

int main() {
char *p = foo(10);
if(p) {
// do stuff with p
free(p);
}

return 0;
}

Option 2:

fill a preallocated buffer provided by the caller (caller allocates buf and passes to the function)

void foo(char *buf, int count) {
for(int i = 0; i < count; ++i)
buf[i] = i;
}

And call it like so:

int main() {
char arr[10] = {0};
foo(arr, 10);
// No need to deallocate because we allocated
// arr with automatic storage duration.
// If we had dynamically allocated it
// (i.e. malloc or some variant) then we
// would need to call free(arr)
}

Returning an array from function in C

… I noticed that the memory of the internal array in my function wasn't deallocated…

Deallocation of memory is not something you can notice or observe, except by looking at the data that records memory reservations (in this case, the stack pointer). When memory is reserved or released, that is just a bookkeeping process about what memory is available or not available. Releasing memory does not necessarily erase memory or immediately reuse it for another purpose. Looking at the memory does not necessarily tell you whether it is in use or not.

When int arr[10] = { 0 }; appears inside a function, it defines an array that is allocated automatically when the function starts executing (or at certain times within the function execution if the definition is in some nested scope). This is commonly done by adjusting the stack pointer. In common systems, programs have a region of memory called the stack, and a stack pointer contains an address that marks the end of the portion of the stack that is currently reserved for use. When a function starts executing, the stack pointer is changed to reserve more memory for that function’s data. When execution of the function ends, the stack pointer is changed to release that memory.

If you keep a pointer to that memory (how you can do that is another matter, discussed below), you will not “notice” or “observe” any change to that memory immediately after the function returns. That is why you see the value of arr_p is the address that arr had, and it is why you see the old data in that memory.

If you call some other function, the stack pointer will be adjusted for the new function, that function will generally use the memory for its own purposes, and then the contents of that memory will have changed. The data you had in arr will be gone. A common example of this that beginners happen across is:

int main(void)
{
int *p = demo(10);
// p points to where arr started, and arr’s data is still there.

printf("arr[3] = %d.\n", p[3]);
// To execute this call, the program loads data from p[3]. Since it has
// not changed, 3 is loaded. This is passed to printf.

// Then printf prints “arr[3] = 3.\n”. In doing this, it uses memory
// on the stack. This changes the data in the memory that p points to.

printf("arr[3] = %d.\n", p[3]);
// When we try the same call again, the program loads data from p[3],
// but it has been changed, so something different is printed. Two
// different things are printed by the same printf statement even
// though there is no visible code changing p[3].
}

Going back to how you can have a copy of a pointer to memory, compilers follow rules that are specified abstractly in the C standard. The C standard defines an abstract lifetime of the array arr in demo and says that lifetime ends when the function returns. It further says the value of a pointer becomes indeterminate when the lifetime of the object it points to ends.

If your compiler is simplistically generating code, as it does when you compile using GCC with -O0 to turn off optimization, it typically keeps the address in p and you will see the behaviors described above. But, if you turn optimization on and compile more complicated programs, the compiler seeks to optimize the code it generates. Instead of mechanically generating assembly code, it tries to find the “best” code that performs the defined behavior of your program. If you use a pointer with indeterminate value or try to access an object whose lifetime has ended, there is no defined behavior of your program, so optimization by the compiler can produce results that are unexpected by new programmers.



Related Topics



Leave a reply



Submit