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.