Gibt ohne den Befehl "return" zurück


8

C-Programmiersprache, kompiliert mit gcc, Terminal Bash in WSL

Ich habe eine rekursive Funktion geschrieben, um die niedrigste Zahl in einem Array zu finden, was gut funktioniert.

/*01*/    int minimo(int array[], int n)
/*02*/    {
/*03*/      static int min = 0;
/*04*/    
/*05*/      if (n == N)
/*06*/      {
/*07*/          return array[n-1];
/*08*/      }
/*09*/      else
/*10*/      {
/*11*/          min = minimo(array, n+1);
/*12*/          if(array[n]<min){
/*13*/              min = array[n];
/*14*/          }
/*15*/      }
/*16*/    }

Das einzige Problem ist, dass es nicht funktionieren sollte, weil es nicht "min" an den Anrufer zurückgibt ...

int main()
{
    //Var
    int array[N] = {10, 2, 5, 1, 7};
    printf("Min: %d\n", minimo(array, 0));
}

Mein Anliegen ist eigentlich ein Problem, aber nicht auf meinem Computer, auf dem die Funktion einwandfrei funktioniert. Es ist ein Problem auf den Laptops und IDEs meiner Freunde. Ich habe versucht, auf dem Macbook eines Freundes auf XCode zu kopieren, und es würde nicht funktionieren, wenn die Zeile "return min". wurde am Ende der Funktion nicht hinzugefügt.

Zwischen Zeile 15-16 muss ich hinzufügen return min;

/*15*/      }
            return min;
/*16*/    }

Meine Fragen an Sie lauten wie folgt:

  1. Wie kann eine Funktion eine Variable automatisch zurückgeben ?
  2. Ist es möglich, dass es die einzige Variable zurückgibt , die ich erstellt habe (static int min)?
  3. Oder ist es ein "Problem" im Zusammenhang mit dem statischen Attribut der Variablen?
  4. Hat es etwas mit der Art der Funktion zu tun ( rekursiv )?

Dies ist mein erster Beitrag. Bitte seien Sie freundlich, wenn ich gegen eine Forenregel verstoße.


Lesen Sie die SO-Frage durch: stackoverflow.com/q/204476/8339821 und die Antworten. Dies bringt Sie zu dem Punkt, an dem Ihre mainFunktion zurückkehrt.
yvw

Auf den ersten Blick scheint es eine WSL-spezifische Sache zu sein, nicht eine gcc-spezifische. Es scheint, dass die WSL automatisch für Sie "denkt" und den Code selbst korrigiert.
RobertS unterstützt Monica Cellio

@ ЯрославМашко Dies ist eine ganz andere Sache und hat nichts mit dieser Frage zu tun. Das Problem ist nicht der Rückgabewert, mainsondern der "automatische" Rückgabewert einer Funktion in einer bestimmten Implementierung.
RobertS unterstützt Monica Cellio

@ RobertSsupportsMonicaCellio Ja, du hast recht. Ich habe die Frage noch einmal durchgelesen und festgestellt, dass der SO wissen möchte, was seine Funktion wirklich zurückbringt. Ich dachte, dass er irgendwie die Rückkehr von main verpasst. Diese Antwort enthält dann vollständige Informationen zum Thema: stackoverflow.com/a/1610454/8339821 . Der Hauptpunkt besteht darin, dass ein bestimmter CStandard in Abwesenheit einer Rückgabeanweisung Null zurückgibt.
yvw

Sie sollten Ihre Datei mit einem -WallSchalter kompilieren und sehen, was der Compiler Ihnen sagt.
yvw

Antworten:


5

Mein Anliegen ist eigentlich ein Problem, aber nicht auf meinem Computer, auf dem die Funktion einwandfrei funktioniert. Es ist ein Problem auf den Laptops und IDEs meiner Freunde. Ich habe versucht, auf dem Macbook eines Freundes auf XCode zu kopieren, und es würde nicht funktionieren, wenn die Zeile "return min". wurde am Ende der Funktion nicht hinzugefügt.

Typisches Beispiel für undefiniertes Verhalten . Funktioniert auf einer Maschine, aber nicht auf einer anderen. Funktioniert tagsüber, aber nicht nachts. Funktioniert mit einem Compiler, aber nicht mit einem anderen. Wenn Sie undefiniertes Verhalten aufrufen, stellt der C-Standard keine Anforderungen an das Verhalten des Codes.

C11-Standard 6.9.1.12

Wenn das}, das eine Funktion beendet, erreicht ist und der Wert des Funktionsaufrufs vom Aufrufer verwendet wird, ist das Verhalten undefiniert.

In Ihrem Code passiert genau das. Sie rufen undefiniertes Verhalten auf, wenn Sie versuchen, den Rückgabewert zu drucken.

Im Gegensatz zu dem, was viele glauben, ist es völlig erlaubt, die return-Anweisung in einer nicht ungültigen Funktion wegzulassen. Es wird nur nicht definiertes Verhalten , wenn Sie versuchen , zu verwenden , das nicht vorhandenen Rückgabewert.

Um dies zu vermeiden, kompilieren Sie immer mindestens mit -Wall -Wextra.


Und vergiss nicht -Werror!
Jonathon Reinhart

@ JonathonReinhart Nun, das ist die Art von Diskussion, die Bier erfordert. :)
klutt

1
@ JonathonReinhart Das Wichtigste ist, sich tatsächlich um die Warnungen zu kümmern. Wenn es dem Codierer egal ist und -WerrorSO verwendet, wird eine Frage mit "Warum wird dies nicht kompiliert?" und ohne es "Warum verhält sich das seltsam?" Ich stimme zwar zu, dass dieser Parameter eine gute Sache ist, aber er verfehlt das Ziel.
Klutt

1
Mein Gefühl ist, -Werrordass unnötige SO-Fragen wie diese vermieden werden, da der Benutzer gezwungen ist , sich um die Warnungen zu kümmern, wenn er keine kaputte ausführbare Datei zum Ausführen hat :-)
Jonathon Reinhart

2
Vielleicht sollte GCC standardmäßig einfach Fehlermeldungen im HTML-Format mit dem Thema Stapelüberlauf und eingebetteten Suchergebnissen anzeigen
Jonathon Reinhart

2

Wie kann eine Funktion eine Variable automatisch zurückgeben?

Es folgt dem Protokoll. Es ist bekannt, dass die Rückgabe der Funktion den zurückgegebenen Wert an einer Stelle finden sollte, und eine explizite returnFunktion dieser Funktion wird diese Stelle füllen. Wenn Sie nicht anrufen return, bleibt an der angegebenen Stelle ein zufälliger Wert erhalten.

Ist es möglich, dass es die einzige Variable zurückgibt, die ich erstellt habe (static int min)?

Nein, es ist undefiniert, was es zurückgibt. Es kann was auch immer sein.

Oder ist es ein "Problem" im Zusammenhang mit dem statischen Attribut der Variablen?

Auch hier ist das, was es zurückgibt, undefiniert.

Hat es etwas mit der Art der Funktion zu tun (rekursiv)?

Ja und nein. Wenn die Funktion als extern definiert ist, folgt der zurückgegebene Wert einem anderen Protokoll wie bei statischen Funktionen.

Es kann alles im endgültigen Code passieren, die C-Sprache legt nicht die Art der Implementierung einer Funktion fest, sei es rekursiv oder nicht. Wenn die Funktion beispielsweise rekursiv ist und vorberechnet werden kann, kann nur der Endwert am Aufrufort ersetzt werden. Dies ist auch dann richtig, wenn das Endergebnis des Programms das erwartete Ergebnis ist, das der operativen Semantik entspricht, die C in definiert ISO9899.

Ich zitiere aus dem offiziellen Dokument:

4 In der abstrakten Maschine werden alle Ausdrücke gemäß der Semantik ausgewertet. Eine tatsächliche Implementierung muss keinen Teil eines Ausdrucks auswerten, wenn daraus geschlossen werden kann, dass sein Wert nicht verwendet wird und keine erforderlichen Nebenwirkungen auftreten (einschließlich solcher, die durch den Aufruf einer Funktion oder den Zugriff auf ein flüchtiges Objekt verursacht werden).

Es kann auch einen Anruf durch den Wert dieses Anrufs ersetzen, und dies ist korrekt.

Bei all Ihren Fragen lautet die Antwort also undefiniertes Verhalten .


1

Wie kann eine Funktion eine Variable automatisch zurückgeben?

Ich bin zufällig, die minVariable befindet sich zufällig im richtigen Rückgaberegister für den ABI.

Ist es möglich, dass es die einzige Variable zurückgibt, die ich erstellt habe (static int min)?

Ich denke, es hängt eher damit zusammen, dass es kurz vor dem Beenden der Funktion verwendet wurde, aber ich vermute hier: Dies ist kein in der C-Sprache definiertes Verhalten, und es hat zufällig funktioniert.

Oder ist es ein "Problem" im Zusammenhang mit dem statischen Attribut der Variablen?

Hat es etwas mit der Art der Funktion zu tun (rekursiv)?

Da dies ein zufälliges Verhalten war, konnte es sein oder nicht. Der Unterschied zwischen zufällig und deterministisch besteht darin, dass Sie so viele Variablen haben, dass Sie die Erklärung aufgeben.


-3

Ich nehme an, Sie haben irgendwo N definiert (in Ihrem Fall wahrscheinlich N = 5).

Die meisten Compiler fügen automatisch die Anweisung "return 0" hinzu, wenn die Anweisung return fehlt.

* Weitere Informationen finden Sie in den Kommentaren. Eigentlich ist es ein undefiniertes Verhalten *

In Ihrer rekursiven Funktion ist es besser, die verbleibende Länge des Arrays zu übergeben und anzuhalten, wenn Sie n == 0 erreichen.

Vermeiden Sie es, globale Variablen zu betrachten oder interne Funktionen zu definieren.

int minimo(int array[], int n)
{
  ...
  if (n == 0)
  ...
            min = minimo(array, n-1);
  ...
}

(andere Modifikation erforderlich)

Eigentlich sollten Sie die Länge des Arrays nur für die Hauptfunktion kennen, nennen Sie es also wie folgt:

printf("Min: %d\n", minimo(array, N));

5
Nein! Mit Ausnahme main()in C99 (oder höher) Implementierungen (wo ein return 0;in Abwesenheit einer früheren return - Anweisung hinzugefügt) , Ausfall returnist UB .
14.

@pmg irgendwo auf der SO habe ich gelesen, dass der Wortlaut auf geht C89. Und das ist ein Minimum, das ich heute bekommen kann.
yvw

@ ЯрославМашко: In C89 wird der Standardrückgabewert nicht erwähnt. C99 (und ähnlich in C11 ): "... das Erreichen des}, das die Hauptfunktion beendet, gibt einen Wert von 0 zurück." (Schwerpunkt liegt bei mir)
pmg
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.