wake-up-neo.com

Wie gebe ich mehrere Werte von einer Funktion in C zurück?

Wenn ich eine Funktion habe, die ein Ergebnis int und ein Ergebnis string erzeugt, wie gebe ich beide von einer Funktion zurück?

Soweit ich das beurteilen kann, kann ich nur eines zurückgeben, was durch den Typ vor dem Funktionsnamen bestimmt wird.

78
Tony Stark

Ich weiß nicht, was Ihr string ist, aber ich gehe davon aus, dass es sein eigenes Gedächtnis verwaltet.

Sie haben zwei Lösungen:

1: Gib ein struct zurück, das alle benötigten Typen enthält.

struct Tuple {
    int a;
    string b;
};

struct Tuple getPair() {
    Tuple r = { 1, getString() };
    return r;
}

void foo() {
    struct Tuple t = getPair();
}

2: Verwenden Sie Zeiger, um Werte zu verteilen.

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);
}

Welches Sie wählen, hängt weitgehend von Ihren persönlichen Vorlieben ab, welche Semantik Sie bevorzugen.

115
Travis Gockel

Option 1: Deklarieren Sie eine Struktur mit einem int und einem string und geben Sie eine Strukturvariable zurück.

struct foo {    
 int bar1;
 char bar2[MAX];
};

struct foo fun() {
 struct foo fooObj;
 ...
 return fooObj;
}

Option 2: Sie können einen der beiden über einen Zeiger übergeben und den aktuellen Parameter über den Zeiger ändern und den anderen wie gewohnt zurückgeben:

int fun(char **param) {
 int bar;
 ...
 strcpy(*param,"....");
 return bar;
}

oder

 char* fun(int *param) {
 char *str = /* malloc suitably.*/
 ...
 strcpy(str,"....");
 *param = /* some value */
 return str;
}

Option 3: Ähnlich wie bei Option 2. Sie können sowohl per Zeiger übergeben als auch nichts von der Funktion zurückgeben:

void fun(char **param1,int *param2) {
 strcpy(*param1,"....");
 *param2 = /* some calculated value */
}
10
codaddict

Zwei verschiedene Ansätze:

  1. Übergeben Sie Ihre Rückgabewerte per Zeiger und ändern Sie sie innerhalb der Funktion. Sie erklären Ihre Funktion als ungültig, sie wird jedoch über die als Zeiger übergebenen Werte zurückgegeben.
  2. Definieren Sie eine Struktur, die Ihre Rückgabewerte aggregiert.

Ich denke, dass # 1 etwas offensichtlicher ist, was los ist, obwohl es langweilig werden kann, wenn Sie zu viele Rückgabewerte haben. In diesem Fall funktioniert Option 2 recht gut, obwohl die Erstellung spezieller Strukturen für diesen Zweck mit einem gewissen Aufwand verbunden ist.

6
James Thompson

Da einer Ihrer Ergebnistypen ein String ist (und Sie C und nicht C++ verwenden), empfehle ich die Übergabe von Zeigern als Ausgabeparameter. Verwenden:

void foo(int *a, char *s, int size);

und nenne es so:

int a;
char *s = (char *)malloc(100); /* I never know how much to allocate :) */
foo(&a, s, 100);

Im Allgemeinen bevorzugen Sie die Zuweisung in der Funktion aufrufend, nicht in der Funktion selbst, damit Sie für verschiedene Zuweisungsstrategien so offen wie möglich sind.

6
Jesse Beder

Erstellen Sie eine Struktur, setzen Sie zwei Werte und geben Sie die Strukturvariable zurück.

struct result {
    int a;
    char *string;
}

Sie müssen Platz für das char * in Ihrem Programm.

6
zs2020

Verwenden Sie Zeiger als Funktionsparameter. Verwenden Sie sie dann, um mehrere Werte zurückzugeben.

3
Bloodlee

Durch Übergabe von Parametern anhand der Funktion.

Beispiele:

 void incInt(int *y)
 {
     (*y)++;  // Increase the value of 'x', in main, by one.
 }

Auch bei Verwendung globaler Variablen wird dies jedoch nicht empfohlen.

Beispiel:

int a=0;

void main(void)
{
    //Anything you want to code.
}
2
Badr

Ein Ansatz ist die Verwendung von Makros. Platziere dies in einer Header-Datei 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__)

Auf diese Weise können bis zu vier Variablen aus einer Funktion zurückgegeben und bis zu vier Variablen zugewiesen werden. Als Beispiel können Sie sie wie folgt verwenden:

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;
}

Dies ist, was es druckt:

(55, 3.9, 24.15)

Die Lösung ist möglicherweise nicht so portabel, da für variadische Makros und for-statement-Variablendeklarationen C99 oder höher erforderlich ist. Aber ich denke, es war interessant genug, um hier zu posten. Ein weiteres Problem ist, dass der Compiler Sie nicht warnt, wenn Sie ihnen die falschen Werte zuweisen. Sie müssen also vorsichtig sein.

Weitere Beispiele und eine stapelbasierte Version des Codes, der Gewerkschaften verwendet, finden Sie in meinem Github-Repository .

2
Klas. S