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:
- Wie kann eine Funktion eine Variable automatisch zurückgeben ?
- Ist es möglich, dass es die einzige Variable zurückgibt , die ich erstellt habe (static int min)?
- Oder ist es ein "Problem" im Zusammenhang mit dem statischen Attribut der Variablen?
- 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.
main
Funktion zurückkehrt.main
sondern der "automatische" Rückgabewert einer Funktion in einer bestimmten Implementierung.C
Standard in Abwesenheit einer Rückgabeanweisung Null zurückgibt.-Wall
Schalter kompilieren und sehen, was der Compiler Ihnen sagt.Antworten:
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
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
.quelle
-Werror
!-Werror
SO 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.-Werror
dass 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 :-)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
return
Funktion dieser Funktion wird diese Stelle füllen. Wenn Sie nicht anrufenreturn
, bleibt an der angegebenen Stelle ein zufälliger Wert erhalten.Nein, es ist undefiniert, was es zurückgibt. Es kann was auch immer sein.
Auch hier ist das, was es zurückgibt, undefiniert.
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:
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 .
quelle
Ich bin zufällig, die
min
Variable befindet sich zufällig im richtigen Rückgaberegister für den ABI.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.
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.
quelle
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.
(andere Modifikation erforderlich)
Eigentlich sollten Sie die Länge des Arrays nur für die Hauptfunktion kennen, nennen Sie es also wie folgt:
quelle
main()
in C99 (oder höher) Implementierungen (wo einreturn 0;
in Abwesenheit einer früheren return - Anweisung hinzugefügt) , Ausfallreturn
ist UB .C89
. Und das ist ein Minimum, das ich heute bekommen kann.