Forum: PC-Programmierung C-Programm ohne goto


von Grübler (Gast)


Lesenswert?

Schönen guten Abend

Ich habe eine kleines C-Programm
1
for (Schleifenbedingung)
2
   {
3
    Befehl;
4
    Befehl;
5
    while (Bedingung)
6
       {
7
        Befehl;
8
        if (Abfrage) break; //verlasse beide Schleifen
9
        Befehl;
10
       }
11
   }

Wenn „Abfrage“ erfüllt ist, möchte ich nicht
nur die while-Schleife sondern auch sofort die
for-Schleife verlassen. Mit break wird ja jetzt
nur die while-Schleife verlassen.

Gibt es eine Lösung ohne goto ;-) ?

: Verschoben durch Admin
von Gerd (Gast)


Lesenswert?

die for schleife hat doch einen Wert z.B. i. Du kannst ja den Wert auf 
dein maximum setzen und bendest dann auch die for-schleife

von Gerd (Gast)


Lesenswert?

sorry blödsinn :) vergesse es

von Gerd (Gast)


Lesenswert?

1
ab=false;
2
for (Schleifenbedingung)
3
   {
4
    Befehl;
5
    Befehl;
6
    while (Bedingung)
7
       {
8
        Befehl;
9
        if (Abfrage) {
10
            ab = true;
11
            break;
12
        }
13
        if(ab) break;
14
        Befehl;
15
       }
16
   }

so sollte es gehen

von ich (Gast)


Lesenswert?

eher nicht...

von Gerd (Gast)


Lesenswert?

ich schrieb:
> eher nicht...

nicht?

von Gerd (Gast)


Lesenswert?

if(ab) break;
Befehl;

natürlich in die for-schleife nicht in die while!

von Oliver D. (unixconf)


Lesenswert?

for (Schleifenbedingung)
   {
    Befehl;
    Befehl;
    while (Bedingung)
       {
        Befehl;
        if (Abfrage) {
          Schleifenbedingung = FALSE;
          break; //verlasse beide Schleifen
        }
        Befehl;
       }
   }


;-)

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Grübler schrieb:
> Wenn „Abfrage“ erfüllt ist, möchte ich nicht nur die while-Schleife
> sondern auch sofort die for-Schleife verlassen.
Pack das Ganze in ein Unterprogramm und mach ein return aus dem 
break... ;-)

von Tim T. (tim_taylor) Benutzerseite


Lesenswert?

Wie wärs es in eine Unterfunktion zu packen?
1
void foo(void) {
2
 for (Schleifenbedingung) {
3
  Befehl;
4
  Befehl;
5
  while (Bedingung) {
6
   Befehl;
7
   if (Abfrage) return; //verlasse beide Schleifen
8
   Befehl;
9
  }
10
 }
11
 return;
12
}

Eventuell die Schleifenbedingung, Bedingung und Abfragewert als 
Parameter übergeben falls sie nicht global sind oder lokal gesetzt 
werden.

von kermit der frosch (Gast)


Lesenswert?

warum kein goto? einfache verschachtelte schleifen ohne goto sind in 80% 
der fälle wurstiger code mit redundanzen.

von Grübler (Gast)


Lesenswert?

Kermit schreibt:
>Warum kein goto?

Goto ist verpönt, da man damit
sehr unübersichtlichen Programmcode
erzeugen kann (Spagetti-Programmierung).
In JAVA gibt es z.B. gar kein goto mehr.

Ich werde aber hier doch ein goto nehmen,
und das Sprungziel direkt unter die Schleifen
setzten. Das scheint mir gut lesbar zu sein.

Danke an alle für die Tipps!

von H.Joachim S. (crazyhorse)


Lesenswert?

ich seh auch kein Problem mit goto. Ja, man kann viel Blödsinn damit 
anstellen. Das heisst aber nicht, dass man es auch macht, wenn man es 
benutzt.
Ja, man kann es immer vermeiden. Muss man aber nicht:-)

von Andreas F. (aferber)


Lesenswert?

Grübler schrieb:
> Goto ist verpönt, da man damit
> sehr unübersichtlichen Programmcode
> erzeugen kann (Spagetti-Programmierung).

Kreissägen führen bei unsachgemäßer Verwendung regelmäßig zu schweren 
Verletzungen, dennoch sind sie nicht "verpönt".

Du lieferst selbst das beste Beispiel, warum ein pauschales "goto ist 
böse" schwachsinnig ist.

> In JAVA gibt es z.B. gar kein goto mehr.

Da gibt es aber ein break mit Label, eben weil der Abbruch von 
verschachtelten Schleifen sonst unübersichtlich und fehleranfällig wird 
(Pascal lässt grüßen...).

Wenn man es drauf anlegt kann man damit genauso üblen Code produzieren 
wie mit goto in C. Eigentlich sogar noch übler, da das Label bei diesen 
Konstrukten dann nichtmal an der Stelle steht, wo wirklich hingesprungen 
wird. Es steht nur nicht das angeblich böse "goto" da.

Andreas

von Markus -. (mrmccrash)


Lesenswert?

Wäre es nicht einfacher, die Schleifenbedingung für das For zu erfüllen?

z.B.
1
int i;
2
bool abbruch = false;
3
4
for (i=0; (i<4)&&(!abbruch); i++)
5
{
6
  Befehl();
7
  Befehl();
8
  while (Bedingung)
9
  {
10
    Befehl();
11
    if(Bedingung)
12
    {
13
      abbruch = true;
14
      break;
15
    }
16
   }
17
}

_.-=: MFG :=-._

von Peter D. (peda)


Lesenswert?

Grübler schrieb:
> Gibt es eine Lösung ohne goto ;-) ?

Nein, es gibt keine Lösung, die gleich effektiv ist.

Die mit Return kostet etwas Stack, ist aber gleich gut leserlich, wie 
das Goto. Und dann kommen aber die Nörgler, die sagen, daß jede Funktion 
nur ein Return haben soll.

Die mit ner Variable macht den Code deutlich unleserlicher und kann 
sogar richtig teuer werden, wenn extra für diese zusätzliche Variable 
ein Stackframe angelegt werden muß.


Man sollte Goto nicht unnütz nehmen. Wenn es aber paßt, wie die Faust 
aufs Auge, dann nimmt man es einfach.

Irgendwelche Dogmen auszusprechen und sich sklavisch daran 
festzukrallen, halte ich für Schwachsinn. Der gesunde Menschenverstand 
sollte Vorrang haben.


Ein ähnliches Problem hat man auch bei Switch-Anweisungen in einer 
Schleife.
Sehr oft gibt es einen oder mehrere Case, die die Schleife verlassen. 
Durch die Doppelfunktion des Break ist das aber nicht möglich
Daher findet man Goto auch sehr oft in Switch-Anweisungen.
Sehr sinnvoll wäre daher ein extra Schlüsselwort zum Beenden eines Case 
gewesen.


Peter

von klaus (Gast)


Lesenswert?

> Gibt es eine Lösung ohne goto ;-)


1
void f()
2
{
3
for (Schleifenbedingung)
4
   {
5
    Befehl;
6
    Befehl;
7
    while (Bedingung)
8
       {
9
        Befehl;
10
        if (Abfrage) return; //verlasse beide Schleifen
11
        Befehl;
12
       }
13
   }
14
15
}

?

von benjamin tülpchen (Gast)


Lesenswert?

ich wette, dass 10k mal öfter gesagt wird goto ist scheiße, als 
verkackter code mit goto gelesen wird.

oder:

ich wette, dass 99% der leute, die sagen goto ist verpönt, noch nie 
verkackten goto-code gesehen haben.

von z.b. so (Gast)


Lesenswert?

1
#define gehezu goto
und schon ist das goto weg ;-)

wenn es passt und den code leserlicher gestaltet, verwende es.
weenn es dein code ist - mach was du willst, wenn dir dein arbeitgeber 
ein goto verbieten möchte/verbietet hast du zwei möglichkeiten:
- gut argumentieren und eine rebellion veranstalten
- akzeptieren und hässliche/schlecht lesbare/sonstige workarounds 
einbauen...

von U.R. Schmitt (Gast)


Lesenswert?

Peter Dannegger schrieb:
> Die mit Return kostet etwas Stack, ist aber gleich gut leserlich, wie
> das Goto. Und dann kommen aber die Nörgler, die sagen, daß jede Funktion
> nur ein Return haben soll.

Jepp, und die Nörgler haben oft recht. Wie toll ist es wenn Du am Ende 
einer Funktion einen Breakpoint setzen willst und musst dann 2 oder 3 
oder 7 setzen, weil entsprechend viele returns da sind.
Wie toll ist es wenn du am Ende der Funktion schnell einen Trace 
rausschreiben willst und kannst auch das dann 3 oder gar 7 mal machen.

Peter Dannegger schrieb:
> Die mit ner Variable macht den Code deutlich unleserlicher und kann
> sogar richtig teuer werden, wenn extra für diese zusätzliche Variable
> ein Stackframe angelegt werden muß.

Der Code von Markus war keinen Deut schlechter. In Sachen Effizienz gabe 
ich dir 100% recht, wobei das auf µCs manchmal eine Rolle spielt, auf 
PCs nur in absoluten Ausnahmefällen.

Peter Dannegger schrieb:
> Man sollte Goto nicht unnütz nehmen. Wenn es aber paßt, wie die Faust
> aufs Auge, dann nimmt man es einfach.
>
> Irgendwelche Dogmen auszusprechen und sich sklavisch daran
> festzukrallen, halte ich für Schwachsinn. Der gesunde Menschenverstand
> sollte Vorrang haben.

100% agree, deshalb habe ich oben auch nur oft gesagt :-)

benjamin tülpchen schrieb:
> ich wette, dass 99% der leute, die sagen goto ist verpönt, noch nie
> verkackten goto-code gesehen haben.

Ich habe mal ein paar Jahre Code warten müssen, der von einem 
selbstgeschriebenen Cross-Compiler (nicht von mir) aus IBM-Host 
Assembler C für Unixsysteme und Windows und OS/2 erzeugt hat. So grausam 
kann kein Mensch C Spagetticode programmieren, nicht mal einer der sonst 
nur Basic programmiert hat :-).

Gruß

von Klaus W. (mfgkw)


Lesenswert?

benjamin tülpchen schrieb:
> ich wette, dass 10k mal öfter gesagt wird goto ist scheiße, als
> verkackter code mit goto gelesen wird.

Wohl wahr.

Aber die Regel ist so leicht, daß jeder sie nachplappern kann.
Ähnlich wie "Makros sind verboten".

Denken statt Abklappern von Regel-Checklisten ist halt aufwendiger.
Das Ganze auf die Spitze getrieben heisst dann MISRA-C.

von skorpionx (Gast)


Lesenswert?

Ein "goto" ist wie Gift, genauso wie vieles gute in Medizin. Es gibt
Programme die dankt dem Befehl gut strukturiert und gut lesbar sind.
Z.B. am Anfang prüft man die Plausibilität von sehr vielen Angaben. Wenn 
etwas nicht passt dann lädt man Puffer für Anzeige eine Meldung und mit 
einem Sprung „goto Ergebnis“ verlässt man egal wie tief verschaltete 
Schleife. Im Ergebnis prüft man dann ob etwas zum Schlissen (geöffnete 
Files) oder zum Freigeben (Speicher).

von Nico22 (Gast)


Lesenswert?

U.R. Schmitt schrieb:
> Peter Dannegger schrieb:
>> Die mit Return kostet etwas Stack, ist aber gleich gut leserlich, wie
>> das Goto. Und dann kommen aber die Nörgler, die sagen, daß jede Funktion
>> nur ein Return haben soll.
>
> Jepp, und die Nörgler haben oft recht. Wie toll ist es wenn Du am Ende
> einer Funktion einen Breakpoint setzen willst und musst dann 2 oder 3
> oder 7 setzen, weil entsprechend viele returns da sind.
> Wie toll ist es wenn du am Ende der Funktion schnell einen Trace
> rausschreiben willst und kannst auch das dann 3 oder gar 7 mal machen.

Da lässt sich aber drüber streiten. Man kann eine Funktion auch ganz 
schön unübersichtlich machen, wenn man aus Krampf nur ein return haben 
möchte. Das gibt dann auch gerne Spaghetticode. Der Königsweg wäre 
natürlich, per goto zu einem Return zu springen ;-)

Nico

von Karl H. (kbuchegg)


Lesenswert?

Die Qunitessenz ist wie so oft:

Diese Daumenregeln sind grundsätzlich nicht schlecht. Sie geben einem 
Anfänger Richtlinien, wie er die gröbsten Source-Code Fehler vermeiden 
kann. Beachtet man sie, dann läuft man nicht so leicht in Gefahr den zu 
Recht gefürchteten 'Spaghetti-Code' zu produzieren.

Aber wie so oft sind derartige Regeln nicht als Dogma zu sehen, von dem 
man nicht im Einzelfall abweichen kann, solange man weiß was man tut und 
einen guten Grund dafür hat.

von Detlev T. (detlevt)


Lesenswert?

Also ich hasse generell Schleifen, die mittendrin verlassen werden. Das 
ist immer schwer zu verstehen. Das obige Beispiel würde ich selbst daher 
so schreiben:
1
for (Schleifenbedingung)
2
   {
3
    short running = 1;
4
5
    while(running)
6
      {
7
        Befehl;
8
        Befehl;
9
         while (Bedingung && running)
10
          {
11
            Befehl;
12
            if (running = !Abfrage))
13
             {
14
               Befehl;
15
             }
16
          }
17
   }

von U.R. Schmitt (Gast)


Lesenswert?

Nico22 schrieb:
> Da lässt sich aber drüber streiten. Man kann eine Funktion auch ganz
> schön unübersichtlich machen, wenn man aus Krampf nur ein return haben
> möchte. Das gibt dann auch gerne Spaghetticode.

Jepp, ganz klar, wie Peter gesagt hat:
> Irgendwelche Dogmen auszusprechen und sich sklavisch daran
> festzukrallen, halte ich für Schwachsinn. Der gesunde Menschenverstand
> sollte Vorrang haben.

> Königsweg wäre natürlich, per goto zu einem Return zu springen ;-)
***ROFL***

Das ist in java toll. Du klammerst das mit einem try finally und kannst 
dort dann alles sauber beenden, egal wie verschachtelt das Ganze ist.
Das ist nämlich das nächste Problem mit mehreren returns. Du hast eine 
komplexere Aktion, z.B: liest Du aus einer Datei/Dateien und/oder 
MQ-Queues Daten und speicherst Sie (abhängig von dem was Du gelesen 
hast, also komplexe Bedingungen und ggf. Schleifen) in eine Datenbank 
und oder andere Queues. Am Ende musst Du alles aufräumen und je nachdem 
ob es geklappt hat in MQ und Datenbank commit oder rollback absetzen. 
Dann noch mehrere Returns und deine Funktion/Methode wird nie richtig 
funktionieren.
Mit try finally problemlos in den Griiff zu kriegen.

Aber Java in µCs ist auch nicht meine Präferenz :-)

von Nico22 (Gast)


Lesenswert?

Oh ja, finally fehlt mir in C++.

von Rolf Magnus (Gast)


Lesenswert?

U.R. Schmitt schrieb:
>> Königsweg wäre natürlich, per goto zu einem Return zu springen ;-)
> ***ROFL***
>
> Das ist in java toll. Du klammerst das mit einem try finally und kannst
> dort dann alles sauber beenden, egal wie verschachtelt das Ganze ist.

Solange dich nicht interessiert, wo innerhalb des Blocks die Exception 
aufgetreten ist. Sonst mußt du halt um jede Funkton ein eigenes try 
setzen.

> Das ist nämlich das nächste Problem mit mehreren returns. Du hast eine
> komplexere Aktion, z.B: liest Du aus einer Datei/Dateien und/oder
> MQ-Queues Daten und speicherst Sie (abhängig von dem was Du gelesen
> hast, also komplexe Bedingungen und ggf. Schleifen) in eine Datenbank
> und oder andere Queues. Am Ende musst Du alles aufräumen und je nachdem
> ob es geklappt hat in MQ und Datenbank commit oder rollback absetzen.
> Dann noch mehrere Returns und deine Funktion/Methode wird nie richtig
> funktionieren.
> Mit try finally problemlos in den Griiff zu kriegen.

Mit goto auch.

> Oh ja, finally fehlt mir in C++.

Warum? Dank vernünfig funktionierender Destruktoren braucht man das doch 
gar nicht.

von Karl H. (kbuchegg)


Lesenswert?

Nico22 schrieb:
> Oh ja, finally fehlt mir in C++.


Brauchen wir auch nicht.
Wir haben einen Destruktor, der auch so funktioniert wie er soll.
RAII und du brauchst kein finally mehr

http://www.research.att.com/~bs/bs_faq2.html#finally

damit verlieren dann auch mehrere return in einer Funktion ihren 
"Schrecken".

von Klaus W. (mfgkw)


Lesenswert?

naja, manchmal wäre es schon nett.
Wenigstens das finally kann man Java als Vorteil zugestehen.

von qt (Gast)


Lesenswert?

Nur nicht-Informatiker können über so eine Lapallie so lange Diskutieren 
:D

von Klaus W. (mfgkw)


Lesenswert?

Du bist Informatiker? Denen sagt man Rechtschreibschwächen nach... :-)

von Karl H. (kbuchegg)


Lesenswert?

Klaus Wachtler schrieb:
> naja, manchmal wäre es schon nett.

z.B. ?

> Wenigstens das finally kann man Java als Vorteil zugestehen.

von Klaus W. (mfgkw)


Lesenswert?

z.B. schlichte Debugausgaben nach dem Motto "ich komme gerade hier 
vorbei und springe zurück..." oder halt alles, was mit Aufräumen zu tun 
hat.

Letzteres kann man natürlich immer in einem dtor verpacken, aber
das lohnt nicht in jedem Fall.

Also hat man dann doch manchmal in mehreren catch-Zweigen mehr
oder weniger Codewiederholung, die in einem finally-Block besser
aussehen würden.

Nachtrag: am ehesten vermisse ich es dann, wenn ich etwas machen
will, was nicht direkt mit der eigentlichen Programmlogik verwebt
ist, z.B. Laufzeitmessung eines Algos.

von U.R. Schmitt (Gast)


Lesenswert?

qt schrieb:
> Nur nicht-Informatiker können über so eine Lapallie so lange Diskutieren

Stimmt, Informatiker schreiben darüber eine Doktorarbeit :-P

von Rolf Magnus (Gast)


Lesenswert?

Klaus Wachtler schrieb:
> naja, manchmal wäre es schon nett.
> Wenigstens das finally kann man Java als Vorteil zugestehen.

Ich sehe es eher als Krücke, die man eingebaut hat, weil die 
Destruktoren fehlen.

von Stefanie B. (sbs)


Lesenswert?

Grübler schrieb:
1
for (Schleifenbedingung && Bedingung)
2
    {
3
     Befehl;
4
     Befehl;
5
     while (Bedingung)
6
        {
7
         Befehl;
8
         if (Abfrage) break; //verlasse beide Schleifen
9
         Befehl;
10
        }
11
    }

Variation nur in Zeile 1 mit && Bedingung

von Klaus W. (mfgkw)


Lesenswert?

@Rolf Magnus:
ok, daß der Grund für finally in Java ein übler ist, macht
den Mechanismus ja nicht per se schlecht.

von Nico22 (Gast)


Lesenswert?

Klaus Wachtler schrieb:
> ok, daß der Grund für finally in Java ein übler ist, macht
> den Mechanismus ja nicht per se schlecht.

Genau darum ging es mir. Wenn man nicht Lust hat, jedes 
C-init()-und-end() in eine eigene Klasse zu kapseln (was natürlich sehr 
elegant ist), dann vermisst man das finally manchmal schon. Es geht 
natürlich auch ohne.

Gruß,
Nico

von Karl H. (kbuchegg)


Lesenswert?

Klaus Wachtler schrieb:
> @Rolf Magnus:
> ok, daß der Grund für finally in Java ein übler ist, macht
> den Mechanismus ja nicht per se schlecht.

Ganz sicher nicht.

Aber wenn man erst mal auf RAII aufgesprungen ist und das konsequent 
macht, will man es nicht mehr missen. Und dann lösen sich 99% aller 
finally Probleme, genauso wie 99% aller Memory Leaks in Luft auf und man 
vermisst einen GC plötzlich überhaupt nicht mehr :-) Und eigentlich ist 
es ja der GC, im Zusammenspiel mit einem unbrauchbaren Destruktor, der 
einem Dinge wie finally aufzwingt.

von Nico22 (Gast)


Lesenswert?

Stimmt, einen GC vermisse ich auch überhaupt nicht. Ist aber immer 
schon, wenn einem valgrind zeigt, dass man doch lieber RAII hätte 
benutzen sollen, weil man irgendwo ein *_end() vergessen hat.

von U.R. Schmitt (Gast)


Lesenswert?

Rolf Magnus schrieb:
> Ich sehe es eher als Krücke, die man eingebaut hat, weil die
> Destruktoren fehlen.

Sorry aber das ist ziemlicher Blödsinn.
Mit finally kann man auch innerhalb einer Methode viel feiner granuliert 
Dinge 'zum lokalen' Schluß beenden.
Und komm mir nicht mit OO-Designtheorien daß dann das Design falsch ist 
und man einzelne Klassen mit jeweils einem Destruktor machen müsste.
Man kann den Spiess auch umdrehen und sagen, C++ hat die Destruktor 
Krücke weil ...
Ausserdem wollte ich hier keine "die Programmiersprache ist besser 
weil..." Diskussion lostreten.
Aber es fühlen sich manche immer wieder ans Bein gepinkelt, wenn man 
"Ihr" System, Sprache, Tool angeblich schlecht macht, nur weil man wagt 
darauf hinzuweisen, daß es bei einem anderen Tool, System, Sprache, ... 
andere Konzepte gibt.
Viel Spass

von Karl H. (kbuchegg)


Lesenswert?

U.R. Schmitt schrieb:

> Aber es fühlen sich manche immer wieder ans Bein gepinkelt, wenn man
> "Ihr" System, Sprache, Tool angeblich schlecht macht, nur weil man wagt
> darauf hinzuweisen, daß es bei einem anderen Tool, System, Sprache, ...
> andere Konzepte gibt.

Genau darum gehst letztenendes.
In C++ gibt es kein finally, weil man in C++ anders programmiert.

Das hat doch nichts mit 'ans Bein pinkeln zu tun'.
Das muss man den Leuten einfach nur vermitteln, die zb von Java zu C++ 
kommen. Manche Idiome funktionieren in C++ nun mal anders. Und ehe man 
nach Möglichkeiten einer 1:1 Übersetzung sucht, sollte man besser auf 
die in der Zielsprache üblichen und bewährten Idiome umschwenken. In C++ 
ist es nun mal der Destruktor, der Aufräumarbeiten erledigt. Das hat den 
Vorteil, dass man als Verwender einer Klasse nicht darauf vergessen kann 
die entsprechende Funktion aufzurufen und man sich daher auch nicht 
darauf konzentrieren muss.

Um einen deutschen Text ins englische zu übertragen, reicht es auch 
nicht aus einfach nur Grammatik und Vokabeln zu beherrschen.

von High Performer (Gast)


Lesenswert?

@Detlev T.:

ja, so ähnliche mache ich das auch. Wenn man gute Bezeichner wählt, ist 
es übersichtlich und logisch. Evtl. ein klein wenig ineffizienter als 
andere Lösungen, aber schön.


@Markus:

>for (i=0; (i<4)&&(!abbruch); i++)

Hmmm, gefällt mir nicht sooo gut. for-Schleifen verwende ich nur, wenn 
die Abbruchbedingung feststeht (z.B. Anzahl der Elemente eines Arrays 
etc.)
Sonst verwende ich lieber eine while- oder do-while-Schleife.

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.