PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : newbie - schleifen



flasheye
16-04-2001, 14:11
Moin moin,

ich brauche eine Endlosschleife. Es soll beispielsweise eine gefragt werden, ob ein weiterer Durchgang gemacht werden soll. Codiert habe ich das in etwa so:

main()
{
char ende;

do {

printf("Ende (j/n)");
scanf("%c", &ende);

printf("\n\n");

} while (ende != 'j');

}

Alles wunderschön, wenn ich ein j eingebe bricht das Programm ab, genau wie es soll. Wenn ich jedoch ein anderes Zeichen eingebe, durchläuft der Rechner die Schleife einmal sinnlos. Er führt dann den Befehl printf() aus, spingt aber über das scanf() drüber, um danach die Schleife wieder korrekt auszuführen. :eek:
Also, im Falle von "Nicht-j" geht ein sinnloser Durchlauf ab. Wovon kommt das?

Danke in Voraus.
DasSein

Sion
16-04-2001, 17:15
Da wird vermutlich das Zeichen im Eingabe-Stream nicht durch scanf gelöscht, beim nächsten Durchlauf wird es also nochmals gesehen.
Vielleicht hilft ein
fflush(stdin);
weiter? (ist in stdio.h)
Ein "getchar();" könnte auch helfen, bin mir nicht so ganz sicher - probiers einfach mal aus!

Viel Glück :-)

stiviman
16-04-2001, 20:51
vollkommen richtiger ansatz, nur gibts ein problem:
da gibts nen bug beim ansi-c-compiler von gnu, nächmlich: fflush(stdin) funktioniert nicht;-) bei allen streams funktionierts, nur bei stdin nicht.

da muss man sich so helfen:

printf("Weiter [j/n]?\n\n");
do
{
scanf("%c",&c);
}while(c=='\n');

weil: das letzte (oder die letzen) '\n' noch im puffer sind.

übrigens:
printf("hallo");
warum wirds nicht angezeigt?
weil erst in den stream ausgegeben wird wenn ein '\n' erfolgt.
printf("hallo\n");
das wird angezeigt. - und dafür gibts fflush:
printf("hallo");
fflush(stdout);
jetzt wirds auch angezeigt, fflush(stdout) bewirkt, dass der gesamte inhalt des puffers tatsächlich ausgegeben wird.

ich weis, ich schreibe immer zu lange sachen... ich werd mich nächstes mal bemühen mich kürzer zu fassen;-)

Stefan Feeser
17-04-2001, 11:18
Hi,

nur ne kurze Anmerkung! Meines Erachtens solltest Du bei derartigen Schleifen wie folgt vorgehen:

int main()
{
char[1] janein;

/* Fuer den Fall das man gar nicht in die Schleife rein will - das folgende ist sozusagen Standart */
printf("Wuenschen Sie einen Abbruch? (j/n) ");
scanf("%c\n", &janein);

while(janein != "j")
{
printf("Und nun?" (j/n) ");
scanf("%c\n", &janein);
}

return 0;
}

Weiter denke ich das Du Dein char-Array auf ein Zeichen setzen kannst, da dann nicht bis zum ersten Leerzeichen gewartet werden muß. Aber das getchar ist hier wohl eleganter!

Gruß

Stefan

flasheye
17-04-2001, 17:35
Hallo,

vielen Dank für Eure Anregungen. Vor allem der EXIT Code (return 0 ;) ). Ich habe jetzt nachgelesen, dass dieser dann von einem shell skript ausgewertet werden kann. Auch sehr nützlich.

Nun aber doch noch mal zu meinem Problem. Ich hatte nur die while Schleife gepostet, weil ich dachte, an der wäre etwas nicht in Ordnung. Nun habe ich Stefans Variante probiert, mit dem selben Resultat. Hier ist jetz mal das vollständige skript. Das soll mal ein Programm werden, welches mir nach der Betragseingabe das Wechselgeld ausgibt. Natürlich mite der kleinsmöglichen Bestückung.

main()
{

char ende;

int wgeld5, wgeld2, wgeld1, wgeld05, wgeld01, wgeld005, wgeld002, wgeld001;

double geld;


/*while (ende != 'j') {*/
do {

geld = 0.0;

printf("\n\n");
printf("\t\tWechselgeld 0.5\n\n");

printf("\t\tEingabe:_");
scanf("%f", &geld);

/* An dieser Stelle soll später die */
/* Funktion aufgerufen werden, die */
/* Menge der auszugebenen Münzen */
/* berechnen soll */
printf("\t\tAusgabe: %.2f\n\n", geld);

printf("\n\n");
printf("\tEnde (j/n)");
ende = getchar();


printf("\n\n");

} while (ende != 'j');
/*}*/

return 0;

}

Wenn ich nun das

scanf("%f", &geld);

auskommentiere läuft die while Schleife korrekt. Ob nun Fuss- oder Kopfgesteuert. Das macht keinen Unterschied.

Jetz meine Frage: kommen sich die beiden Eingaben da in die Quere? Witzig ist halt, wenn ich bei Eingabe:_ eine Zahl eingebe, zeigt mir Ausgabe:, dass kein Wert in geld drinsteht. Und wenn ich j eingebe, beendet sich das Programm, so als ob, die double zahl gar nicht eingelesen wird dafür aber der character. Ich hatte vorher 2 scanf's verwendet, was den selben Effekt hatte.

Kann es sein, dass ich die Geldeingabe, bzw die Berechnung der Ausgabebeträge als eigenständige Funktion definieren muss?

Ich wäre für weitere Anregungen sehr dankbar. Ich muss gestehen, dass ich trotz meiner Programmierefahrungen in anderen Sprachen; problemorientiert: COBOL, Quantum; doch sehr an C zu beissen habe.

Als dann, bye

DasSein

[ 17. April 2001: Beitrag editiert von: flasheye ]

[ 17. April 2001: Beitrag editiert von: flasheye ]

[ 17. April 2001: Beitrag editiert von: flasheye ]

[ 17. April 2001: Beitrag editiert von: flasheye ]

stiviman
18-04-2001, 19:16
Mit 100%iger Sicherheit kann ichs nicht sagen, aber ich meine mal:
scanf() liest so lange, bis vom Benutzer ein '\n' kommt. Dieses '\n' bleibt aber im Eingabepuffer und wird NICHT gelöscht.

Beim Aufruf von getchar() gibt der Benutzer dann 'j' ein. Allerdings wird nicht das j zurückgegeben, sondern das nächste Zeichen dass im Puffer ist. Und das ist das '\n'.
Deshalb funktionierts wenn du scanf("%f",&dGeld); weglässt.

char c;
while (c!='j')... ist keine gute Idee, da die Variable c nicht initialisiert wird. Das heißt wenn du Pech hast steht im Speicher der zufällig für die Variable c reserviert wird schon der ASCII-Code für 'j' drin, und dann würde die Schleife gar nicht durchgenommen werden;-)
Grundsätzlich würde ich in C alle Variablen vorinitialisieren, also
char c='n';

flasheye
18-04-2001, 20:56
Hallo,

mittlerweile habe ich den Typ double in float korrigiert. Mir kommt das ein wenig komisch vor, aber jetzt zeigt Ausgabe den eingegebenen Betrag aus. Welchen Zeiger muss ich innerhalb des scanf() benutzen, um einen double einlesen zu können?

Aber nichts desto trotz überlagern sich die beiden Eingaben. So als hätte ich die beiden Inputposition (x/y-Koordinaten) direkt übereinandergelegt. Mittlerweile habe ich aber auch gelesen, dass getchar() zeilenorientiert arbeitet, und dass bei scanf() unvorhersehbare Aktionen autreten können, wenn die Eingabe nicht abgesichert wurde. Sprich in die float Variable wird ein Buchstabe geschrieben, und so fort.

Wenn ich weiter bin, dann melde ich mich wieder.

DasSein :p

flasheye
19-04-2001, 21:29
wow, :eek: megahammer... Dankeschön. Dieses scanf ist wirklich schlimm. Ich werd's gleich mal ausprobieren.

Bye

flasheye
19-04-2001, 23:28
Hi,

ich habs noch nicht ganz verstanden, aber es läuft, juche!

Aber es funktioniert nur mit einem Ausrufezeichen.

do {

} while (!ende);

Als dann, bis zum nächsten turn.

DasSein :rolleyes:

[ 19. April 2001: Beitrag editiert von: flasheye ]

jgbauman
20-04-2001, 00:02
sorry, mein Fehler, natuerlich: while(!ende)

jgbauman
20-04-2001, 00:34
scanf ist zu meiden wie die Pest.
Besser, wenn auch noch nicht perfekt, ist da, eine Eingabezeile komplett zu lesen [fgets()] und diese dann mit sscanf() zu untersuchen.

Lies am bestene die entprechenden man pages.

Und nimm folgendes Beispiel nicht als Kritik sonder als Anregung (is naemlich auch nicht perfekt ;-)

#include <stdlib.h>
#include <stdio.h>

/* maximale Laenge einer Eingabezeile */
#define MAXINPUT 1000

/* Lese ein char als Antwort auf die Frage s */
char read_char(const char *s){
/* Buffer auf dem Stack */
char buf[MAXINPUT+1];
char ch;

/* Gib die Frage aus */
if ( s != NULL) {
printf("%s", s);
fflush(stdout);
}

/* Lese eine komplette Eingabezeile */
fgets(buf, MAXINPUT, stdin);
/* Analysiere die Eingabezeile */
sscanf(buf, "%c", &ch);
return ch;
}

/* Lese ein double als Antwort auf die Frage s */
double read_double(const char *s){
/* Buffer auf dem Stack */
char buf[MAXINPUT+1];
/* 0 als Standardwert falls Eingabe ungueltig */
double d=0.f;

/* Gib die Frage aus */
if ( s != NULL) {
printf("%s", s);
fflush(stdout);
}

/* Lese eine komplette Eingabezeile */
fgets(buf, MAXINPUT, stdin);
/* Analysiere die Eingabezeile (lf == long float == double)*/
sscanf(buf, "%lf", &d);
return d;
}

int main() {

char ende;

int wgeld5, wgeld2, wgeld1, wgeld05, wgeld01, wgeld005, wgeld002, wgeld001;

double geld;

do {
geld = 0.0;

printf("\n\n");
printf("\t\tWechselgeld 0.5\n\n");

geld = read_double("\t\tEingabe: ");

/* An dieser Stelle soll später die */
/* Funktion aufgerufen werden, die */
/* Menge der auszugebenen Münzen */
/* berechnen soll */
printf("\t\tAusgabe: %.2lf\n\n", geld);

printf("\n\n");
/* ende hat den Wert 0 falls kein 'j' gelesen wurden, ansonsten den Wert 1 */
/* das mach Ende zu eine boolschen Variablen in C */
ende = ( 'j' == read_char("\tEnde (j/n) ") );
printf("\n\n");

} while (ende); /* impliziert: while ( ende != 0 ) */

return 0;
}

flasheye
20-04-2001, 18:25
Halli Hallo,

es ist vollbracht, und ich stelle fest: Ich hatte kein C Problem, sondern ein IO Loch. Die Bildschirmein- und -ausgabe unter C ist ja schon ein bisschen blöde, aber wenn ich daran denke, dass diese Sprache gaanz andere Sachen noch viieeel besser kann, freue ich mich schon darauf, es richtig zu können. In 2 oder drei Jahren meine ich natürlich. :rolleyes:

Aber wie das ja so ist, hat mir die Lösung jetzt doch noch eine Frage aufgeworfen. Warum gibt das Programm ohne

*betrag += 0.01;

immer einen Pfennig zu wenig aus?


Hier nun das fertige skript:

#include "<"stdio.h">" <--Auch lustg, ohne ""
#include "<"stdlib.h">" siet mans nicht.



/************************************************** ************************************************** ***************************/

#define MAXINPUT 1000 /* maximale Laenge einer Eingabezeile */

/************************************************** ************************************************** ***************************/

/* Lese ein char als Antwort auf die Frage s */


char read_char(const char *s) { /* Buffer auf dem Stack */

char buf[MAXINPUT+1];
char ch;

if ( s != NULL) { /* Gib die Frage aus */
printf("%s", s);
fflush(stdout);
}

fgets(buf, MAXINPUT, stdin); /* Lese eine komplette Eingabezeile */
sscanf(buf, "%c", &ch); /* Analysiere die Eingabezeile */
return ch;

}

/************************************************** ************************************************** ***************************/

/* Lese ein double als Antwort auf die Frage s */


double read_double(const char *s) {

char buf[MAXINPUT+1]; /* Buffer auf dem Stack */

double d = 0.f; /* 0 als Standardwert falls Eingabe ungueltig */

if ( s != NULL) { /* Gib die Frage aus */
printf("%s", s);
fflush(stdout);
}

fgets(buf, MAXINPUT, stdin); /* Lese eine komplette Eingabezeile */
sscanf(buf, "%lf", &d); /* Analysiere die Eingabezeile (lf == long float == double)*/
return d;

}

/************************************************** ************************************************** ***************************/

/* Wechselgeld berechnen */

int berech(int ind, double *betrag, float *teilen) {

int rueck = 0;


switch (ind) {

case 0: *teilen = 5.0; break;
case 1: *teilen = 2.0; break;
case 2: *teilen = 1.0; break;
case 3: *teilen = 0.5; break;
case 4: *teilen = 0.1; break;
case 5: *teilen = 0.05; break;
case 6: *teilen = 0.02; break;
case 7: *teilen = 0.01;
*betrag += 0.01; break;

}

rueck = *betrag / *teilen;
*betrag -= (*teilen * rueck);
return rueck;

}


/************************************************** ************************************************** ***************************/


int main() {

char ende;

int i, wgeld[8];

double geld;
float teiler;

do {

geld = teiler = 0.0;
for (i = 0; i <= 7; i++) {
wgeld[i] = 0;
}

printf("\n\n");
printf("\t\tWechselgeld 0.1\n");
printf("\t\t===============\n\n");

geld = read_double("\t\tEingabe: ");

printf("\n\n");

for (i = 0; i <= 7; i++) {
printf("\t\tMünze(%.2f): %d mal\n", teiler, (wgeld[i] = berech(i, &geld, &teiler)));
}


printf("\n\n");

ende = ( 'j' == read_char("\tEnde (j/n) ") ); /* ende hat den Wert 0 falls kein 'j' gelesen wurden, ansonsten den Wert 1 */
/* das mach Ende zu eine boolschen Variablen in C */
printf("\n\n");

} while (!ende); /* impliziert: while ( ende != 0 ) */

return 0;

}

Bye...
DasSein :)

[ 20. April 2001: Beitrag editiert von: flasheye ]

[ 20. April 2001: Beitrag editiert von: flasheye ]

[ 20. April 2001: Beitrag editiert von: flasheye ]

[ 20. April 2001: Beitrag editiert von: flasheye ]
:confused:

[ 20. April 2001: Beitrag editiert von: flasheye ]

flasheye
20-04-2001, 21:03
Ich habe double teiler genommen, jezt kann ich *betrag += 0.01 weglassen.

War nartürlich die genauigkeit. Jetzt tritt der Pfennigschlucker erst ab einem Bertag grösser 10 zu Tage. Weiss jemand warum? Hat das was damit zu tun, dass der Quotient vom Typ int ist und die beiden anderen Variablen vom Typ double?


Tschüüss
DasSein :D

[ 20. April 2001: Beitrag editiert von: flasheye ]

jgbauman
21-04-2001, 01:53
Die Zeile
rueck = (float)(*betrag / *teilen); und das Weglassen von dem
*betrag+=0.01 sollte helfen. Ist leider nicht so ganz einsichtig. Da geht wohl was mit der type coersion daneben. Muesste mal wieder im Standard waelzen um genau zu sagen was da schief lauft :-(

Du koenntest auch noch deine switch-Anweisung durch ein Array (evtl in main) ersetzen.

Ich wuerde auch den Betrag mal 100 nehmen und dann mit int in Pfennig (und eventuell schon mal auf die Euro-Umstellung [dann Cents] vorbereiten ;-) weiterrechnen. Aber das ist Geschmackssache.

Huebsch waere es auch noch die for-schleife mit in die berech Funktion zu ziehen und berech den Betrag, die Muenzsortenanzahl, ein Array mit den Wertigkeiten der Muenzen und ein Array zum Speichern der Anzahl der einzelnen Muenzsorten (Ergebnis) zu uebergeben. Natuerlich sollte dann die Ausgabe in einer separaten for-Schleife, ausserhalb von berech stattfinden.
Und nun wuerde es sich schon fast lohnen mit #define eine Konstante fuer die Muenzsortenanzahl einzufuehren.

Wieso initialisierts Du wgeld[...] anfangs mit null, wenn Du spaeter sowieso Werte zuweist? War das Absicht, nach dem Motto: Wir schreiben Code, der sich moeglichst uebersichtlich verhaelt und Probleme durch zu starke Optimierung vermeidet? Dann war das sehr loeblich ;-)

Nur so als Denkanstoesse ...
viel Spass noch

flasheye
21-04-2001, 13:49
Hallo jgbaumann,

das habe ich mir schon gedacht, dass das mit den verschiedenen Typen zu tun hat. Das initialisieren wichtiger Variablen ist übrigens eine Angewohnheit. Immer auf Nummer Sicher gehn. Man weiss ja nie, was vorher drinsteht. Ich hatte in meinem Job diesbezüglich schon einige peinliche Momente.

Ach ja, und den Betrag mal 100 nehmen, ich vergass. Das war ja bei Pascal auch so, hätte nicht gedacht, dass ich bei C auch auf dieses Problem stosse. Bin halt auch schon einige Zeit raus aus Tunbo Pascal. Ich habe zur Zeit aus beruflichen Gründen mit Quantum und Quancept zu tun. Das sind problemorientierte Sprachen, auf die Bedürfnisse der Marktforschung ausgerichtet. Das ist so plump und easy, das mein Hirn 'n Saugerloch kriegt.

Als dann, bis bald....
DasSein :-)