Se ho una funzione che produce un risultato int
e un risultato string
, come faccio a restituirli entrambi da una funzione?
Per quanto ne so posso restituire solo una cosa, determinata dal tipo che precede il nome della funzione.
Se ho una funzione che produce un risultato int
e un risultato string
, come faccio a restituirli entrambi da una funzione?
Per quanto ne so posso restituire solo una cosa, determinata dal tipo che precede il nome della funzione.
Risposte:
Non so quale sia la tua string
, ma presumo che gestisca la propria memoria.
Hai due soluzioni:
1: restituisci a struct
che contiene tutti i tipi di cui hai bisogno.
struct Tuple {
int a;
string b;
};
struct Tuple getPair() {
Tuple r = { 1, getString() };
return r;
}
void foo() {
struct Tuple t = getPair();
}
2: usa i puntatori per passare i valori.
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);
}
Quale scegli di utilizzare dipende in gran parte dalle preferenze personali in merito alla semantica che ti piace di più.
char *
e a size_t
per la lunghezza a meno che non sia assolutamente vitale per la funzione allocare la propria stringa e / o il ritorno NULL
.
getPair
quindi dereferenzia . A seconda di ciò che stai facendo (OP non ha mai chiarito se questa è effettivamente una domanda C), l'allocazione potrebbe essere un problema, ma di solito non è in C ++ land (l'ottimizzazione del valore di ritorno salva tutto questo) e in C land, i dati le copie di solito avvengono esplicitamente (tramite strncpy
o altro).
Option 1
: Dichiara una struttura con un int e una stringa e restituisce una variabile struttura.
struct foo {
int bar1;
char bar2[MAX];
};
struct foo fun() {
struct foo fooObj;
...
return fooObj;
}
Option 2
: Puoi passare uno dei due tramite il puntatore e apportare modifiche al parametro attuale tramite il puntatore e restituire l'altro come al solito:
int fun(char **param) {
int bar;
...
strcpy(*param,"....");
return bar;
}
o
char* fun(int *param) {
char *str = /* malloc suitably.*/
...
strcpy(str,"....");
*param = /* some value */
return str;
}
Option 3
: Simile all'opzione 2. Puoi passare entrambi tramite il puntatore e non restituire nulla dalla funzione:
void fun(char **param1,int *param2) {
strcpy(*param1,"....");
*param2 = /* some calculated value */
}
int fun(char *param, size_t len)
strcpy
per esempio.
Poiché uno dei tuoi tipi di risultato è una stringa (e stai usando C, non C ++), ti consiglio di passare i puntatori come parametri di output. Uso:
void foo(int *a, char *s, int size);
e chiamalo così:
int a;
char *s = (char *)malloc(100); /* I never know how much to allocate :) */
foo(&a, s, 100);
In generale, preferisci fare l'allocazione nella funzione chiamante , non all'interno della funzione stessa, in modo da poter essere il più aperto possibile per diverse strategie di allocazione.
Due approcci diversi:
Penso che il numero 1 sia un po 'più ovvio su cosa sta succedendo, anche se può diventare noioso se hai troppi valori di ritorno. In tal caso, l'opzione n. 2 funziona abbastanza bene, sebbene ci sia un certo sovraccarico mentale coinvolto nella creazione di strutture specializzate per questo scopo.
string
, potrebbe essere lecito ritenere C ++ ...
Passando i parametri per riferimento alla funzione.
Esempi:
void incInt(int *y)
{
(*y)++; // Increase the value of 'x', in main, by one.
}
Anche utilizzando variabili globali ma non è raccomandato.
Esempio:
int a=0;
void main(void)
{
//Anything you want to code.
}
void main(void)
OH COME BRUCIA!
main
dovrebbe restituire un codice di stato. Sotto * nix, è più comune dichiararlo come int main(int argc, char *argv[])
, credo che Windows abbia convenzioni simili.
Un approccio consiste nell'utilizzare le macro. Inseriscilo in un file di intestazionemultitype.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__)
Ciò rende possibile restituire fino a quattro variabili da una funzione e assegnarle a un massimo di quattro variabili. Ad esempio, puoi usarli in questo modo:
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;
}
Questo è ciò che stampa:
(55, 3.9, 24.15)
La soluzione potrebbe non essere così portabile perché richiede C99 o versioni successive per macro variadiche e dichiarazioni di variabili for-statement. Ma penso che sia stato abbastanza interessante postare qui. Un altro problema è che il compilatore non ti avviserà se assegni loro valori sbagliati, quindi devi stare attento.
Ulteriori esempi e una versione basata su stack del codice che utilizza le unioni sono disponibili nel mio repository GitHub .
__typeof__
string
vuoi dire "Sto usando C ++ e questa è lastd::string
classe" o "Sto usando C e questo è unchar *
puntatore o unchar[]
array".