• Apfeltalk ändert einen Teil seiner Allgemeinen Geschäftsbedingungen (AGB), das Löschen von Useraccounts betreffend.
    Näheres könnt Ihr hier nachlesen: AGB-Änderung
  • Viele hassen ihn, manche schwören auf ihn, wir aber möchten unbedingt sehen, welche Bilder Ihr vor Eurem geistigen Auge bzw. vor der Linse Eures iPhone oder iPad sehen könnt, wenn Ihr dieses Wort hört oder lest. Macht mit und beteiligt Euch an unserem Frühjahrsputz ---> Klick

supernervige Endlosschleife in C - Verwirrung pur!

  • Ersteller moescream
  • Erstellt am

moescream

Gast
Hallo liebe Apfelsportsfreunde,

es ist mal wieder soweit und meine IT Abgabe steht vor der Tür. Diesmal klemmts an einer winzig kleinen Kleinigkeit, aber leider komm ich selbst nicht dahinter.

Ich will in einer Schleife solange einen Integer einlesen lassen, bis dessen Wert zwischen 1 und 9999 liegt. Wenn versehentlich ein anderes Zeichen, also ein Character, eingegeben wird, dann dürfte sich der Wert der Variablen n ja nicht geändert haben, d.h. der Wert ist entweder noch 0 oder, falls bereits eine ungültige Eingabe erfolgt ist, eben dieser ungültige vorangegangene Wert, was ja wieder die Schleife einleiten müsste. Alles funktioniert wunderbar, nur wenn ich tatsächlich einen Character eingebe, dann lande ich sofort in einer Endlosschleife. Bin ehrlich gestanden gerade ziemlich überfragt. Ich habe die Variable mit dem Wert 0 initialisiert und selbst wenn ich in der Schleife eine 0 eingebe (also tatsächlich die Bedingung der Schleife erfülle), dann läuft das Programm noch normal und die Schleife wird wieder ausgeführt. Sobald aber ein Character eingegeben wurde, liefert scanf zwar AUCH eine 0 zurück (oder eben die letzten ungültigen Wert) aber geht dann sofort in die Endlosschleife ohne die scan funktion ein weiteres mal auszuführen. Heißt das, das bei einem Typenkonflikt (Integer erwartet - character eingelesen) zwar der zuletzt aktuelle Wert der Variablen an den Benutzer zurückgegeben wird, aber das Programm intern mit einem anderen Wert arbeitet?

Ich würde mich über Hinweise sehr freuen, vor allem weil ich glaube, dass hier wahrscheinlich nur eine Winzigkeit verändert werden muss um das Programm lauffähig zu machen.

PS: Ich hab in anderen Beiträgen gelesen, dass man den -Wall Compiler benutzen soll, wenn man detailierte Fehlermeldungen erhalten will. Weiß jemand ob der unter XCode zur Verfügung steht? Hab in den man pages nichts gefunden...

Danke!!! Moritz


Hier noch ein code schnippsel:

#include <stdio.h>
int main ()

{

/*Variablendeklaration*/
int n=0;

/*Eingabe der Obergrenze*/

do
{
printf("\nBitte legen Sie eine Grenze fest, bis zu der alle Primzahlen ermittelt werden sollen.\n");
scanf(" %d", &n);
printf("Die Eingabe war: %d", n);
}
while ((n<=0)||(n>=10000));

return 0;
}
 

MacApple

Schöner von Bath
Registriert
05.01.04
Beiträge
3.652
PS: Ich hab in anderen Beiträgen gelesen, dass man den -Wall Compiler benutzen soll, wenn man detailierte Fehlermeldungen erhalten will. Weiß jemand ob der unter XCode zur Verfügung steht? Hab in den man pages nichts gefunden...
-Wall ist eine Option des gcc und auch der gcc auf Mac OS X versteht diese Option. Xcode ruft ja nur den gcc auf, wenn's ans Compilieren geht. In den Targeteinstellungen bei den Build Optionen kannst Du unter "Other Warning Flags" -Wall eintragen, dann ruft Xcode den gcc auch mit -Wall auf.

MacApple
 

RoyalKnight

Cox Orange
Registriert
08.12.05
Beiträge
99
Wall wird dir in diesem Fall recht wenig nützen ;). Das Problem tritt auf, weil deine Eingabe noch immer im Buffer von stdin steht und nicht geleert wird - du musst also eine Fehlerbehandlung einbauen um den Buffer zu leeren - mehr dazu siehe im Code:
Code:
#include <stdio.h>
int main ()

{

/*Variablendeklaration*/
int n=0;

/*Eingabe der Obergrenze*/

do
{
printf("\nBitte legen Sie eine Grenze fest, bis zu der alle Primzahlen ermittelt werden sollen.\n");
  [COLOR=Red]if(!scanf(" %d", &n))
  {
    // error handling: clean stdin-buffer:
    scanf("%*s");
  }[/COLOR]
printf("Die Eingabe war: %d", n);
}
while ((n<=0)||(n>=10000));

return 0;
}
Habs aber nicht getestet...
 

moescream

Gast
Danke für deine schnelle Antwort! Ich habs grade getestet und es funktioniert... Ich sags ganz ehrlich, ich versteh zwar im Grunde wovon du sprichst, aber ich hab deinen code einfach reinkopiert und bin glücklich das es funktioniert. Wie man den Buffer leert, darüber lernen wir an der Uni natürlich nix, da meckern sie nur wenn du nicht selber auf so schlaue Ideen kommst...o_O
Aber vielen vielen Dank
lg moritz
 

RoyalKnight

Cox Orange
Registriert
08.12.05
Beiträge
99
Das "Problem" ist ja, dass scanf nach dem festgelegten Format-String sucht, das ist in deinem Fall ein Integer (%d). Diesen findet er natürlich nicht, wenn du einen Character eintippst, das Zeug bleibt also im Buffer und das wars. Zum leeren des Buffers nimmt man einfach scanf("%*s") - das liest einen String (%s - also alles). Der * hat zu bedeuten, dass nix in den Buffer kommt. Fertig :D
 

moescream

Gast
Ok, hab ich bekeppt. Ich hab heute auch schon ein bischen damit rumgespielt - im Prinzip wird der stdin direkt an den stdout weitergegeben, wie unter Linux das Piping. Die fflush funktion läuft unter mac wohl nicht? Hab ich gestern auch noch probiert aber nicht ans Laufen gekriegt. Deine if-Schleife hat hier bei meinen IT Tutoren noch für unglaube gesorgt - haben die angeblich noch nie gesehen... Du negierst praktisch die scanf funktion, sprich wenn scanf nicht den definierten format typ abholt, dann geht er in die Schleife und holt einfach alles ab was da so im zwischenspeicher liegt, ohne es abzuspeichern (deswegen auch kein &n), oder?
lg mo
 

RoyalKnight

Cox Orange
Registriert
08.12.05
Beiträge
99
Die fflush funktion läuft unter mac wohl nicht?
Mit dem Mac bzw. Xcode habe ich ehrlich gesagt noch nie programmiert, sondern großteils nur unter Debian mit der GCC, welche übrigens auch Xcode verwendet, von daher (bis auf unterschiedliche Versionen) ident. Soweit ich weiß ist das Verhalten von fflush nicht definiert. D.h. je nach Compiler kannst du Glück, oder auch Pech haben, jedenfalls finde ich es nicht sinnvoll derartige Funktionen zu verwenden ;).
Deine if-Schleife hat hier bei meinen IT Tutoren noch für unglaube gesorgt - haben die angeblich noch nie gesehen...
Die Negation, oder das im if-Block enthaltene scanf? Wenn es ersteres ist, würde ich ihnen empfehlen C zu lernen (das ist Grundlage, das sollte man können bevor es an Kontrollstrukturen geht), oder für ein andere Fach Tutor zu werden. Btw. if ist keine Schleife ;).
Du negierst praktisch die scanf funktion, sprich wenn scanf nicht den definierten format typ abholt, dann geht er in die Schleife und holt einfach alles ab was da so im zwischenspeicher liegt, ohne es abzuspeichern (deswegen auch kein &n), oder?
scanf liefert dir die Anzahl der erfolgreich (dem Format entsprechenden) eingelesenen Argumente. Wenn keines korrekt ist, bekommst du eine 0 zurück. Eine 0 verneint (negiert) liefert eine 1 und somit wird der Code im if-Block ausgeführt. Du könntest den Return-Wert selbstverständlich auch einer Variable zuweisen und diese ausgeben, damit du weißt, wie scanf arbeitet.

Was scanf wirklich macht, liest du am besten unter [1] (übrigens eine tolle Seite, würd ich mir merken ;)) nach. Ich erklärs dir aber trotzdem kurz: Also du gibst einen Character ein und schließt mit der Eingabetaste ab, also überprüft scanf, ob es dem festgelegten Format entspricht. Das ist nicht der Fall, es liefert 0 zurück. Wenn du nun diesen Return-Wert nicht überprüfst, wird der Code der while-Schleife wieder ausgeführt. scanf hat noch immer die vorige Eingabe im Buffer, da nicht verworfen, also gehts beim Überprüfen weiter und das für alle Ewigkeit.

[1] http://www.cplusplus.com/reference/clibrary/cstdio/scanf.html
 

moescream

Gast
Die Negation von scanf haben Sie nicht sofort gerafft. Aber ansonsten möchte ich echt nichts gegen unsere Tutoren sagen, die können einem normalerweise schon weiterhelfen, aber sie sind halt nicht immer greifbar und die meisten arbeiten auch nicht mit Mac, wesshalb sie dann immer gleich skeptisch sind wenn du mit der Frage ankommst.
Vielen Dank für den Hinweis mit der c++ Seite, ich werd mich da mal einlesen. Im Prinzip haben wir ja vom Lehrstuhl aus ein Skript, in dem alles erklärt wird und im Normalfall reicht das auch aus um die Übungen zu bestehen. Nur wenn man wirklich hinter die Strukturen kommen will, muss man halt etwas tiefer gehen, das ist ja überall so.
Dem return wert der scanf funktion eine Variable zuweisen hab ich auch grad mal probiert, dabei hat sich lustigerweise rausgestellt, dass Zahlen ja wie Character behandelt werden! Hab mir daraufhin mal die ASCII Tabelle angeschaut und gesehen, dass den Zahlen doch tatsächlich ein Wert zugewiesen wird - wie kompliziert muss man eigentlich denken? Hätte doch gereicht, wenn die Null den Wert 0 hat, die Eins den Wert 1 und so weiter...o_O
Vielen Dank nochmal für deinen Hilfe, ich hab echt was gelernt!!:) Lg mo