Как вернуть разные типы из одной функции

У меня есть следующий код c:

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

void *func(int a) { 
    if (a==3) {
        int a_int = 5;
        int *ptr_int = &a_int;
        return (void *)ptr_int;
    } 
    else if (a==4) {
        char a_char = 'b';
        char *ptr_char = &a_char;
        return (void *)ptr_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; 
}


Но когда я использую gcc для тестирования этого кода, я получаю следующие результаты:

int value = 98
char value = �
[email protected]:/home/bohao/Desktop/test1375# gcc test.c -o test
[email protected]:/home/bohao/Desktop/test1375# ./test 
int value = 98
char value = 
[email protected]:/home/bohao/Desktop/test1375# gcc test.c -o test
[email protected]:/home/bohao/Desktop/test1375# ./test 
int value = 98
char value = 
[email protected]:/home/bohao/Desktop/test1375# gcc test.c -o test
[email protected]:/home/bohao/Desktop/test1375# ./test 
int value = 98
char value = 
[email protected]:/home/bohao/Desktop/test1375# gcc test.c -o test
[email protected]:/home/bohao/Desktop/test1375# ./test 
int value = 98
char value = 
[email protected]:/home/bohao/Desktop/test1375# gcc test.c -o test
[email protected]:/home/bohao/Desktop/test1375# ./test 
int value = 98
char value = g
[email protected]:/home/bohao/Desktop/test1375# gcc test.c -o test
[email protected]:/home/bohao/Desktop/test1375# ./test 
int value = 98
char value = 
[email protected]:/home/bohao/Desktop/test1375# gcc test.c -o test
[email protected]:/home/bohao/Desktop/test1375# ./test 
int value = 98
char value = !

Почему у меня есть98 для ptr_int ислучайное значение из ptr_char?
Что я хочу это иметьобщая функция который может возвращать различные типы значений вместо использования двух функций. Это возможно ? Если да, то как это сделать?

 Gilad Naaman25 мая 2016 г., 11:53
Нет, вы не можете вернуть несколько типов.
 StoryTeller25 мая 2016 г., 12:03
@MartinJames, возвращение по значению или выходному параметру может быть лучше, если различные члены варианта достаточно малы ...
 Bohao LI25 мая 2016 г., 11:55
@GiladNaaman Так что нельзя сделать общую функцию?
 Some programmer dude25 мая 2016 г., 11:55
ИМО ты должен переосмыслить свой дизайн.
 Martin James25 мая 2016 г., 12:01
Вернуть динамически размещенный вариантный тип. Это действительно так.
 LPs25 мая 2016 г., 11:53
Вы не можете вернуть выделенный указатель стека (локальная область) из функции ....
 Tom Karzes25 мая 2016 г., 12:01
Автоматические переменные не сохраняются после возврата функции. Они расположены в стеке. Это очень, очень простой C.

Ответы на вопрос(5)

Решение Вопроса

Проблема, как я понимаю, вы пытаетесьreturn адрес локальной переменной из функции (области видимости) и попытки доступа к возвращенной памяти от вызывающей стороны. В звонилке память естьнедействительным и любое использование приведет кнеопределенное поведение.

Решение: вам нужно использовать динамическое выделение памяти для указателя (malloc()/ calloc()) который вы хотитеreturn из функции. Это решит проблему здесь, так как время жизни динамически распределенной памяти доfree()-d вручную или до завершения программы, в зависимости от того, что наступит раньше.

Сказав это, этот подход не является хорошим. Если все, что вы хотите вернуть один из нескольких типов, перейдите кstruct содержащий члены для всех типов и использовать флаг, чтобы отметить тип. Заполните соответствующую переменную-член, установите флаг иreturn переменная структуры.

Для лучшего вы можете использоватьunion как член структуры, так как вам нужно толькоодин тип за один раз, Для рабочего кода, пожалуйста, обратитесь кдругой ответ от@pmg.

 Sourav Ghosh25 мая 2016 г., 15:02
Причина для понижения?
 Bohao LI25 мая 2016 г., 12:00
Очень ясный ответ, теперь я понимаю, спасибо.
 StoryTeller25 мая 2016 г., 12:05
Поскольку вы хотите использовать только один тип за раз, я бы рекомендовал теговое объединение, а не просто структуру.
 Bohao LI25 мая 2016 г., 12:27
@SouravGhosh Он, очевидно, сделал то, что вы сказали :) Я уже заметил это.
 Sourav Ghosh25 мая 2016 г., 12:24
@ BohaoLI Смотрите ответ сэра PMG, этого должно быть достаточно для вас. :)

Ваша проблема в том, что вы возвращаете адрес локальной переменной области действия. Вы должны использовать динамическое распределение, чтобы делать то, что вы хотите сделать.

#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;
}
 Bohao LI25 мая 2016 г., 12:20
Спасибо, это хороший ответ.

Если вам нужна функция, которая возвращает два (или более) значения, у вас есть две возможности:

1- сделать функциюvoid и вернуть значения в качестве параметров по ссылке &

2. Объявите структуру (или класс), которая группирует значения и заставляет функцию возвращать значение этой структуры.

 Bohao LI25 мая 2016 г., 11:58
Но если я сделаю функцию недействительной, я не смогу вернуть указатели, я думаю, верно?
 AhmadWabbi25 мая 2016 г., 12:08
Вы не можете вернуть указатель на локальную переменную в любом случае. Но если вы правильно разместите указатель, вы можете вернуть указатель по ссылке. Просто назначьте его параметру.

Это потому, что значения, на которые вы возвращаете указатели, имеютлокальная сфера, Это означает, что когда функция возвращаетa_char а такжеa_int Переменные фактически больше не существуют, поэтому ссылки на них (указатели) недействительны.

Причина, по которой вы видите случайный вывод, заключается в том, что память,было используемые этими переменными теперь используются чем-то другим.

Вы можете объявить эти переменные в более широкой области (например, в области файлов или программ) или использовать динамическое выделение памяти.

В этом примере используются переменные области видимости файла:

#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; 
}

В этом конкретном случае вы также можете просто вернуть строки (которые будут поточно-ориентированными):

#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; 
}
 Toby25 мая 2016 г., 13:08
Если вы не хотите использовать статические переменные, то метод динамического распределения памяти - это метод, который нужно использовать. Тем не менее, в идеале я бы переосмыслил дизайн, который требует, чтобы функция возвращала два разных типа. Возьмите ваш код в качестве примера, он печатает оба выхода независимо от типа; это означает, что функция может вернуть толькоchars один будучиперсонаж '5' и другие'b'.
 Bohao LI25 мая 2016 г., 12:11
Я хочу иметь как можно меньше статических переменных, потому что статические переменные приведут к поточно-ориентированным проблемам позже.

Вы можете вернуть (структура, содержащая) объединение

#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;
        }
    }
}

Увидетькод работает на Ideone.

 Bohao LI25 мая 2016 г., 12:23
Спасибо, это полезно.
 Sourav Ghosh25 мая 2016 г., 12:23
Ссылка вашего ответа (кода) на мой. :)
 LPs25 мая 2016 г., 12:24
Почему бы просто не избежать указателей внутри объединения и не выделить указатель типа объединения?union members *my_var = malloc(sizeof(union members));
 pmg25 мая 2016 г., 12:31
Это возможность @LPs, но это не мешает выделять место для строки.

Ваш ответ на вопрос