Forum: PC-Programmierung Schleife mit ESC-abbruch geht das?


von moony (Gast)


Lesenswert?

Hi!

Ich habe auch erst mit VC++ angefangen, und nachdem ich jetzt mal ein 
paar Tutorials durchgearbeitet habe, wollte ich mal ein eigenes Programm 
schreiben. Aber jetzt hänge ich an einer Stele fest.

Ich habe in einer case-Anweisung eine do-while-Schleife. Ich will es so 
haben, dass der compiler so lange die Schleifenanweisungen macht, bis 
der jemand die ESC-Taste gedrückt hat. Leider klappt das bei mir nicht.

Ich habe geschrieben:

int abbruch;
...

#define   ESC      27

...

case 2:
  {
    cin.get();
    do
    {
         printf("Hallo");
    }
    while (abbruch != ESC);
  }
break;

...

Das Programm zeigt mir aber immer nur das Wort "Hallo" aus.
Was kann ich da jetzt tun?

Danke & gruß
Moony

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Du solltest den Rückgabewert von cin.get() auch auswerten ... Du weist 
ihn aber keiner Variablen zu.
Versuche mal folgendes

  abbruch = cin.get();

von moony (Gast)


Lesenswert?

ja, das hatte ich auch schon. Das hat zwar funktioniert, aber ich wollte 
unbedingt abbruch auf ESC haben, da ich noch etliches in die Shcleife 
reinmachen werde, und dann auch sicher mal zwischendurch cin.get() 
verwenden werde. Wenn es dann so weit ist, beendet er mitten in der 
Schleife, und das wäre nicht so schön. :-)

Hat jemand noch eine Idee wie man das machen könnte?

ich habe vergessen dazuzusagen, dass die do-while Schleife nicht 
zwingent nötig ist. Einfach nur eine Schleife, die zuende sein sollte, 
wenn man ESC drückt.

Dank & Gruß

moony

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

> ja, das hatte ich auch schon. Das hat zwar funktioniert, aber ich wollte
> unbedingt abbruch auf ESC haben, da ich noch etliches in die Shcleife
> reinmachen werde, und dann auch sicher mal zwischendurch cin.get()
> verwenden werde. Wenn es dann so weit ist, beendet er mitten in der
> Schleife, und das wäre nicht so schön. :-)

Lies Dir das bitte nochmal durch. Verstehst Du das, was Du da 
geschrieben hast?

Ich nicht.

von moony (Gast)


Lesenswert?

ja, ich verstehe das.

Ich meinte:

Wenn ich die Schleife abbrechen lasse, wenn man ENTER drückt, und dann 
noch in die Schleife schreibe, dass er weitermachen soll wenn man ENTER 
drückt, dann bricht er an der Stelle ab, wo es eigentlich weitergehen 
soll wenn man ENTER drückt. und das wäre nicht so schön.

Jetzt verstanden?

Moony

von Chris (Gast)


Lesenswert?

Dann liegt das Problem aber in der Programmlogik. Du musst dir also 
erstmal selbst darüber klar werden, was das Programm mit welchem 
Tastendruck zu welchem Zeitpunkt anfangen soll.

Ein Kommandozeilen-Tool bricht man übrigens üblicherweise nicht mit 
Escape ab, sondern mit Signalen wie SIGINT, das durch den Tastendruck 
Strg-C erzeugt wird.

von Uhu U. (uhu)


Lesenswert?

Chris wrote:
> Ein Kommandozeilen-Tool bricht man übrigens üblicherweise nicht mit
> Escape ab, sondern mit Signalen wie SIGINT, das durch den Tastendruck
> Strg-C erzeugt wird.

Das stimmt so nicht. Strg-C killt das Programm, d.h., es wird dort 
beendet, wo es sich gerade befindet. Ein reguläres Beenden ist so nicht 
möglich.

Die Idee, ESC zu verwenden, um die Schleife zu beenden und dann evtl. 
regulär zu terminieren, oder auch irgendwas anderes zu machen, ist weder 
exotisch, noch falsch, sondern durchaus naheliegend.

@moony
Versuchs mal mit cin.getc(abbruch); -- abbruch muß dann allerdings als 
char definiert sein.

von déjà vu (Gast)


Lesenswert?

>Das stimmt so nicht. Strg-C killt das Programm, d.h., es wird dort
>beendet, wo es sich gerade befindet. Ein reguläres Beenden ist so nicht
>möglich.
Das stimmt so aber auch nicht. Ich weiss nicht, wie das C-Aequivalent 
ist, aber mit PERL geht ein sauberers Beenden bei Strg-C so:

SIG{INT} = sub { do_this_and_that(); exit 0};

von Thomas B. (yahp) Benutzerseite


Lesenswert?

> Das stimmt so nicht. Strg-C killt das Programm, d.h., es wird dort
> beendet, wo es sich gerade befindet. Ein reguläres Beenden ist so nicht
> möglich.

Das ist doch auch Quatsch. Ein vernüftiges Programm wird einen 
Signalhandler für SIGINT und Konsorten implementieren und dann die 
Signale mit vernünftigem Beenden verarbeiten.

von Bobby (Gast)


Lesenswert?

Leute helft mir mal:

Das mit den Signals kenn ich bisher nur
von Linux. Gibt es das auch bei Windows ?

von t.danielzik (Gast)


Lesenswert?

Hallo moony,

du must die Zeile cin.get() auch innerhalb der do Schleife einfügen.

    do
    {
         cin.get();
         printf("Hallo");
    }
    while (abbruch != ESC);

dann sollte es gehen.

von moony (Gast)


Lesenswert?

Hi all!

Ich habe jetzt alle eure tipps mal ausprobiert aber es funktioniert 
immer noch nicht. :-/

Das programm beendet immer noch nicht, wenn man ESC drückt. Gibt es in 
VC++ nicht so etwas wie in Pascal...

repeat

<das und das>

until keypessed = ESC;

???

Danke an alle & Gruß

moony

von Uhu U. (uhu)


Lesenswert?

Ich hab nochmal etwas nachgedacht... Mit cin.get() oder cin.getc() kann 
es aus einem ganz einfachen Grund nicht gehen: Diese Funktionen warten, 
bis eine Eingabe anliegt, d.h. deine Schleife stoppt so lange, bis eine 
Eingabe kam.

Die Lösung: Du must in der Schleife feststellen, ob überhaupt ein 
Zeichen im Puffer steht. Erst wenn das der Fall ist, holst du es mit 
cin.getc() ab und wertest es aus.

Die Abfrage, ob ein Zeichen vorhanden ist, ist über den an cin istream 
streambuf möglich. An diesen streambuf kann man folgendermaßen kommen:

   streambuf *pCon = cin.rdbuf();

rdbuf ist eine Memberfunktion der Basisklasse ios.

Aus dem streambuf erhält man die Anzahl der unverarbeiteten Zeichen mit

   streamsize sSize = pCon->in_avail();

Wenn man nun die ganze Schose zusammensetzt, erhält man folgenden 
Ausdruck, um die Anzahl der in cin bereitstehenden Zeichen abzufragen:

   if (cin.rdbuf()->in_avl() > 0)
      <hole und verarbeite das Zeichen>

Eventuell könnte man es auch kürzer machen, aber ich mir nicht sicher, 
ob das funktioniert: Man ruft cin.peek(). Die sieht nur im Puffer nach, 
was das nächste Zeichen ist. Wenn cin.peek() auch dann zurückkehrt, wenn 
kein Zeichen anliegt, geht es damit, wenn sie wartet, hast du Pech 
gehabt... Wie sie sich verhält, wenn der Puffer leer ist, habe ich auf 
die Schnelle leider nicht gefunden.

von Karl H. (kbuchegg)


Lesenswert?

Uhu Uhuhu wrote:

> Die Abfrage, ob ein Zeichen vorhanden ist, ist über den an cin istream
> streambuf möglich. An diesen streambuf kann man folgendermaßen kommen:
>
>    streambuf *pCon = cin.rdbuf();
>
> rdbuf ist eine Memberfunktion der Basisklasse ios.
>
> Aus dem streambuf erhält man die Anzahl der unverarbeiteten Zeichen mit
>
>    streamsize sSize = pCon->in_avail();
>
> Wenn man nun die ganze Schose zusammensetzt, erhält man folgenden
> Ausdruck, um die Anzahl der in cin bereitstehenden Zeichen abzufragen:
>
>    if (cin.rdbuf()->in_avl() > 0)
>       <hole und verarbeite das Zeichen>

Das kann das Problem lösen, muss es aber nicht. Denn: Wie kommen
denn die Zeichen in den stream Buffer hinein? Niemand sagt, dass
bei einem Aufruf von rdbuf oder in_avail auch alle Zeichen, die
vom BS gepuffert wurden, auch übernommen werden.

In C++ gibt es grundsätzlich kein dezidiertes 'keyboard' und damit
auch keine Möglichkeit festzustellen ob eine Taste gedrückt wurde
oder nicht.

Alle 100% Lösungen zu diesem Thema sind immer Platformabhängig.


Oft gibt es eine Funktion namens kbhit(), die genau das macht:
Beim Betriebssystem nachfragen, ob ein Tastendruck vorliegt.

von moony (Gast)


Lesenswert?

Nachdem ich jetzt die ganze Schose in eine for(;;)-Schleife gemacht 
habe, und versucht habe die Zeichen mit cin.getc() abzuholen, zeigte er 
mir die Fehlermeldungen an:

error C2039: 'getc': Ist kein Element von 
'std::basic_istream<_Elem,_Traits>'

Was kann ich da jetzt tun? Habe ich irgentetwas falsch gemacht oder 
vergessen?

Gruß

moony

von Uhu U. (uhu)


Lesenswert?

Guck mal in die Doku - cin.getc hat einen Referenzparameter...

Die Parameter bei Funktionen in verbalen Beschreibungen wegzulassen, ist 
bequem und üblich, wird aber vom Compiler nicht toleriert.

von moony (Gast)


Lesenswert?

Ich habe jetzt mal in der Doku und auch auf 
msdn2.microsoft.com/en-us/library/ nachgesehen. Er findet nicht einmal 
cin.getc()!

Welchen Referenzparameter meinst du denn?

Auch wenn die Frage dumm ist, beantworte sie mir bitte trotzdem.
moony

von Uhu U. (uhu)


Lesenswert?

Da stehts: Beitrag "Re: Schleife mit ESC-abbruch geht das?"

Ansonsten: Googel einfach mal nach cin.getc - aber wenn es gelingt, die 
Anzahl der vorhandenen Zeichen abzufragen, kannst du evtl. auch get 
verwenden, wenn dein Compiler getc nicht kennt.

getc steht auf 
http://search.msdn.microsoft.com/search/Default.aspx?query=getc&brand=msdn&locale=en-us&refinement=00&lang=en-us
gelistet. Ich hatte einfach auf 
http://msdn2.microsoft.com/en-us/library/ nach getc - ohne Objekt und 
Klammern - gesucht.

von moony (Gast)


Lesenswert?

Ok. Jetzt klappt alles.
Vielen Dank an alle und Bis zum nächstem Problem.

Gruß

moony

von Uhu U. (uhu)


Lesenswert?

Ist dir eigentlich klar, warum der Compiler

error C2039: 'getc': Ist kein Element von
'std::basic_istream<_Elem,_Traits>'

schimpft, wenn du ihm cin.getc(); zu fressen gibst? Es gibt doch 
istream::getc...

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.