Jeśli mam funkcję, która generuje wynik int
i wynik string
, w jaki sposób mogę zwrócić je obie z funkcji?
O ile wiem, mogę zwrócić tylko jedną rzecz, określoną przez typ poprzedzający nazwę funkcji.
c
return-value
Tony Stark
źródło
źródło
string
zrobić to znaczy „Używam C ++ i jest tostd::string
klasa” lub „Używam C i jest tochar *
wskaźnik lubchar[]
tablicą.”Odpowiedzi:
Nie wiem, jakie
string
jest twoje , ale założę, że zarządza własną pamięcią.Masz dwa rozwiązania:
1: Zwróć,
struct
który zawiera wszystkie potrzebne typy.struct Tuple { int a; string b; }; struct Tuple getPair() { Tuple r = { 1, getString() }; return r; } void foo() { struct Tuple t = getPair(); }
2: Użyj wskaźników, aby przekazać wartości.
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); }
Który z nich wybierzesz, zależy w dużej mierze od osobistych preferencji co do tego, jaką semantykę lubisz bardziej.
źródło
char *
i asize_t
dla długości, chyba że jest to absolutnie niezbędne, aby funkcja przydzieliła własny ciąg i / lub zwróciłaNULL
.getPair
następnie wyłuskuje . W zależności od tego, co robisz (OP nigdy nie wyjaśnił, czy jest to faktycznie pytanie w C), alokacja może być problemem, ale zwykle nie jest w C ++ land (optymalizacja wartości zwracanej zapisuje to wszystko), aw C land, dane kopie zwykle są jawne (przezstrncpy
lub cokolwiek).Option 1
: Zadeklaruj strukturę z int i stringiem i zwróć zmienną strukturalną.struct foo { int bar1; char bar2[MAX]; }; struct foo fun() { struct foo fooObj; ... return fooObj; }
Option 2
: Możesz przekazać jeden z dwóch za pomocą wskaźnika i wprowadzić zmiany do rzeczywistego parametru przez wskaźnik, a drugi jak zwykle zwrócić:int fun(char **param) { int bar; ... strcpy(*param,"...."); return bar; }
lub
char* fun(int *param) { char *str = /* malloc suitably.*/ ... strcpy(str,"...."); *param = /* some value */ return str; }
Option 3
: Podobnie jak w przypadku opcji 2. Możesz przekazać zarówno wskaźnik, jak i nic nie zwracać z funkcji:void fun(char **param1,int *param2) { strcpy(*param1,"...."); *param2 = /* some calculated value */ }
źródło
int fun(char *param, size_t len)
strcpy
na przykład.Ponieważ jednym z typów wyników jest łańcuch (i używasz C, a nie C ++), zalecam przekazywanie wskaźników jako parametrów wyjściowych. Posługiwać się:
void foo(int *a, char *s, int size);
i nazwij to tak:
int a; char *s = (char *)malloc(100); /* I never know how much to allocate :) */ foo(&a, s, 100);
Ogólnie rzecz biorąc, preferuj alokację w funkcji wywołującej , a nie w samej funkcji, abyś mógł być jak najbardziej otwarty na różne strategie alokacji.
źródło
Dwa różne podejścia:
Myślę, że # 1 jest trochę bardziej oczywiste, jeśli chodzi o to, co się dzieje, chociaż może to być nudne, jeśli masz zbyt wiele wartości zwracanych. W takim przypadku opcja nr 2 działa całkiem dobrze, chociaż tworzenie wyspecjalizowanych struktur do tego celu wiąże się z pewnym obciążeniem umysłowym.
źródło
string
, może być bezpiecznie założyć, C ++ ...Utwórz strukturę i ustaw dwie wartości wewnątrz i zwróć zmienną strukturalną.
struct result { int a; char *string; }
Musisz przeznaczyć miejsce na program
char *
w swoim programie.źródło
Użyj wskaźników jako parametrów funkcji. Następnie użyj ich do zwrócenia wielu wartości.
źródło
Przekazując parametry przez odniesienie do funkcji.
Przykłady:
void incInt(int *y) { (*y)++; // Increase the value of 'x', in main, by one. }
Również przy użyciu zmiennych globalnych, ale nie jest to zalecane.
Przykład:
int a=0; void main(void) { //Anything you want to code. }
źródło
void main(void)
OH JAK SIĘ SPALA!main
ma zwrócić kod statusu. Pod * nix częściej deklaruje się to jakoint main(int argc, char *argv[])
, uważam, że Windows ma podobne konwencje.Jedną z metod jest użycie makr. Umieść to w pliku nagłówkowym
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__)
Umożliwia to zwrócenie do czterech zmiennych z funkcji i przypisanie ich do maksymalnie czterech zmiennych. Jako przykład możesz ich użyć w następujący sposób:
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; }
Oto, co drukuje:
(55, 3.9, 24.15)
Rozwiązanie może nie być tak przenośne, ponieważ wymaga C99 lub nowszej wersji dla makr wariadycznych i deklaracji zmiennych dla instrukcji. Ale myślę, że opublikowanie tutaj było wystarczająco interesujące. Inną kwestią jest to, że kompilator nie ostrzeże Cię, jeśli przypiszesz im niewłaściwe wartości, więc musisz być ostrożny.
Dodatkowe przykłady i wersja kodu oparta na stosie przy użyciu unii są dostępne w moim repozytorium github .
źródło
__typeof__