Forum: PC-Programmierung Sprung zu MAIN in C


von Carolin Z. (seobalis)


Lesenswert?

Hallo Leute,
ich habe ein Problem mit der direkte Sprung in C. Ich habe noch nicht 
viel Ahnung wie das am besten laufen soll. Oder mir fehlt es noch die 
Verständnis :(

#include<stdio.h>
1
int main(){
2
  for(..){
3
    if(...)
4
       unterprogramm1();
5
    if(...)
6
       unterprogramm2();
7
    label: printf("...");
8
9
  }
10
return 0;
11
}
12
void unterprogramm1(){
13
  if(..)
14
    goto label;
15
  else ..
16
}
17
18
void unterprogramm2(){
19
  if(..)
20
    goto label;
21
  else ...
22
}


So habe ich mir das gedacht. Aber der scheint nicht zu funktionieren.
Ich bedanke mich für euere Hilfe.

Carolin

von foo (Gast)


Lesenswert?

Goto gilt nur im selben Block wie das Label zu dem du springen
willst. Sprich { .... label: ... goto label} ist okay,
aber {.... label: .... } .... {... goto label...} geht nicht.

Aus nem andern Block geht mit setjmp und longjmp.

Goto und longjmp erst recht sollte man nur benutzen
wenn man wirklich "weiss was man tut". Es gibt Anwendungsfälle
wo es sinnvoll ist, zb gemeinsame Fehlersprungstellen. (der linux
Kern ist voll davon).

Ansonsten: Lass die Finger davon, macht das Programm sonst
absolut unleserlich/wartbar.

von Gast (Gast)


Lesenswert?

kommst aus der Basic Ecke?
Spaghetti-Code gibts nicht mehr. Labels auch nicht.
Anstatt "goto" schreibtst du einfach "return".
Das Programm wird dann an der Stelle weiterbearbeitet an der du in die 
unterfunktion gesprungen bist

von foo (Gast)


Lesenswert?

"kommst aus der Basic Ecke?
Spaghetti-Code gibts nicht mehr. Labels auch nicht."

Doch es gibt noch Spaghetti Code. Doch es gibt noch
Labels.

Ich wusste dass gleich wieder so einer kommt.
Ne technische Frage beantwortet man zuerst mit ner technischen
Antwort. Ratschläge kannst du danach anbringen und wenn
du ihn ernst meinst und dich nicht nur aufplustern willst,
dann auch in nem andern Ton.

von Carolin Z. (seobalis)


Lesenswert?

> Anstatt "goto" schreibtst du einfach "return".
> Das Programm wird dann an der Stelle weiterbearbeitet an der du in die
> unterfunktion gesprungen bist

Ja! Aber dieser Fall ist nicht so gut bei mir. z.B in diesem Fall
1
#include<stdio.h>
2
3
int main(){
4
  for(..){
5
    if(...)
6
       unterprogramm1();
7
    if(...)
8
       unterprogramm2();
9
    label: printf("...");
10
11
  }
12
return 0;
13
}
14
void unterprogramm1(){
15
  if(..){
16
     if(...)
17
        answer();
18
     else
19
        abbruch();
20
     for(...)
21
     .....
22
  }  
23
  else ..
24
    abbruch();
25
}
26
27
void unterprogramm2(){
28
  if(..)
29
    goto label;
30
  else ...
31
}
32
void abbruch(){
33
if(..)
34
/*in diesem Programm soll zum label springen. Wenn ich return benutze dann wird for Schleife in Unterprogramm1 weiter laufen usw.
35
36
*/ 
37
}

von Uhu U. (uhu)


Lesenswert?

Deine Unterprogramme sollten einen Returncode liefern, der in Main 
ausgewertet wird:

int main(){
  int retCode;
  for(..){
    if(...)
       retCode = unterprogramm1();
    if(...)
       retCode = unterprogramm2();
    switch (retCode) {
       case 0: printf("...");
             break;
       case 1:
             break;
  }
return 0;
}

void unterprogramm2(){
  if(..)
    return 0;
  else ...

  return 1;
}

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

> Deine Unterprogramme sollten einen Returncode liefern,
> der in Main ausgewertet wird:

Das passt nicht ganz zu

> void unterprogramm2(){

das sollte wohl besser

> int unterprogramm2(){

lauten.

von Carolin Z. (seobalis)


Lesenswert?

Rufus t. Firefly wrote:
>> Deine Unterprogramme sollten einen Returncode liefern,
>> der in Main ausgewertet wird:
>
> Das passt nicht ganz zu

Jap!

1
#include<stdio.h>
2
int main(){
3
  for(..){
4
    if(...)
5
       a = unterprogramm1(b);
6
    if(...)
7
       unterprogramm2();
8
    label: printf("...");
9
10
  }
11
return 0;
12
}
13
int unterprogramm1(int ...){
14
  if(..){
15
     if(...)
16
        answer();
17
     else
18
        abbruch();
19
     for(...)
20
     .....
21
  }  
22
  else ..
23
    abbruch();
24
  return ...;
25
/*
26
in diesem fall kann ich das nicht benutzen
27
*/
28
}
29
30
void unterprogramm2(){
31
  if(..)
32
  
33
  else ...
34
}
35
void abbruch(){
36
if(..)
37
/*in diesem Programm soll zum label springen. Wenn ich return benutze dann wird for Schleife in Unterprogramm1 weiter laufen usw.
38
39
*/ 
40
}

von Uhu U. (uhu)


Lesenswert?

Das switch-Statement in main kannst nicht einfach weglassen - na gut, es 
geht auch ein if -, das label schon.

Tipp: Versuche das Problem ohne abbruch() zu lösen - die Funktion stellt 
nur eine Sackgasse dar, die nicht zur Lösung führt.

Allein über den Wert, den unterprogramm1 zurückgibt, kannst du - mit 
Hilfe des switch - den weiteren Ablauf in main steuern.

von Karl H. (kbuchegg)


Lesenswert?

Du solltest dir wirklich überlegen, wie du dein Programm
mit strukturierten Mitteln programmieren kannst. Im Moment
bist du auf dem besten Weg zum, von foo und Gast angekündigtem
Spaghetti-Code. Inklusive aller Probleme.

>
1
> void abbruch(){
2
> if(..)
3
> /*in diesem Programm soll zum label springen. Wenn ich return
4
> benutze dann wird for Schleife in Unterprogramm1 weiter laufen usw.
5
> */ 
6
> }
7
>

Ja, und.
Dann lass doch einfach die Funktion abbruch() seinerseits wieder
einen Return-Code liefern, der den Aufrufer darüber aufklärt
ob jetzt abgebrochen werden soll oder nicht.
1
int abbruch()
2
{
3
  if( ... ) {
4
    // es soll tatsächlich abgebrochen werden
5
    ...
6
    return 1;
7
  }
8
9
  // kein Abbruch notwendig, der Aufrufer kann weiterarbeiten
10
  return 0;
11
}

und der Aufrufer hält sich natürlich daran, was ihm die Funktion
abbruch() vorschreibt
1
int unterprogramm1(int ...){
2
  if(..){
3
     if(...)
4
        answer();
5
     else
6
        if( abbruch() )
7
          return 0;
8
     for(...)
9
     .....
10
  }  
11
  else ..
12
    if( abbruch() )
13
      return 0;
14
15
  return 1;
16
}

Und natürlich basiert dann auch main() seine Entscheidung wie es
weiter geht darauf, welchen Wert unterprogramm1 zurückliefert.
Und so weiter und so weiter.

Was eine Funktion tun soll, kann mit den Argumenten einer
Funktion gesteuert werden. Den Rückgabewert einer Funktion
kann man aber wunderbar dazu benutzen, damit die Funktion dem
Aufrufer mitteilt, wie es weiter gehen soll.

Auch wenn mich foo jetzt gleich wieder schimpfen wird:
Vergiss goto, setjmp und longjmp!
Es gibt ein paar Ausnahmefälle in denen diese Dinge sinnvoll
sind. Aber als Anfänger wirst du die nächsten 2 Jahre mit
einiger Sicherheit nicht auf solche Fälle stossen. Und wenn
sie dann da sind, hast du genug Erfahrung, damit das dann nicht
in Spaghetti-Code ausartet.

von Carolin Z. (seobalis)


Lesenswert?

Kann ich vllt #ifndef oder #ifdef benutzen? Weil ich in der Funktion 
Abbruch einen Poiterwert zurückgeben muss :(

von Karl H. (kbuchegg)


Lesenswert?

Carolin Zapa wrote:
> Kann ich vllt #ifndef oder #ifdef benutzen? Weil ich in der Funktion
> Abbruch einen Poiterwert zurückgeben muss :(

Ganz ehrlich:
Bist du sicher, dass du nicht ein paar Grundlagenstunden zum
Thema 'Programmieren in C' ausgelassen hast?

#ifndef, #ifdef
haben mit dieser Problematik nichts, aber auch gar nichts zu tun.

von Carolin Z. (seobalis)


Lesenswert?

Karl heinz Buchegger wrote:
> Carolin Zapa wrote:
>> Kann ich vllt #ifndef oder #ifdef benutzen? Weil ich in der Funktion
>> Abbruch einen Poiterwert zurückgeben muss :(
>
> Ganz ehrlich:
> Bist du sicher, dass du nicht ein paar Grundlagenstunden zum
> Thema 'Programmieren in C' ausgelassen hast?
>

Deswegen bin ich doch Anfänger

> #ifndef, #ifdef
> haben mit dieser Problematik nichts, aber auch gar nichts zu tun.
Also wenn ich abbruch als eine programm definiert und mit z.B.
#define ABBRUCH

also dann kann ich doch in mein hauptprogramm mit
#ifndef ABBRUCH

....
#else

#endif
arbeiten

von Karl H. (kbuchegg)


Lesenswert?

Carolin Zapa wrote:
> Karl heinz Buchegger wrote:
>> Carolin Zapa wrote:
>>> Kann ich vllt #ifndef oder #ifdef benutzen? Weil ich in der Funktion
>>> Abbruch einen Poiterwert zurückgeben muss :(
>>
>> Ganz ehrlich:
>> Bist du sicher, dass du nicht ein paar Grundlagenstunden zum
>> Thema 'Programmieren in C' ausgelassen hast?
>>
>
> Deswegen bin ich doch Anfänger
>
>> #ifndef, #ifdef
>> haben mit dieser Problematik nichts, aber auch gar nichts zu tun.
> Also wenn ich abbruch als eine programm definiert und mit z.B.
> #define _ABBRUCH_
>
> also dann kann ich doch in mein hauptprogramm mit
> #ifndef _ABBRUCH_
>
> ....
> #else
>
> #endif
> arbeiten

Nein.
Noch mal. #ifdef und #indef haben nicht das Geringste mit
deinem Problem bzw. dessen Lösung zu tun. Diese 'Werkzeuge'
benötigt man für etwas völlig anderes.

Du kennst mitlerweile die Lösung. Die lautet: Argumente
gehen in eine Funktion hinein und werden unter anderem
dazu benutzt das Verhalten einer Funktion zu steuern.
Rückgabewerte einer Funktion werden dazu benutzt, dass
die Funktion ihrem Aufrufer mitteilen kann, wie es weiter
geht.
Der Rest sind ein paar if-else oder switch-case und du bist
dabei.

Das ist weder Raketentechnik noch besonders schwer.

> Weil ich in der Funktion
> Abbruch einen Poiterwert zurückgeben muss :(

Na dann gib doch einen Pointerwert zurück. Du kannst ja
vereinbaren, dass ein Rückgabewert von NULL als
'alles Abbrechen' gedeutet wird.
Falls das nicht geht, dann brauchst du 2 Returnwerte.
Da das aber in C nicht geht, musst du einen 'Rückgabewert'
über die Argumentschnittstelle zurückliefern. Ich würde
mal sagen, das wird wohl der Pointer werden (Generell
ist es in solchen Fällen meist besser, wenn der eigentliche
Returnwert für Fehler/Status-Rückgabe benutzt wird und der
Rest über die Argumentschnittstelle)

Am Beispiel eines char-Pointers, der von Abbruch geliefert
wird und zb irgendeinen Statustext angibt:
1
int Abbruch( char** ppPtr )
2
{
3
  if( .... )
4
  {
5
    ...
6
    *ppPtr = "Text";
7
    return 1;
8
  }
9
10
  *ppPtr = "Alles OK";
11
  return 0;
12
}

Aufruf:
1
  ...
2
  char* FehlerTxt;
3
4
  for( ....
5
    if( Abbruch( &FehlerTxt ) )
6
      // Abbruch hat gemeldet, dass abgebrochen werden soll
7
      // na dann machen wir das auch
8
      return;
9
10
    // Abbruch will nicht wirklich, dass abgebrochen wird
11
    // also machen wir das hier auch nicht, es geht weiter
12
    // in der Schleife. Aber Abbruch hat einen Text geliefert
13
    // den mal ausgeben.
14
    printf( "%s", FehlerTxt );
15
  }


Das, Funktionsargumente und Rückgabewerte, sind die Werkzeuge
mit denen man so ein Problem behandelt. Und damit kann man jede
wie auch immer geartete Situation deiner Problem-Machart in den
Griff kriegen. Argumente gehen nicht nur in eine Funktion hinein,
sondern eine Funktion kann auch Ergebnisse über die Argument-
schnittstelle zurückliefern.

von Minetti (Gast)


Lesenswert?

Das geht so nicht. Die #-Präprozessoranweisungen werden zur 
Kompiliertzeit ausgeführt, nicht zur Laufzeit des Programmes.

Übrigens... was macht der Compiler mit dem Stack, wenn man 
Unterfunktionen nicht mit return sondern mit goto verlässt? Würde mich 
wundern, wenn er so schlau ist und die Rücksprungadresse & Co wieder 
runternimmt...

von Karl H. (kbuchegg)


Lesenswert?

Minetti wrote:
> Das geht so nicht. Die #-Präprozessoranweisungen werden zur
> Kompiliertzeit ausgeführt, nicht zur Laufzeit des Programmes.
>
> Übrigens... was macht der Compiler mit dem Stack, wenn man
> Unterfunktionen nicht mit return sondern mit goto verlässt?

Probiers aus.
Du kommst mit goto nicht aus einer Funktion heraus.

> Würde mich
> wundern, wenn er so schlau ist und die Rücksprungadresse & Co wieder
> runternimmt...

setjmp, longjmp muessen genau das machen.

von Oops (Gast)


Lesenswert?

>Übrigens... was macht der Compiler mit dem Stack, wenn man
>Unterfunktionen nicht mit return sondern mit goto verlässt? Würde mich
>wundern, wenn er so schlau ist und die Rücksprungadresse & Co wieder
>runternimmt...

Das ist genau der Witz warum man nur innerhalb eines Blocks mit Goto 
springen darf. Dann ist der Stack nämlich immer intakt. Man kann also 
auch eine Funktion auch nicht mit goto verlassen, weil das auch hiesse 
den Block zu verlassen.

Für die anderen Fälle gibt es eben setjmp/longjmp. Die merken sich die 
Stacktiefe.


Gruss
Oops

von Oops (Gast)


Lesenswert?

Oops! Da hat sich schon wieder was überschnitte. ;-)

Gruss
Oops

von Oops (Gast)


Lesenswert?

Der tiefere Grund ist folgender:
goto und label sind in C definiert.
Da aber keine Maschinenabhängigkeit entstehen darf,
sind sie auf den Block beschränkt.

setjmp/longjmp sind hingegen Funktionen die der Hesteller mitliefert und 
die Implementierung bezüglich Stackaufbau usw. berücksichtigen müssen.

Gruss
Oops

von Carolin Z. (seobalis)


Lesenswert?

Danke für euere Hilfe. ich probiere das erstmal  mit dem Weg von  Karl 
heinz Buchegger (kbuchegg)

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.