How to return different types from a single function

前端 未结 5 1602
[愿得一人]
[愿得一人] 2020-12-18 15:57

I have the following c code :

#include 
#include 

void *func(int a) { 
    if (a==3) {
        int a_int = 5;
        int *pt         


        
相关标签:
5条回答
  • 2020-12-18 16:22

    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; 
    }
    
    0 讨论(0)
  • 2020-12-18 16:22

    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.

    0 讨论(0)
  • 2020-12-18 16:34

    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;
    }
    
    0 讨论(0)
  • 2020-12-18 16:41

    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.

    0 讨论(0)
  • 2020-12-18 16:43

    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.

    0 讨论(0)
提交回复
热议问题