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
intmain(){
2
for(..){
3
if(...)
4
unterprogramm1();
5
if(...)
6
unterprogramm2();
7
label:printf("...");
8
9
}
10
return0;
11
}
12
voidunterprogramm1(){
13
if(..)
14
gotolabel;
15
else..
16
}
17
18
voidunterprogramm2(){
19
if(..)
20
gotolabel;
21
else...
22
}
So habe ich mir das gedacht. Aber der scheint nicht zu funktionieren.
Ich bedanke mich für euere Hilfe.
Carolin
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.
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
"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.
> 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
intmain(){
4
for(..){
5
if(...)
6
unterprogramm1();
7
if(...)
8
unterprogramm2();
9
label:printf("...");
10
11
}
12
return0;
13
}
14
voidunterprogramm1(){
15
if(..){
16
if(...)
17
answer();
18
else
19
abbruch();
20
for(...)
21
.....
22
}
23
else..
24
abbruch();
25
}
26
27
voidunterprogramm2(){
28
if(..)
29
gotolabel;
30
else...
31
}
32
voidabbruch(){
33
if(..)
34
/*in diesem Programm soll zum label springen. Wenn ich return benutze dann wird for Schleife in Unterprogramm1 weiter laufen usw.
> 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.
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.
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
>voidabbruch(){
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
intabbruch()
2
{
3
if(...){
4
// es soll tatsächlich abgebrochen werden
5
...
6
return1;
7
}
8
9
// kein Abbruch notwendig, der Aufrufer kann weiterarbeiten
10
return0;
11
}
und der Aufrufer hält sich natürlich daran, was ihm die Funktion
abbruch() vorschreibt
1
intunterprogramm1(int...){
2
if(..){
3
if(...)
4
answer();
5
else
6
if(abbruch())
7
return0;
8
for(...)
9
.....
10
}
11
else..
12
if(abbruch())
13
return0;
14
15
return1;
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.
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.
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
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
intAbbruch(char**ppPtr)
2
{
3
if(....)
4
{
5
...
6
*ppPtr="Text";
7
return1;
8
}
9
10
*ppPtr="Alles OK";
11
return0;
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.
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...
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.
>Ü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
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