Was passiert, wenn ‘&’ nicht in eine ‘scanf’-Anweisung eingefügt wird?

Lesezeit: 7 Minuten

Benutzer-Avatar
Kiste Kiste Kiste Kiste

Ich war zu einem Vorstellungsgespräch gegangen, in dem mir die Frage gestellt wurde:

Was haltet ihr von folgendem?

int i;
scanf ("%d", i);
printf ("i: %d\n", i);

Ich habe geantwortet:

  • Das Programm wird erfolgreich kompiliert.
  • Es wird die Nummer falsch drucken, aber es wird bis zum Ende laufen, ohne abzustürzen

Meine Antwort war falsch. Ich war überwältigt.

Danach haben sie mich entlassen:

Das Programm stürzte in einigen Fällen ab und führte zu einem Core-Dump.

Ich konnte es nicht verstehen warum würde das Programm abstürzen? Kann mir jemand den Grund erklären? Jede Hilfe geschätzt.

  • Jeder anständige Compiler wird sich darüber beschweren, wie scanf erwartet einen Zeiger

    – Cole Tobin

    2. Januar 2016 um 5:49 Uhr

  • Bitte machen Sie diese Tag-Änderungen nicht rückgängig. Dieses Tag wurde aus einem bestimmten Grund entfernt.

    – Brad Larson

    5. März 2016 um 17:41 Uhr

  • @BradLarson, in Ordnung, ich werde es nicht tun. Zuerst dachte ich, dass das that-Tag für diese Frage geeignet wäre. Können Sie mir sagen, warum das Tag entfernt wurde?

    – Kiste Kiste Kiste Kiste

    6. März 2016 um 2:49 Uhr

  • Dieser Link wurde in einem der Bearbeitungsgründe angegeben: meta.stackoverflow.com/questions/256592/…

    – Brad Larson

    6. März 2016 um 16:36 Uhr

Benutzer-Avatar
hackt

Wenn eine Variable definiert wird, weist der Compiler Speicher für diese Variable zu.

int i;  // The compiler will allocate sizeof(int) bytes for i

i oben definiert ist nicht initialisiert und hat einen unbestimmten Wert.

Zum Schreiben von Daten an die zugeordnete Speicherstelle i, müssen Sie die Adresse der Variablen angeben. Die Aussage

scanf("%d", &i);

werde eine schreiben int Daten durch den Benutzer an den zugewiesenen Speicherplatz i.

Wenn & wird nicht vorangestellt idann scanf versucht, die Eingabedaten in den Speicherplatz zu schreiben i Anstatt von &i. Seit i unbestimmten Wert enthält, gibt es einige Möglichkeiten, dass es einen Wert enthält, der dem Wert einer Speicheradresse entspricht, oder dass es einen Wert enthält, der außerhalb des Bereichs der Speicheradresse liegt.

In beiden Fällen kann sich das Programm unregelmäßig verhalten und zu undefiniertem Verhalten führen. Da kann alles passieren.

  • Es ist fast garantiert, dass Sie abstürzen, da Sie auf dem System, auf dem es ausgeführt wird, einen Speicherschutzfehler oder etwas Ähnliches erhalten. Natürlich andere Dinge könnte passieren, abhängig von der Größe des Programms, dem zugewiesenen Speicher usw., aber mein Geld liegt bei einem System-/Anwendungsabsturz.

    – sfdcfox

    1. Januar 2016 um 23:54 Uhr


  • @sfdcfox mein Geld liegt darin, dass der Compiler undefiniertes Verhalten bemerkt und den jeweiligen Codeblock als nicht erreichbar behandelt (= ihn aus dem Code entfernt und jeden Codepfad umleitet, der zu ihm führt).

    – John Dvorak

    2. Januar 2016 um 8:17 Uhr

  • @JanDvorak Ich habe diese Idee gesehen, dass der Compiler das zuvor erwähnte UB effektiv “löschen” kann, aber kennen Sie ein Beispiel, in dem wir es in Aktion sehen können? Es klingt schwer zu glauben – weshalb ich mir ziemlich sicher bin, dass es wahr sein wird, da dies schließlich C++ ist. 😉 Genau hier meinst Du, dass das schlecht beraten ist scanf möglicherweise nicht erreicht werden, sodass der Benutzer nicht zur Eingabe aufgefordert werden konnte? Ich wusste nicht, dass „als ob“ beobachtbare Nebenwirkungen hervorrufen kann, aber ich denke, dass diese Regel nicht für UB gilt, wie für alle anderen.

    – Unterstrich_d

    2. Januar 2016 um 12:37 Uhr


  • @JanDvorak: Wenn Compiler “deaktivieren” würden alle UB-Code auf diese Weise, würde eine große Anzahl recht gängiger Anwendungen plötzlich nicht mehr funktionieren …

    – DevSolar

    18. Januar 2016 um 13:10 Uhr

  • @sfdcfox: Du darfst nicht davon ausgehen, dass ein Speicherschutz vorhanden ist. Außerhalb der Desktop-Nische gibt es einige Systeme, die ohne laufen – wobei UB „undefiniertes Verhalten dieser Anwendung“ bedeutet und alle anderen derzeit im Speicher befindlichen, einschließlich des Betriebssystems“. Das sind die gleichen Systeme, die auf Speicher nicht eher schlecht reagieren free()d vor der Rückkehr von main()

    – DevSolar

    18. Januar 2016 um 13:12 Uhr


Benutzer-Avatar
Iharob Al-Asimi

Weil es undefiniertes Verhalten hervorruft. Das scanf() Funktionsfamilie erwartet einen Zeiger auf eine ganze Zahl, wenn die "%d" Bezeichner gefunden. Sie übergeben eine Ganzzahl, die als Adresse einer Ganzzahl interpretiert werden kann, dies aber nicht ist. Dies hat kein definiertes Verhalten im Standard. Es wird tatsächlich kompilieren (wird jedoch eine Warnung ausgeben), aber es wird sicherlich auf unerwartete Weise funktionieren.

In dem Code, wie er ist, gibt es noch ein weiteres Problem. Das i Die Variable wird nie initialisiert, sodass sie einen unbestimmten Wert hat, ein weiterer Grund dafür Undefiniertes Verhalten.

Beachten Sie, dass der Standard nichts darüber aussagt, was passiert, wenn Sie einen bestimmten Typ übergeben, wenn ein anderer Typ erwartet wurde, es ist einfach ein undefiniertes Verhalten, egal welche Typen Sie austauschen. Aber diese besondere Situation fällt unter eine besondere Betrachtung, da Zeiger in ganze Zahlen konvertiert werden können, obwohl das Verhalten nur definiert ist, wenn Sie zurück in einen Zeiger konvertieren und wenn der ganzzahlige Typ in der Lage ist, den Wert korrekt zu speichern. Aus diesem Grund wird es kompiliert, aber es funktioniert sicherlich nicht richtig.

  • Aber in meiner Studienzeit, als ich noch studiert habe Geist von Cgab es eine Aussage wie diese: scanf ("%s", name);

    – Kiste Kiste Kiste Kiste

    1. Januar 2016 um 14:57 Uhr

  • ^ das funktioniert, weil name ist wahrscheinlich ein char-Array, und der Name eines Arrays ist gleich der Adresse des ersten Elements in diesem Array.

    – kfx

    1. Januar 2016 um 14:58 Uhr

  • Das ist sehr unterschiedlich. Sicherlich name war ein Array und Arrays werden automatisch in Zeiger auf ihr erstes Element umgewandelt. Außerdem wäre es sicherer char name[100]; scanf("%99s", name);.

    – Iharob Al Asimi

    1. Januar 2016 um 14:58 Uhr


  • Also, im Grunde meinst du das scanf versucht, den Wert an der Stelle mit der Variablen i zu speichern.

    – Kiste Kiste Kiste Kiste

    1. Januar 2016 um 15:02 Uhr

  • Obwohl Ihr Kommentar nicht klar ist, denke ich, dass Sie es verstanden haben. Ja, so funktioniert es.

    – Iharob Al Asimi

    1. Januar 2016 um 15:03 Uhr

Benutzer-Avatar
MikeCAT

Sie haben Daten vom falschen Typ übergeben (int* wird erwartet, aber int übergeben wird) an scanf(). Dies führt zu undefiniertes Verhalten.

Bei undefiniertem Verhalten kann alles passieren. Das Programm kann abstürzen und darf nicht abstürzen.

In einer typischen Umgebung wird das Programm vermutlich abstürzen, wenn eine “Adresse”, die auf einen Ort verweist, an den das Betriebssystem nicht schreiben darf, übergeben wird scanf()und das Schreiben dorthin veranlasst das Betriebssystem, das Anwendungsprogramm zu beenden, und es wird als Absturz beobachtet.

Eine Sache, die die anderen Antworten noch nicht erwähnt haben, ist, dass auf einigen Plattformen sizeof (int) != sizeof (int*). Wenn die Argumente auf eine bestimmte Weise übergeben werden*, scanf könnte einen Teil einer anderen Variablen oder der Rücksendeadresse verschlingen. Das Ändern der Absenderadresse kann sehr wohl zu einer Sicherheitslücke führen.

* Ich bin kein Experte für Assemblersprache, also nehmen Sie dies mit einem Körnchen Salz.

Ich konnte nicht verstehen, warum das Programm abstürzen würde? Kann mir jemand den Grund erklären. Jede Hilfe geschätzt.

Vielleicht etwas angewandter:

int i = 123;
scanf ("%d", &i);

Mit dem ersten Befehl weisen Sie Speicher für einen ganzzahligen Wert zu und schreiben 123 in diesen Speicherblock. Nehmen wir für dieses Beispiel an, dass dieser Speicherblock die Adresse hat 0x0000ffff. Mit dem zweiten Befehl lesen Sie Ihre Eingabe und scanf schreibt die Eingabe in den Speicherblock 0x0000ffff – weil Sie nicht auf den Wert dieser Variablen zugreifen (dereferenzieren). i aber es ist Adresse.

Wenn Sie den Befehl verwenden scanf ("%d", i); Stattdessen schreiben Sie die Eingabe in den Speicher die Anschrift 123 (weil das der Wert ist, der in dieser Variablen gespeichert ist). Natürlich kann das schrecklich schief gehen und einen Absturz verursachen.

  • Danke. +1 für die gute Erklärung. (Auch schöner Name übernommen von Der Marsianer.

    – Kiste Kiste Kiste Kiste

    4. Januar 2016 um 14:56 Uhr

Da in scanf (wie vom Standard gefordert) kein &(kaufmännisches Und) steht, wird das Programm, sobald wir den Wert eingeben, abrupt beendet, egal wie viele Codezeilen weiter im Programm geschrieben werden.

–>> Ich habe das in Codeblöcken ausgeführt und gefunden.

Dasselbe Programm, wenn wir im Turbo-C-Compiler laufen, dann werden alle Zeilen perfekt ausgeführt, auch die nach scanf, aber das einzige, was, wie wir wissen, der Wert von i gedruckt wäre, wäre Müll.

Fazit:- Da es bei einigen Compilern läuft und bei anderen nicht, ist dies kein gültiges Programm.

  • Danke. +1 für die gute Erklärung. (Auch schöner Name übernommen von Der Marsianer.

    – Kiste Kiste Kiste Kiste

    4. Januar 2016 um 14:56 Uhr

1386250cookie-checkWas passiert, wenn ‘&’ nicht in eine ‘scanf’-Anweisung eingefügt wird?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy