Come restituisco più valori da una funzione in C?


89

Se ho una funzione che produce un risultato inte 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.


7
Con stringvuoi dire "Sto usando C ++ e questa è la std::stringclasse" o "Sto usando C e questo è un char *puntatore o un char[]array".
Chris Lutz

beh, nel mio caso particolare, erano due int: uno per il "punteggio" di ciò che stavo confrontando e uno per l '"indice" di dove è stato trovato il punteggio massimo. Volevo usare un esempio di stringa qui solo per il caso più generale
Tony Stark

Passa la stringa per riferimento e restituisci l'int. Il modo più veloce. Nessuna struttura richiesta.
Stefan Steiger

1
Una funzione che restituisce 2 risultati non fa più di una cosa? Cosa direbbe lo zio Bob?
Duncan

Risposte:


124

Non so quale sia la tua string, ma presumo che gestisca la propria memoria.

Hai due soluzioni:

1: restituisci a structche contiene tutti i tipi di cui hai bisogno.

2: usa i puntatori per passare i valori.

Quale scegli di utilizzare dipende in gran parte dalle preferenze personali in merito alla semantica che ti piace di più.


7
Penso che dipenda più da quanto siano correlati i valori di ritorno. Se int è un codice di errore e la stringa è un risultato, questi non dovrebbero essere messi insieme in una struttura. È solo sciocco. In tal caso, restituirei int e passerei la stringa come a char *e a size_tper la lunghezza a meno che non sia assolutamente vitale per la funzione allocare la propria stringa e / o il ritorno NULL.
Chris Lutz

@ Chris Sono completamente d'accordo con te, ma non ho idea della semantica di utilizzo delle variabili di cui ha bisogno.
Travis Gockel

Buon punto Chris. Un'altra cosa che penso valga la pena sottolineare è il valore rispetto al riferimento. Se non sbaglio restituire la struttura come mostrato nell'esempio significa che verrà eseguita una copia al momento della restituzione, è corretto? (Sono un po 'traballante su C) Mentre l'altro metodo utilizza il pass-by-reference e quindi non richiede l'allocazione di più memoria. Naturalmente, la struttura potrebbe essere restituita tramite puntatore e condividere lo stesso vantaggio, giusto? (assicurandosi di allocare la memoria correttamente e tutto il resto ovviamente)
RTHarston

@BobVicktor: C non ha affatto semantica di riferimento (che è esclusiva di C ++), quindi tutto è un valore. La soluzione dei due puntatori (# 2) sta passando copie dei puntatori in una funzione, che getPairquindi 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 strncpyo altro).
Travis Gockel

@TravisGockel Grazie per la correzione. Mi riferivo al fatto che vengono utilizzati i puntatori, quindi non sta copiando i valori, ma condividendo solo ciò che è stato già allocato. Ma hai ragione nel dire che non è propriamente chiamato pass-by-reference in C. E grazie anche per le altre grandi pepite di conoscenza. Adoro imparare queste piccole cose sulle lingue. :)
RTHarston

10

Option 1: Dichiara una struttura con un int e una stringa e restituisce una variabile struttura.

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:

o

Option 3: Simile all'opzione 2. Puoi passare entrambi tramite il puntatore e non restituire nulla dalla funzione:


Per quanto riguarda l'opzione 2, dovresti anche passare la lunghezza della stringa. int fun(char *param, size_t len)
Chris Lutz

Ora dipende da cosa sta facendo la funzione. Se sappiamo che tipo di risultato la funzione inserisce nell'array char, potremmo semplicemente allocare abbastanza spazio per esso e passarlo alla funzione. Non c'è bisogno di passare la lunghezza. Qualcosa di simile a come usiamo strcpyper esempio.
codaddict

7

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:

e chiamalo così:

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.


6

Due approcci diversi:

  1. Passa i valori di ritorno tramite puntatore e modificali all'interno della funzione. Dichiari la tua funzione come void, ma ritorna tramite i valori passati come puntatori.
  2. Definisci una struttura che aggreghi i valori restituiti.

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.


1
C non ha riferimenti ;-), anche se dal momento che il poster è stato utilizzato string, potrebbe essere lecito ritenere C ++ ...
Travis Gockel

Me ne sono completamente dimenticato! Ho modificato la mia risposta per utilizzare i puntatori, ma sono stato chiaramente nella terra C ++ per troppo tempo. :)
James Thompson

6

Crea uno struct e imposta due valori all'interno e restituisci la variabile struct.

Devi allocare spazio per il char *nel tuo programma.


3

Usa i puntatori come parametri della funzione. Quindi usali per restituire più valori.


2

Passando i parametri per riferimento alla funzione.

Esempi:

Anche utilizzando variabili globali ma non è raccomandato.

Esempio:


4
void main(void)OH COME BRUCIA!
Chris Lutz

cosa intendi? @ Chris Lutz
Badr

6
maindovrebbe restituire un codice di stato. Sotto * nix, è più comune dichiararlo come int main(int argc, char *argv[]), credo che Windows abbia convenzioni simili.
Duncan

2

Un approccio consiste nell'utilizzare le macro. Inseriscilo in un file di intestazionemultitype.h

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:

Questo è ciò che stampa:

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 .


1
Un problema di portabilità più grande è la funzionalità non standard__typeof__
MM

Invece di typeof, potresti probabilmente usare sizeof. Ottieni la dimensione dei valori restituiti e alloca un array abbastanza grande da memorizzarli tutti. Quindi puoi restituirlo.
Klas. S
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.