Forum: PC-Programmierung Problem mit gets()


von der_lord (Gast)


Lesenswert?

Hallo Leute!

Ich habe ein Problem mit der Funktion gets();

Ich möchte einen Taschenrechner programmieren, der zunächst einmal die 
Anfangszahl einliest und anschließend diese Zahl und zusätzlich den 
eingegebenen Operator zu einem Ergebnis errechnet, bis das "=" 2x 
gedrückt wird.

So solls aussehen:

    Eingabe Startzahl: 833
    833+3        RETURN drücken
    =836-4       RETURN drücken
    =832*2       RETURN drücken
    =1664/4      RETURN drücken
    =416==       RETURN drücken
    ENDE



Das Ganze möchte ich mit der Funktion gets() machen. Das Problem ist 
aber, dass der Cursor nicht beim Aufruf von gets() anhält, sondern das 
Programm einfach weiterläuft, ohne dass ich eine Eingabe getätigt habe.

Hier mein Codeschnipsel:
1
#include <stdio.h>
2
3
int main (void)
4
{
5
  float Anfangszahl;
6
  char Operator_und_Zahl[20];
7
8
  printf("Anfangszahl eingeben: ");
9
  scanf("%f",&Anfangszahl);
10
  printf("= %.7f\n",Anfangszahl);
11
  gets(Operator_und_Zahl);       //Hier sollte der Cursor stehen bleiben, damit ich meine Eingabe tätigen kann
12
  if (Operator_und_Zahl[0]=='=')
13
    printf("FERTIG!");
14
15
system("pause");
16
  
17
}



Vielen Dank!

von Gerry E. (micky01)


Lesenswert?

Was macht denn Dein Programm falsch?
Hast Du mal an die Benutzung einer Schleife gedacht?
"while" vielleicht...

von Karl H. (kbuchegg)


Lesenswert?

Das Problem ist an dieser Stelle nicht gets, sondern scanf.
scnaf liest zwar das \n mit ein, stellt es aber wieder in die 
EingabeQueue zurück, da es für die Eingabe hier
  scanf("%f",&Anfangszahl);
nicht gebraucht wurde.
Dann kommt gets zu Zug und findet als allererstes das Return vor, 
welches bei der Eingabe der Zahl übrig blieb.

Mischen von getch(), scanf() und gets() ist meistens eine schlechte 
Idee. Man verliert sehr schnell den Überblick, welche Zeichen noch in 
der Eingabe auf Bearbeitung warten und welche nicht.


Übrigens: gets ist in C eine "Funktion non grata".
man sollte sie NIE benutzen. Dass sie in C noch vorhanden ist, hat 
historische Ursachen.
gets:  ein definitives NO-NO
fegts: die Funktion der Wahl

(Da du auf einem Taschenrechner bist, kann es natürlich sein, dass du 
kein fgets zur Verfügung hast. Solche Umgebungen sind meist ein wenig 
eigen. Aber du solltest auf jeden Fall feststellen ob du fgets hast und 
wenn ja gleich wieder vergessen, jemals von einer Funktion gets gehört 
zu haben. Oder die C-Götter mögen dich mit einer 10 Jahre andauernden 
Kretze bestrafen. gets ist für mehr vom Benutzer verursachte Abstürze, 
Progamm-Cracker-eien und sonstige lausige Fehler in C Programmen 
verantwortlich, als irgendeine andere Funktion)

von der_lord (Gast)


Lesenswert?

Ok danke erstmal für die schnelle Hilfe.

Ich werde es dann wohl mit scanf() machen. Nun aber noch eine Frage:

Ich habe ja oben in meinem Beispiel den Ablauf des Programms gezeigt. 
Wie kann ich sozusagen Zwei unterschiedliche Eingaben mit scanf() 
trennen?
Die Erste Eingabe wäre ja das Rechenzeichen (sprich, welche Operation 
ausgeführt werden soll). Die zweite Eingabe wäre dann die Zahl, mit der 
das gewünschte Rechenzeichen arbeiten soll.

Vielen Dank!

von Karl H. (kbuchegg)


Lesenswert?

der_lord schrieb:

> Ich werde es dann wohl mit scanf() machen. Nun aber noch eine Frage:

Das war die falsche Entscheidung :-)
fgets wäre es gewesen, zusammen mit einem Auftrennen der Eingabe in 
deinem Programm.
Robuste Eingabe erhält man praktisch nur mit der Methode:
  Die Eingabe des Benutzers wird immer erst als ein String eingelesen.
  Das Programm analysiert dann String um die Einzelteile der Eingabe
  zu bestimmen.

Es gibt zwar seit dem letzten C-Standard so etwas wie "regular 
Expressions" in der Formatanweisung, aber
   1) kenn ich mich damit wenig aus
   2) halte ich die selbst-Aufdröselmethode immer noch für besser,
      da sie einem bessere Fehlermeldungen im Falle eines Falles
      erlaubt

> Ich habe ja oben in meinem Beispiel den Ablauf des Programms gezeigt.
> Wie kann ich sozusagen Zwei unterschiedliche Eingaben mit scanf()
> trennen?

Da du noch am Anfang stehst, ist ein sauberes Stringparsen 
wahrscheinlich noch zu schwierig für dich. Daher

> Die Erste Eingabe wäre ja das Rechenzeichen (sprich, welche Operation
> ausgeführt werden soll). Die zweite Eingabe wäre dann die Zahl, mit der
> das gewünschte Rechenzeichen arbeiten soll.

Man kann bei scanf auch mehrere 'Formatieranweisungen' geben

  double Zahl1, Zahl2;
  char   Zeichen;

  scanf( "%f%c%f", &Zahl1, &Zeichen, &Zahl2 );

Eine Eingabe von
  833+78

wird von scanf dann in
    Zahl1 = 833
    Zeichen = '+'
    Zahl2 = 78
aufgedröselt.

von der_lord (Gast)


Lesenswert?

OK, vielen vielen Dank, ich werde es nachher versuchen,
man merkt, hier sind Profis im Forum :)

von der_lord (Gast)


Lesenswert?

Jetzt habe ich das Problem, dass scanf() anscheinend falsch mit den 
float-Werten rechnet.

Gebe ich zum Beispiel:
491.00000+2   ein, so kommt als Ergebnis 490 raus.

Hier nun der etwas veränderte Code:
1
#include <stdio.h>
2
3
int main (void)
4
{
5
  float Anfangszahl;
6
  char Operator;
7
  float Zahl;
8
  printf("Anfangszahl eingeben: ");
9
  scanf("%f",&Anfangszahl);
10
  printf("= %.7f",Anfangszahl);
11
  scanf("%c%f",&Operator,&Zahl);
12
  while(Operator!="=")
13
  {
14
    printf(" = %f",Zahl+Anfangszahl);
15
    scanf("%c%f",&Operator,&Zahl);
16
  }
17
18
19
system("pause");
20
  
21
}

von Karl H. (kbuchegg)


Lesenswert?

scanf rechnet überhaupt nicht.

Aber in solchen Fällen, in denen man eine Benutzereingabe auswerten 
will, ist es IMMER eine extrem gute Idee, sich erst mal das was das 
Programm überhaupt eingelesen hat ganz einfach ausgeben zu lassen.

Denn viel öfter als man denkt, liest das Programm nicht das ein, was der 
Programmierer sich vorstellt.
1
  scanf("%f",&Anfangszahl);
2
  printf("= %.7f",Anfangszahl);
3
  scanf("%c%f",&Operator,&Zahl);
4
5
  printf( "Eingelesen: #%c# %f\n", Operator, Zahl );

Ich habe auch vor und hinter das Operator-Zeichen in der Ausgabe ein 
Sonderzeichen (in dem Fall #) eingefügt, damit ich in der Ausgabe auch 
Leerzeichen oder sonstige nicht-darstellbare Zeichen erkennen kann.

von der_lord (Gast)


Lesenswert?

Also die Ausgabe stimmt soweit. Das Problem ist aber trotzdem noch da :(

von Karl H. (kbuchegg)


Lesenswert?

Was genau gibst du ein?

von der_lord (Gast)


Lesenswert?

ich gebe ein:

Anfangszahl: 4

Dann erscheint in der Konsole:

4.0000000


dann gebe ich
+6 ein, dann stimmt das Ergebnis.
Es erscheint
10.0000000

Gebe ich jetzt aber erneut einen Wert zur Addition ein, dann stimmt der 
Wert nicht.

10.0000000+3
dann kommt als Ergebnis
7.0000000

von ... .. (docean) Benutzerseite


Lesenswert?

while(Operator!="=")

ist auch nicht ganz richtig "=" ist ein String, besser ist ein '=' das 
ist ein char

von Karl H. (kbuchegg)


Lesenswert?

der_lord schrieb:
> ich gebe ein:
>
> Anfangszahl: 4
>
> Dann erscheint in der Konsole:
>
> 4.0000000
>
>
> dann gebe ich
> +6 ein, dann stimmt das Ergebnis.
> Es erscheint
> 10.0000000
>
> Gebe ich jetzt aber erneut einen Wert zur Addition ein,

aha.
Wir sind also im 2.ten Durchlauf durch die while Schleife.
Hast du dir auch ausgeben lassen, was da dann eingelesen wurde.

> dann stimmt der
> Wert nicht.
>
> 10.0000000+3
> dann kommt als Ergebnis
> 7.0000000

Ist doch richtig!
4 + 3 ergibt 7

(Du änderst ja nie deine Anfangszahl, rechnest aber immer Anfangszahl + 
Zahl)

von der_lord (Gast)


Lesenswert?

Hallo Leute!

Es geht immer noch nicht :( Hatte gestsern keine Zeit mehr 
weiterzuprogrammieren.

Ich finde den Fehler einfach nicht....Das Programm fragt zwar nach der 
Anfangszahl, rechnet aber danach nicht mit den Werten weiter und gibt 
bei der printf-Anweisung nichts aus...

Hier mein Code:
1
#include <stdio.h>
2
3
int main (void)
4
{
5
  float Anfangszahl;
6
  char Operator;
7
  float Zahl;
8
  printf("Anfangszahl eingeben: ");
9
  scanf("%f",&Anfangszahl);
10
  printf("= %f",Anfangszahl);
11
  
12
  do
13
  {
14
    scanf("%c%f",&Operator,&Zahl);
15
    switch(Operator)
16
    {
17
      case '+':  Anfangszahl = Anfangszahl+Zahl;
18
            printf("= %.7f",Anfangszahl);
19
            break;
20
      case '-':  Anfangszahl = Anfangszahl+Zahl;
21
            printf("= %.7f",Anfangszahl);
22
            break;
23
    }
24
  }while(Operator!='=')
25
26
system("pause");
27
  
28
}

Vielen Dank!

von Karl H. (kbuchegg)


Lesenswert?

der_lord schrieb:

> Ich finde den Fehler einfach nicht....Das Programm fragt zwar nach der
> Anfangszahl, rechnet aber danach nicht mit den Werten weiter und gibt
> bei der printf-Anweisung nichts aus...

Dann befolge den vorher schon gegebenen Rat:
Wenn dir nicht klar ist, was im Programm warum abgeht, dann verschaffe 
dir Klarheit, indem du ins Programm printf Anweisungen einbaust, die dir 
sagen was wann und warum passiert.

>   do
>   {
>     scanf("%c%f",&Operator,&Zahl);

printf( "Op: %c  Zahl: %f\n", Operator, Zahl );

>     switch(Operator)
>     {
>       case '+':
              printf( "Berechne Addition:  %f + %f\n", Anfangszahl, Zahl 
);
>             Anfangszahl = Anfangszahl+Zahl;
>             printf("= %.7f",Anfangszahl);
>             break;
>       case '-':
              printf( "Berechne Subtraktion:  %f - %f\n", Anfangszahl, 
Zahl );
>             Anfangszahl = Anfangszahl+Zahl;
>             printf("= %.7f",Anfangszahl);
>             break;

        default:
          printf( "Unbekannter Operator: %c\n", Operator );

>     }
>   }while(Operator!='=')
>

von der_lord (Gast)


Lesenswert?

Jetzt fange ich mal schrittweise an das Programm zu verstehen...Ich habe 
das Ganze jetzt erstmal Schritt-für-Schritt aufgefädelt.

Nun möchte ich mir lediglich den Operator und die Zahl ausgeben lassen, 
die ich vorher eingegeben habe...Und das funktioniert schon mal nicht.
1
#include <stdio.h>
2
3
int main (void)
4
{
5
  float Anfangszahl=0;
6
  float Zahl=0;
7
  char Operator;
8
9
  printf("Anfangszahl eingeben");
10
  scanf("%f",&Anfangszahl);
11
  printf("= %f",Anfangszahl);
12
  scanf("%c%f",&Operator,&Zahl);
13
  
14
  printf("Operator:%c  Zahl:%f",Operator,Zahl);
15
  system("pause");
16
  return 0;
17
}

Woran liegt es, dass bei "Operator" nichts ausgegeben wird und die 
Variable "Zahl" in der printf-Anweisung richtig ausgegeben wird?
Können mit scanf die beiden Parameter doch nicht einfach hintereinander 
eingelesen werden?!

Danke!

von Klaus W. (mfgkw)


Lesenswert?

Tja, wenn du wenigstens den Rückgabewert von scanf()
prüfen würdest, wüsstest du, ob das Einlesen überhaupt
geklappt hat.

Außerdem kann man ein char auch mit %d ausgeben und sieht dann
den ASCII-Code; das hilft bei komischen Werten mehr
(Steuerzeichen, Leerzeichen etc..

Das Verhalten hängt natürlich auch von deiner Eingabe ab, die
hier niemand sieht.

von Karl H. (kbuchegg)


Lesenswert?

der_lord schrieb:

> Woran liegt es, dass bei "Operator" nichts ausgegeben wird

Doch.
Es wird etwas ausgegeben :-)

Dieser
  scanf("%c%f",&Operator,&Zahl);

schnappt sich für Operator den Return, der beim vorhergehenden scanf 
übrig geblieben ist :-)

Dass deine Zahl trotzdem richtig kommt, liegt daran, dass du 
wahrscheinlich irgendwas in der Art "+67" eingibst. Und ein + ist ein 
gültiger Anfang für eine Zahl. Gib als Antwort auf den 2.ten scanf mal 
"*8" ein und du wirst sehen, dass Zahl nicht deiner Eingabe entspricht.

Vielleicht verstehst du jetzt langsam, warum robuste Eingabe praktisch 
immer über den Weg fgets/sscanf führt :-)

Aber probiers mal so:

  printf("Anfangszahl eingeben");
  scanf("%f",&Anfangszahl);
  printf("= %f",Anfangszahl);
  scanf("\n%c%f",&Operator,&Zahl);

Hier wird dem 2.ten scanf aufgetragen, den \n der noch in der Eingabe 
auf bBearbeitung wartet, einfach zu überlesen.

von der_lord (Gast)


Lesenswert?

Schwer jetzt darauf was zu schreiben...

Ich weiß ehrlichgesagt nicht, wie ich dann mit dieser scanf-Anweisung 
beide Werte "richtig" entgegennehmen lassen kann.

Ich gebe jetzt folgendes ein:

So sieht nun meine Ausgabe aus, wenn ich den Platzhalter %c mit %d 
ersetze:
1
printf("Operator:%d  Zahl:%f\n\n",Operator,Zahl);
1
Anfangszahl: 300
2
3
300.0000000+5      RETURN
4
Operator:10  Zahl:5.0000000
5
6
Drücken sie eine beliebige Taste....


Danke!

von der_lord (Gast)


Lesenswert?

Hallo Leute!

Also ich habs jetzt soweit geschafft, allerdings springt er mir noch 
nicht aus der Schleife, sobald ich ein "=" eingebe....

Woran liegt das? Die Ausführ-Bedingung für die Schleife ist doch, 
solange die Eingabe ungleich "=" ist.Oder?


Hier mein Code:
1
#include <stdio.h>
2
3
int main (void)
4
{
5
  float Anfangszahl;
6
  char Operator;
7
  float Zahl;
8
  printf("Anfangszahl eingeben: ");
9
  scanf("%f",&Anfangszahl);
10
  printf("= %f",Anfangszahl);
11
  
12
  do
13
  {
14
    scanf("\n%c%f",&Operator,&Zahl);
15
    switch(Operator)
16
    {
17
      case '+':    Anfangszahl = Anfangszahl+Zahl;
18
          printf("= %.7f",Anfangszahl);
19
          break;
20
21
      case '-':    Anfangszahl = Anfangszahl-Zahl;
22
          printf("= %.7f",Anfangszahl);
23
          break;
24
25
    case '*':    Anfangszahl = Anfangszahl*Zahl;
26
          printf("= %.7f",Anfangszahl);
27
          break;
28
29
    case '/':    Anfangszahl = Anfangszahl/Zahl;
30
          printf("= %.7f",Anfangszahl);
31
          break;
32
  
33
    default:    printf("==%.7f",Anfangszahl);
34
          break;
35
36
    }
37
  }while(Operator!='=');
38
39
system("pause");
40
  
41
}

Vielen Dank!

von HildeK (Gast)


Lesenswert?

Diese Zeile erfordert zwei Eingaben, d.h. nur mit dem '=' wird scanf 
noch nicht beendet.
 scanf("\n%c%f",&Operator,&Zahl);

Gib einfach mal "= 0" ein anstatt nur '='.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.