Se eu tenho uma função que produz um resultado int
e um resultado string
, como faço para retornar os dois de uma função?
Até onde sei, só posso retornar uma coisa, conforme determinado pelo tipo que precede o nome da função.
c
return-value
Tony Stark
fonte
fonte
string
que você quer dizer "Eu estou usando C ++ e esta é astd::string
classe" ou "Eu estou usando C e este é umchar *
ponteiro ouchar[]
matriz."Respostas:
Não sei qual
string
é o seu , mas vou presumir que ele administra sua própria memória.Você tem duas soluções:
1: Retorne um
struct
que contém todos os tipos de que você precisa.struct Tuple { int a; string b; }; struct Tuple getPair() { Tuple r = { 1, getString() }; return r; } void foo() { struct Tuple t = getPair(); }
2: Use ponteiros para passar valores.
void getPair(int* a, string* b) { // Check that these are not pointing to NULL assert(a); assert(b); *a = 1; *b = getString(); } void foo() { int a, b; getPair(&a, &b); }
Qual você escolhe usar depende muito da preferência pessoal quanto à semântica que você mais gosta.
fonte
char *
asize_t
para o comprimento, a menos que seja absolutamente vital para a função alocar sua própria string e / ou retornarNULL
.getPair
então desreferencia . Dependendo do que você está fazendo (OP nunca esclareceu se esta é realmente uma questão C), a alocação pode ser uma preocupação, mas geralmente não está no terreno C ++ (a otimização do valor de retorno salva tudo isso) e no terreno C, os dados as cópias geralmente acontecem explicitamente (viastrncpy
ou qualquer outro).Option 1
: Declara uma estrutura com um int e uma string e retorna uma variável de estrutura.struct foo { int bar1; char bar2[MAX]; }; struct foo fun() { struct foo fooObj; ... return fooObj; }
Option 2
: Você pode passar um dos dois via ponteiro e fazer alterações no parâmetro real por meio do ponteiro e retornar o outro como de costume:int fun(char **param) { int bar; ... strcpy(*param,"...."); return bar; }
ou
char* fun(int *param) { char *str = /* malloc suitably.*/ ... strcpy(str,"...."); *param = /* some value */ return str; }
Option 3
: Semelhante à opção 2. Você pode passar via ponteiro e não retornar nada da função:void fun(char **param1,int *param2) { strcpy(*param1,"...."); *param2 = /* some calculated value */ }
fonte
int fun(char *param, size_t len)
strcpy
por exemplo.Como um de seus tipos de resultado é uma string (e você está usando C, não C ++), recomendo passar ponteiros como parâmetros de saída. Usar:
void foo(int *a, char *s, int size);
e chamá-lo assim:
int a; char *s = (char *)malloc(100); /* I never know how much to allocate :) */ foo(&a, s, 100);
Em geral, prefira fazer a alocação na função de chamada , não dentro da própria função, para que você possa estar o mais aberto possível para diferentes estratégias de alocação.
fonte
Duas abordagens diferentes:
Acho que o nº 1 é um pouco mais óbvio sobre o que está acontecendo, embora possa se tornar tedioso se você tiver muitos valores de retorno. Nesse caso, a opção nº 2 funciona muito bem, embora haja alguma sobrecarga mental envolvida na criação de estruturas especializadas para esse propósito.
fonte
string
, pode ser seguro assumir C ++ ...Crie uma estrutura e defina dois valores dentro e retorne a variável de estrutura.
struct result { int a; char *string; }
Você deve alocar espaço para o
char *
em seu programa.fonte
Use ponteiros como parâmetros de sua função. Em seguida, use-os para retornar vários valores.
fonte
Passando parâmetros por referência à função.
Exemplos:
void incInt(int *y) { (*y)++; // Increase the value of 'x', in main, by one. }
Também usando variáveis globais, mas não é recomendado.
Exemplo:
int a=0; void main(void) { //Anything you want to code. }
fonte
void main(void)
OH, COMO QUEIMA!main
deve retornar um código de status. Em * nix, é mais comum declará-lo comoint main(int argc, char *argv[])
, acredito que o Windows tem convenções semelhantes.Uma abordagem é usar macros. Coloque isso em um arquivo de cabeçalho
multitype.h
#include <stdlib.h> /* ============================= HELPER MACROS ============================= */ /* __typeof__(V) abbreviation */ #define TOF(V) __typeof__(V) /* Expand variables list to list of typeof and variable names */ #define TO3(_0,_1,_2,_3) TOF(_0) v0; TOF(_1) v1; TOF(_2) v2; TOF(_3) v3; #define TO2(_0,_1,_2) TOF(_0) v0; TOF(_1) v1; TOF(_2) v2; #define TO1(_0,_1) TOF(_0) v0; TOF(_1) v1; #define TO0(_0) TOF(_0) v0; #define TO_(_0,_1,_2,_3,TO_MACRO,...) TO_MACRO #define TO(...) TO_(__VA_ARGS__,TO3,TO2,TO1,TO0)(__VA_ARGS__) /* Assign to multitype */ #define MTA3(_0,_1,_2,_3) _0 = mtr.v0; _1 = mtr.v1; _2 = mtr.v2; _3 = mtr.v3; #define MTA2(_0,_1,_2) _0 = mtr.v0; _1 = mtr.v1; _2 = mtr.v2; #define MTA1(_0,_1) _0 = mtr.v0; _1 = mtr.v1; #define MTA0(_0) _0 = mtr.v0; #define MTA_(_0,_1,_2,_3,MTA_MACRO,...) MTA_MACRO #define MTA(...) MTA_(__VA_ARGS__,MTA3,MTA2,MTA1,MTA0)(__VA_ARGS__) /* Return multitype if multiple arguments, return normally if only one */ #define MTR1(...) { \ typedef struct mtr_s { \ TO(__VA_ARGS__) \ } mtr_t; \ mtr_t *mtr = malloc(sizeof(mtr_t)); \ *mtr = (mtr_t){__VA_ARGS__}; \ return mtr; \ } #define MTR0(_0) return(_0) #define MTR_(_0,_1,_2,_3,MTR_MACRO,...) MTR_MACRO /* ============================== API MACROS =============================== */ /* Declare return type before function */ typedef void* multitype; #define multitype(...) multitype /* Assign return values to variables */ #define let(...) \ for(int mti = 0; !mti;) \ for(multitype mt; mti < 2; mti++) \ if(mti) { \ typedef struct mtr_s { \ TO(__VA_ARGS__) \ } mtr_t; \ mtr_t mtr = *(mtr_t*)mt; \ MTA(__VA_ARGS__) \ free(mt); \ } else \ mt /* Return */ #define RETURN(...) MTR_(__VA_ARGS__,MTR1,MTR1,MTR1,MTR0)(__VA_ARGS__)
Isso possibilita retornar até quatro variáveis de uma função e atribuí-las a até quatro variáveis. Como exemplo, você pode usá-los assim:
multitype (int,float,double) fun() { int a = 55; float b = 3.9; double c = 24.15; RETURN (a,b,c); } int main(int argc, char *argv[]) { int x; float y; double z; let (x,y,z) = fun(); printf("(%d, %f, %g\n)", x, y, z); return 0; }
Isto é o que imprime:
(55, 3.9, 24.15)
A solução pode não ser tão portátil porque requer C99 ou posterior para macros variáveis e declarações de variáveis para instruções. Mas acho que foi interessante postar aqui. Outro problema é que o compilador não irá avisá-lo se você atribuir a eles os valores errados, então você deve ter cuidado.
Exemplos adicionais e uma versão baseada em pilha do código usando uniões estão disponíveis em meu repositório github .
fonte
__typeof__