Problem mit getchar

B

ByeBye 249714

Code:
#include <stdio.h>

int main()
{
  char eingabe;
  int zahl;
  printf("\nGeben sie ein Zahl ein: ");
  scanf("%i", &zahl);
  Label1: printf("Geben sie (H)exadezimal, (O)ktal, (A)scii ein: ");
  eingabe=getchar();
  switch(toupper(eingabe)) {
                           case 'H':
                                printf("\n%i Dezimal ist %x Hexadezimal\n", zahl, zahl);
                                break;
                           case 'O':
                                printf("\n%i Dezimal ist %o Oktal\n", zahl, zahl);
                                break;
                           case 'A':
                                printf("\n%i Dezimal ist %c Hexadezimal\n", zahl, zahl);
                                break;
                           default: printf("\nUngültige Operation.\n\n");
                                    goto Label1;
                           }                                
  system("PAUSE");	
  return 0;
}

Wie kann ich hier verhindern, dass die eingelesene Zahl in getchar geschrieben wird? (ohne zuerst abzufragen, wie man die Zahl dargestellt haben möchte) auch mit scanf? Aber wozu benutzt man dann getchar?
 
Zuletzt bearbeitet von einem Moderator:
Hi

Es ist für mich leider unverständlich, was du willst, alo rate ich mal...

Verhindern, dass getchar was einliest, kannst du, indem du es aus dem Quelltext rauslöscht.
Ebenso mit der Abfrage (nach H O A).

Hier wird nirgends eine Zahl in getchar geschrieben
Man kann mit der Tastatur "in getchar schreiben", aber nicht im Quelltext.

Und getchar ist von der Funktionsweise her das Gleiche wie scanf("%c").

Gruß
 
Na, vielleicht noch etwas genauer mein Problem:
Nachdem ich eine Zahl eingelesen habe, möchte ich mittels getchar einen Buchstabe einlesen.
Problem: getchar nimmt sich die Zahl die ich zuvor eingelesen habe.. ich möchte quasi, dass getchar ignoriert, was vor "Label1" passiert ist
 
Hi

Das ist leider ein typisches Problem von scanf.

Probier mal statt
C++:
scanf("%i", &zahl);
das zu schreiben:
C++:
zahl=inteinlesen();
mit dieser Funktion:
C++:
int inteinlesen()
{
    int erg;char str[24];
    do
    {
        fgets(str,24,stdin);
        erg=strlen(str)-1;
        if(erg>=0&&str[erg]=='\n')str[erg]='\0';
        else{while(fgetc(stdin) != '\n');}
    }while(1!=sscanf(str,"%d",&erg));
    return erg;
}
Habs sie jetzt ohne zu testen einfach hingetippt, sag wenns nicht funktioniert.

Gruß

edit: Moment, das ist die falsche Funktion. Ich such die richtige...
edit2: Jetzt richtig.
 
Zuletzt bearbeitet:
Code:
#include <stdio.h>

int inteinlesen()
{
    int erg;char str[24];
    do
    {
        fgets(str,24,stdin);
        erg=strlen(str)-1;
        if(erg>=0&&str[erg]=='\n')str[erg]='\0';
        else{while(fgetc(stdin) != '\n');}
    }while(1!=sscanf(str,"%d",&erg));
    return erg;
}

int main()
{
  char eingabe;
  int zahl;
  printf("\nGeben sie ein Zahl ein: ");
  zahl=inteinlesen;                                                 //scanf("%i", &zahl);
  Label1: printf("Geben sie (H)exadezimal, (O)ktal, (A)scii ein: ");
  eingabe=getchar();
  switch(toupper(eingabe)) {
                           case 'H':
                                printf("\n%i Dezimal ist %x Hexadezimal\n\n", zahl, zahl);
                                break;
                           case 'O':
                                printf("\n%i Dezimal ist %o Oktal\n\n", zahl, zahl);
                                break;
                           case 'A':
                                if (zahl<=255) printf("\n%i Dezimal ist %c Hexadezimal\n", zahl, zahl);
                                else printf("\n%i Ungültige Operation.\n\n", zahl, zahl);
                                break;
                           default: printf("\nUngültige Operation.\n\n");
                                    goto Label1;
                           }                                
  system("PAUSE");	
  return 0;
}

Hm, abgesehen davon dass ich die Funktion noch nicht wirklich durchschaue (bin noch in den Anfängen C zu lernen, die Begriffe kommen bestimmt später noch), funktionierts mit dem Quelltext oben nicht. Habe ich irgendwas falsch eingefügt?
 
Klappt! Jetzt zu deiner Funktion:

Code:
int inteinlesen()
{
    int erg;char str[24];
    do
    {
        fgets(str,24,stdin);
        erg=strlen(str)-1;
        if(erg>=0&&str[erg]=='\n')str[erg]='\0';
        else{while(fgetc(stdin) != '\n');}
    }while(1!=sscanf(str,"%d",&erg));
    return erg;
}

Im Endeffekt wird eine Zahl ausgegeben (die, dich eingeben werde).
Das Array str[24] kann man auch als Zeiger auf die 0te Stelle im Array auffassen.

Jetzt macht die Funktion etwas bestimmtes, bis sie danach feststellt (do.. while), dass sscanf(str,"%d",&erg) gleich 1 ist (d.h. bis die Überprüfung wahr ist? d.h. bis sscanf in dem Array str "%d" findet? )

Insbesondere verstehe ich auch diese Zeile nicht: while(fgetc(stdin) != '\n');
das \n und \0 hat doch bestimmt etwas damit zu tun, dass Strings am Ende mit \0 im Rechner dargestellt werden; aber was wird denn solang "fgetc(stdin) != '\n'" gemacht?

Allgemein bin ich mit den Begriffen fgets, stdin, sscanf nicht vertraut
 
Aalso,
der Reihe nach durch:

int erg;
mach ich nur, damit ich eben ein int zum zwischenspeichern der Eingabe habe, bevor ich es dann mit return zurückgebe.

char str[24];
legt einen String mit 24 Buchstaben an (oder ein char-Array mit 24 chars, was dir besser gefällt).
Jedenfalls 24 chars zusammen.
Warum 24? Schicksal.
Nein, im Ernst: Ich brauch in der Funktion einen String, in dem ich ein int abspeichern kann (und zwar nicht in einem 4-Byte-int, sondern Ziffer für Ziffer in je einem char).
Der maximale Wert von einem 4-Byte-int ist irgendwo um die 4 Milliarden.
4000000000. Das sind maximal 10 Ziffern. Dazu noch die abschließende binäre Null (\0), die später (wenn in str was drinsteht) das Ende markieren wird. Macht maximal 11 benötigte chars. Plus die Entertaste am Schluss macht 12. (Normalerweise muss man die nicht mitzählen, hier aber schon. Warum? Weiter unten)
Aber weils gerade so eine schöne Zahl war, hab ich 24 genommen...jaja
Mit 12 müsste es auch problemlos funktionieren.

Dann eine do-while Schleife.
Warum nicht nur while?
do-while wird sicher einmal durchgemacht, bevor die Bedingung geprüft wird und eventuell daraufhin aufgehört wird.
Das normale while prüft gleich am Anfang, wird also eventuell (wenn die Bedingung nicht passt) nie zum "Inneren" der Schleife kommen.

Das Schleifeninnere behandle ich (zur besseren Übersicht) besser weiter unten extra.
Grob gesagt wird eine Zeile von der Tastatur buchstabenweise in das char-Array str gespeichert (wie gewohnt bis zur Entertaste)
Genauer unten.

Dann sscanf:
scanf kennst du. Das liest was von der Tastatur ein (und speichert es je nach %... in irgendwelche Variablen).
sscanf macht fast das Gleiche, Aber: Es holt sich die Eingabe nicht von der Tastatur, sondern von so einem Buchstabenarray wie str.
Der Benutzer hat also eine Zahl eingegeben, die aber wegen dem Schleifeninneren nicht in einem int, sondern Ziffer-/Buchstaben-Weise in str ist.
Jetzt kommt sscanf und macht daraus %d (oder %i, ist egal, steht beides für ein int). Abgespeichert wird das im int erg vom Anfang (erg wie Ergebnis).

Warum vergleich ich das als Schleifenbedingung mit 1?
Die gesamte scanf-Gruppe (scanf, sscanf, fscanf ... etc) hat auch ein int als Returnwert.
Zurückgegeben wird die Anzahl der erfolgreich eingelesenen Variablen.
Da mein sscanf nur ein %d, also ein int, einlesen soll, gibt es im OK-Fall 1 zurück.

Also wenn 1 herausgekommen ist, ist alles in Ordnung, die Schleife ist aus und die Zahl (die in erg gespeichert ist) wird zurückgegeben. rein in dein int zahl im main.
Wenn aber beim sscanf nicht 1 rausgekommen ist, ist irgendein Fehler aufgetreten.
zB hat der Benutzer keine Zahl eingegeben, sonder zB sowas: "12as34df".
Wenn das sscanf fertig ist, kann man am Inhalt vom erg nicht erkennen, ob alles in Ordnung war.
Es wird irgendwas drinstehen, aber der Benutzer könnte die Zahl ja eingegeben haben.
Also prüfe ich eben den Returnwert von sscanf.

Wenn der Benutzer irgendwas unpassendes eingegeben hat, mach ich durch die Schleife die ganze Einlese-Prozedur nocheinmal und ihm eine weitere Eingabemöglichkeit. Solange, bis er wirklich eine ordentliche Zahl eingibt.

Puuhh...Schleifeninneres kommt noch...
 
Zuletzt bearbeitet:
Zurück