How to return different types from a single function

…衆ロ難τιáo~ 提交于 2019-11-29 08:59:42
Sourav Ghosh

The problem as I see it, you're trying to return the address of a local variable from a function (scope) and trying to access the returned memory from the caller. In the caller, the memory is invalid and any usage will lead to undefined behavior.

Solution: You need to use dynamic memory allocation for the pointer (malloc()/ calloc()) which you want to return from the function. This will overcome the issue here, as the lifetime of the dynamically allocated memory is untill free()-d manually or till program termination, whichever is earlier.

Having said that, this approach is not a good one. If all you want to return one of multiple types, go for a struct containing members for all types and use a flag to mark the type. Fill the corresponding member variable, set the flag and return the structure variable.

For better, you can actually use an union as a member of the structure, as you only need one type at a time. For a working code, please refer to the other answer by @pmg.

You can return (a struct containing) an union

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

union members {
    int *intp;
    char *charp;
    double doublev;
};
struct group {
    int lastunionmember;
    union members x;
};

struct group f1(void) {
    struct group r = {0};
    int choice = rand() % 3;

    if (choice == 0) {
        r.x.intp = malloc(sizeof (int)); // remember to free(intp) at some time
        *r.x.intp = 42;
        r.lastunionmember = 1;
    }
    if (choice == 1) {
        r.x.charp = malloc(42); // remember to free(charp) at some time
        strcpy(r.x.charp, "forty two");
        r.lastunionmember = 2;
    }
    if (choice == 2) {
        r.x.doublev = 3.14159;
        r.lastunionmember = 3;
    }
    return r;
}

int main(void) {
    struct group x;
    srand(time(0));
    for (int k = 0; k < 20; k++) {
        x = f1();
        switch (x.lastunionmember) {
            default: printf("invalid value\n"); break;
            case 1: printf("int value is %d\n", *x.x.intp); break;
            case 2: printf("string is \"%s\"\n", x.x.charp); break;
            case 3: printf("double value is %f\n", x.x.doublev); break;
        }
    }
}

See the code running at ideone.

Your problem is that you are returning the address of a local scoped variable. You have to use dynamic allocation to do what you want to do.

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

void *func(int a)
{
    void *retVal = NULL;

    if (a==3)
    {
        retVal = malloc(sizeof(int));
        if (retVal != NULL)
        {
            *((int *)(retVal)) = 5;
        }
    }
    else if (a==4)
    {
        retVal = malloc(sizeof(int));
        if (retVal != NULL)
        {
            *((char *)(retVal)) = 'b';
        }
    }
    else
    {
        fprintf(stderr, "return value is NULL");
    }

    return retVal;
}

int main ()
{
    int *ptr_int = func(3);
    char *ptr_char = func(4);

    fprintf(stdout, "int value = %d\n", *ptr_int);
    fprintf(stdout, "char value = %c\n", *ptr_char);

    free(ptr_int);
    free(ptr_char);

    return 0;
}

This is because the values that you return the pointers to are of local scope. This means that when the function returns the a_char and a_int variables effectively no longer exist, thus references to them (the pointers) are invalid.

The reason that you see the random output is because the memory that was used by those variables is now being used by something else.

You could either declare these variables at a wider scope (i.e. file scope or program scope) or use dynamic memory allocation.

This example uses file scope variables:

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

static int a_int = 5;
static char a_char = 'b'

void *func(int a) { 
    if (a==3) {
        return (void *)&a_int;
    } 
    else if (a==4) {
        return (void *)&a_char;
    }
    else {
        fprintf(stderr, "return value is NULL");
        return NULL;
    }
}

int main (int argc, char *argv[]) {
    int *ptr_int = (int *)func(3);
    char *ptr_char = (char *)func(4);
    fprintf(stdout, "int value = %d\n", *ptr_int);
    fprintf(stdout, "char value = %c\n", *ptr_char);
    return 0; 
}

In this specific case you could also just return strings (which would be thread-safe):

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

char * func(int a) {
    if (a == 3) {
        return "5";
    } else if (a == 4) {
        return "b";
    } else {
        return "Return value is nothing";
    }
}

int main (int argc, char *argv[]) {
    fprintf(stdout, func(3));
    fprintf(stdout, func(4));
    fprintf(stdout, func(15));
    return 0; 
}

If you want a function that return two (or more) values, you have two possibilities:

1- Make the function void and return the values as parameters by reference &

2- Declare a struct (or class) that groups the values and make the function return a value of this struct.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!