简体   繁体   中英

Return two pointers from a function in c

I know that you can return a pointer to the first element of an array in c by doing:

#include <stdlib.h>
#include <stdio.h>

int *my_func(void);

int main(void)
{
    int *a;
    int i;

    a = my_func();

    for(i = 0; i < 3; i++)
    {
        printf("a[%d] = %d\n", i, a[i]);
    }

    free(a);

    return 0;
}

int *my_func(void)
{
    int *array;
    int i;

    array = calloc(3, sizeof(int));

    for(i = 0; i < 3; i++)
    {
        array[i] = i;
    }

    return array;
}

But if I wanted to return two pointers instead of just one, I tried:

#include <stdlib.h>
#include <stdio.h>

int *my_func(int *);

int main(void)
{
    int *a;
    int *b;
    int i;

    a = my_func(b);

    for(i = 0; i < 3; i++)
    {
        printf("a[%d] = %d\n", i, a[i]);
        printf("b[%d] = %d\n", i, b[i]);
    }

    free(a);
    free(b);

    return 0;
}

int *my_func(int *array2)
{
    int *array;
    int i;

    array = calloc(3, sizeof(int));
    array2 = calloc(3, sizeof(int));

    for(i = 0; i < 3; i++)
    {
        array[i] = i;
        array2[i] = i;
    }

    return array;
}

But this seg faults on the printf for b. I ran it through valgrind and it says that there is an invalid read of size 4 at the printf for b, which means I'm doing something screwy with the b pointer. I was just wondering what the best way to "return" a second pointer to an array was in c? I'm asking because I would like to do it this way rather than use a global variable (I'm not opposed to them, as they are useful at times, I just prefer not to use them if possible). The other questions I've seen on this site used statically allocated arrays, but I haven't yet stumbled across a question that was using dynamic allocation. Thanks in advance!

I can think of three (and a half) simple ways to return multiple items of any kind from a C-function. The ways are described below. It looks like a lot of text, but this answer is mostly code, so read on:

  1. Pass in an output argument as you have done, but do it correctly. You have to allocate space for an int * in main() and then pass the pointer to that to my_func .

    In main() :

     a = my_func(&b); 

    my_func() becomes:

     int *my_func(int **array2) { int *array; int i; array = calloc(3, sizeof(int)); *array2 = calloc(3, sizeof(int)); for(i = 0; i < 3; i++) { array[i] = i; (*array2)[i] = i; } return array; } 
  2. Make your function allocate array of two pointers to the int arrays you are trying to allocate. This will require an additional allocation of two int pointers, but may be worth the trouble.

    main() then becomes:

     int main(void) { int **ab; int i; ab = my_func(b); for(i = 0; i < 3; i++) { printf("a[%d] = %d\\n", i, ab[0][i]); printf("b[%d] = %d\\n", i, ab[1][i]); } free(ab[0]); free(ab[1]); free(ab); return 0; } 

    my_func() then becomes:

     int **my_func(void) { int **arrays; int i, j; arrays = calloc(2, sizeof(int *)); arrays[0] = calloc(3, sizeof(int)); arrays[1] = calloc(3, sizeof(int)); for(j = 0; j < 2; j++) { for(i = 0; i < 3; i++) { arrays[j][i] = i; } } return arrays; } 
  3. Return a structure or structure pointer. You will need to define the structure, and decide whether you want to return the structure itself, a newly allocated pointer to it, or pass it in as a pointer and have my_func() fill it in for you.

    The structure definition would look something like this:

     struct x { int *a; int *b; } 

    You would then rephrase your current functions as one of the following three options:

    1. Direct passing of structure (not recommended for general use):

       int main(void) { struct x ab; int i; ab = my_func(); for(i = 0; i < 3; i++) { printf("a[%d] = %d\\n", i, ab.a[i]); printf("b[%d] = %d\\n", i, ab.b[i]); } free(ab.a); free(ab.b); return 0; } struct x my_func(void) { struct x ab; int i; ab.a = calloc(3, sizeof(int)); ab.b = calloc(3, sizeof(int)); for(i = 0; i < 3; i++) { ab.a[i] = i; ab.b[i] = i; } return ab; } 
    2. Return a pointer to a dynamically allocated structure (this is a pretty good option in general):

       int main(void) { struct x *ab; int i; ab = my_func(); for(i = 0; i < 3; i++) { printf("a[%d] = %d\\n", i, ab->a[i]); printf("b[%d] = %d\\n", i, ab->b[i]); } free(ab->a); free(ab->b); free(ab); return 0; } struct x *my_func(void) { struct x *ab; int i; ab = malloc(sizeof(struct x)); ab->a = calloc(3, sizeof(int)); ab->b = calloc(3, sizeof(int)); for(i = 0; i < 3; i++) { ab->a[i] = i; ab->b[i] = i; } return ab; } 
    3. Allocate the structure in main() and fill it in in my_func via a passed-in pointer. This option is often used in a way where my_func would allocate the structure if you pass in a NULL pointer, otherwise it would return whatever you passed in. The version of my_func shown here has no return value for simplicity:

       int main(void) { struct x ab; int i; my_func(&ab); for(i = 0; i < 3; i++) { printf("a[%d] = %d\\n", i, ab.a[i]); printf("b[%d] = %d\\n", i, ab.b[i]); } free(ab.a); free(ab.b); return 0; } void my_func(struct x *ab) { int i; ab->a = calloc(3, sizeof(int)); ab->b = calloc(3, sizeof(int)); for(i = 0; i < 3; i++) { ab->a[i] = i; ab->b[i] = i; } return; } 

For all the examples shown here, don't forget to update the declaration of my_func at the top of the file, although I am sure any reasonable compiler will remind you if you forget.

Keep in mind also that these are just three options I pulled out of my brain at a moments notice. While they are likely to cover 99% of any use cases you may come up against any time soon, there are (probably lots of) other options out there.

Function parameters are its local variables. Functions deal with copies of values of the supplied arguments.

You can imagine your function definition and its call the following way

a = my_func(b);


int *my_func( /* int *array2 */ )
{
    int *array2 = b;
    //...
}

So any changes of the local variable array2 inside the function do not influence on the original argument b .

For such a function definition you have to pass the argument by reference that is the function should be declared like

int *my_func( int **array2 );
                  ^^

There are many ways to implement the function. You could define a structure of two pointers as for example

struct Pair
{
    int *a;
    int *b;
};

and use it as the return type of the function

struct Pair my_func( void );

Another approach is to pass to the function an array of pointers to the original pointers.

The function can look as it is shown in the demonstrative program.

#include <stdio.h>
#include <stdlib.h>

size_t multiple_alloc( int ** a[], size_t n, size_t m )
{
    for ( size_t i = 0; i < n; i++ ) *a[i] = NULL;

    size_t k = 0;

    for ( ; k < n && ( *a[k] = malloc( m * sizeof( int ) ) ) != NULL; k++ )
    {
        for ( size_t i = 0; i < m; i++ ) ( *a[k] )[i] = i;
    }

    return k;
}

#define N   2
#define M   3

int main(void) 
{
    int *a;
    int *b;

    multiple_alloc( ( int ** [] ) { &a, &b }, N, M );

    if ( a )
    {
        for ( size_t i = 0; i < M; i++ ) printf( "%d ", a[i] );
        putchar( '\n' );
    }

    if ( b )
    {
        for ( size_t i = 0; i < M; i++ ) printf( "%d ", b[i] );
        putchar( '\n' );
    }

    free( a );
    free( b );

    return 0;
}

The program output is

0 1 2 
0 1 2 
#include <stdlib.h>
#include <stdio.h>

int *my_func(int **);

int main(void)
{
    int *a;
    int *b;
    int i;

    b=(int *)malloc(sizeof(int));

    a = my_func(&b);


    for(i = 0; i < 3; i++)
    {
        printf("a[%d] = %d\n", i, a[i]);
        printf("b[%d] = %d\n", i, b[i]);
    }

    free(a);
    free(b);

    return 0;
}

int *my_func(int **array2)
{
    int *array;
    int i;


    array = calloc(3, sizeof(int));
    *array2 =calloc(3,sizeof(int));

    for(i = 0; i < 3; i++)
    {
        array[i] = i;
        *((*array2)+i)=i;//or (*array2)[i]

    }

    return array;
}

Pass the pointer by reference. Because its the same logic as, to manipulate an integer block you need to pass a pointer to it. Similarly, to manipulate a pointer, you will have to pass a pointer to it(ie pointer to pointer).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM