Thread: How do I return a reference to an array from a function

  1. #1
    Registered User
    Join Date
    Jul 2018
    Posts
    6

    Question How do I return a reference to an array from a function

    Hey guys!

    First post here. Trying to figure out how to return a reference to an array from a function. Here is a snippet of code I am working with:

    Code:
    int (*getArray())[5]{
    int arr[5]= {2, 4, 6, 8, 10};
    return &arr;
    } int main( int argc, char* argv[] ) {
    int (*arr)[5]= getArray();
    //Iterate over array
    for( int i= 1; i<= 5; i++ )
    printf("%d\n", arr[i]); return 0;
    }
    This is the output (newlines omitted)

    Code:
    20 40 60 80 100

    So my questions are:

    1. Where are these zeros coming from? How can I change the code
    to lose them?
    2. The compiler warns me that I'm returning an address to the array,
    am I to manually relinquish the memory of the array? Is this a
    closure?
    3. Is this a good way of going about returning an array from a function?
    What are some alternative methods?
    4. How do I make my code pretty/more legible for future posts?
    Last edited by dracut; 07-19-2018 at 05:29 PM. Reason: Attempting to make code pretty

  2. #2
    Registered User
    Join Date
    Dec 2017
    Posts
    1,190
    1. Where are these zeros coming from? How can I change the code to lose them?

    It's a coincidence that the values look like your values times 10. If you change your 5 values to anything else, you will still get the same output. The output is actually the total size of the array (20 bytes) times 1, 2, 3, 4 and 5. Indexing off of the array pointer like arr[i] (with indices 1 to 5) causes that. Instead you need to use it like (*arr)[i] (and the indices should be 0 to 4). But there are more problems than just that.


    2. The compiler warns me that I'm returning an address to the array, am I to manually relinquish the memory of the array? Is this a closure?

    No, it is not a closure. Do you not know what local variables are? You can't return the address of a (non-static) local variable from a function since they are stored on the stack and aren't reliably accessible after the function returns since the stack space will be reused.


    3. Is this a good way of going about returning an array from a function? What are some alternative methods?

    The closest thing to your code that works is to declare the array as static so it's not stored on the stack and remains accessible after the function returns.
    Code:
    #include <stdio.h>
    
    int (*getArray())[5] {
        static int arr[5] = {2, 5, 6, 8, 10};   
        return &arr; 
    }
    
    int main() {
        int (*arr)[5]= getArray();
        for (int i = 0; i < 5; i++)  // indices are 0 to 4
            printf("%d ", (*arr)[i]); // must access it like this
        putchar('\n');
        return 0;
    }
    But that's overkill since almost the same thing can be achieved more simply like this:
    Code:
    #include <stdio.h>
    
    int *getArray() {
        static int arr[5] = {2, 4, 6, 8, 10};
        return arr;
    }
    
    int main() {
        int *arr = getArray();
        for (int i = 0; i < 5; i++)
            printf("%d ", arr[i]);
        putchar('\n');
        return 0;
    }
    However, that's not how it would usually be done. There are two usual ways to return an array:

    1. Dynamically allocate the array and return that.
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    
    int *getArray(int size) {
        int *a = malloc(size * sizeof *a);
        for (int i = 0; i < size; i++)
            a[i] = i * 2;
        return a;
    }
    
    void printArray(const int *a, int size) {
        for (int i = 0; i < size; i++)
            printf("%d ", a[i]);
        putchar('\n');
    }
    
    int main() {
        int *a = getArray(10);
        printArray(a, 10);
        free(a);  // remember to free the memory
        return 0;
    }
    b. Declare the array in the caller and pass it in.
    This is often the best way.
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    
    void fillArray(int *a, int size) {
        for (int i = 0; i < size; i++)
            a[i] = i * 2;
    }
        
    void printArray(const int *a, int size) {
        for (int i = 0; i < size; i++)
            printf("%d ", a[i]);
        putchar('\n');
    }
    
    int main() {
        int a[10];
        fillArray(a, 10);
        printArray(a, 10);
        return 0;
    }
    We live as it were by chance, and by chance we are governed. - Seneca

  3. #3
    Registered User
    Join Date
    Dec 2017
    Posts
    1,190
    I didn't explain exactly why your original code prints 20, 40, 60, 80, 100.

    The first thing to note is that gcc is returning a NULL pointer from your getArray function. Since returning the address of a local variable is undefined behaviour, gcc is allowed to return anything it wants. Returning NULL is most likely to cause a predictable failure and alert the programmer to the problem. If it returned the actual address then the program might seem to work at first but suddenly stop working when you change something that seems unrelated. That bug would be harder to track down.

    Array indexing, a[i], is basically just shorthand for *(a + i). a + i is "pointer arithmetic", which adds the size of the object in bytes to the base pointer a, and the * dereferences the resulting pointer. Since NULL is basically 0 and the array is 20 bytes long, you get 0 + i * 20, which gives 0, 20, 40, 60, 80 for i = 0, 1, 2, 3, 4. (You originally used 1 to 5, giving 20 to 100).

    So the only thing left to explain is why dereferencing a pointer with the value of 0, 20, 40, etc doesn't cause a segfault. The answer is that it isn't being dereferenced. Whether you print *(arr + i) or (arr + i) (with arr being what you returned from your original function), gcc generates exactly the same assembly code, basically what you would expect with the latter. Presumably this is because the address of an array is the address of its first element, i.e., given int a[5], a and &a are the same. So the compiler treats &a and *&a essentially the same way.
    We live as it were by chance, and by chance we are governed. - Seneca

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 2
    Last Post: 01-10-2016, 01:23 AM
  2. Replies: 4
    Last Post: 01-23-2008, 06:21 AM
  3. Pass an array to a function by reference?
    By Loic in forum C++ Programming
    Replies: 3
    Last Post: 06-04-2007, 11:44 PM
  4. Passing an array as reference to a function?
    By Kylecito in forum C++ Programming
    Replies: 10
    Last Post: 03-11-2006, 02:25 AM

Tags for this Thread