C-Programmierung: Sprachbeschreibung: Anweisungen

Anweisungen

Bearbeiten

Diese Darstellungen stützen sich auf die Sprache C gemäß ISO/IEC 9899:1999 (C99). Auf Dinge, die mit C99 neu eingeführt wurden, wird im Folgenden gesondert hingewiesen.

Anweisungen und Blöcke sind Thema des Kapitels 6.8 Statements and blocks in C99.

Benannte Anweisung

Bearbeiten

Benannte Anweisungen sind Thema des Kapitels 6.8.1 Labeled statements in C99.

Syntax:

Bezeichner : Anweisung
case konstanter Ausdruck : Anweisung
default : Anweisung

Sowohl die case-Anweisung, wie auch die default-Anweisung dürfen nur in einer switch-Anweisung verwendet werden.

Siehe auch: switch.

Der Bezeichner der benannten Anweisung kann in der gesamten Funktion angesprochen werden. Sein Gültigkeitsbereich ist die Funktion. Dies bedeutet, dass der Bezeichner in einer goto-Anweisung noch vor seiner Deklaration verwendet werden kann.

Siehe auch: goto, if

Zusammengesetzte Anweisung

Bearbeiten

Das Kapitel 6.8.2 Compound statement in C99 hat die zusammengesetzten Anweisungen zum Thema.

Syntax (C89):

{ declaration-listopt statement-listopt }

declaration-list:

Deklaration
declaration-list Deklaration

statement-list:

Anweisung
statement-list Anweisung

Syntax (C99):

{ block-item-listopt }

block-item-list:

block-item
block-item-list block-item

block-item:

Deklaration
Anweisung

Eine zusammengesetzte Anweisung bildet einen Block.

Zusammengesetzte Anweisungen dienen dazu, mehrere Anweisungen zu einer einzigen Anweisung zusammenzufassen. So verlangen viele Anweisungen eine Anweisung als Unteranweisung. Sollen jedoch mehrere Anweisungen als Unteranweisung angegeben werden, so steht oft nur der Weg zur Verfügung, diese Anweisungen als eine Anweisung zusammenzufassen.

Wesentliches Merkmal der Syntax zusammengesetzter Anweisungen sind die umschließenden geschweiften Klammern ({}). Bei Anweisungen, die Unteranweisungen erwarten, wie beispielsweise Schleifen oder Verzweigungen, werden geschweifte Klammern so häufig eingesetzt, dass leicht der falsche Eindruck entsteht, sie seien Teil der Syntax der Anweisung. Lediglich die Syntax einer Funktionsdefinition verlangt (in C99) die Verwendung einer zusammengesetzen Anweisung.

Beispiel:

#include <stdio.h>

int main(int argc, char *argv[])
{
        if (argc > 1)
                printf("Es wurden %d Parameter angegeben.\n", argc-1);
                printf("Der erste Parameter ist '%s'.\n", argv[1]);

        return 0;
}

Das eben gezeigte Beispiel lässt sich übersetzen, jedoch ist sein Verhalten nicht das Gewünschte. Der erste Parameter der Applikation soll nur ausgegeben werden, wenn er angegeben wurde. Jedoch wird nur die erste printf-Anweisung (eine Ausdrucksanweisung) bedingt ausgeführt. Die zweite printf-Anweisung wird stets ausgeführt, auch wenn die Formatierung des Quelltextes einen anderen Eindruck vermittelt. Repräsentiert der Ausdruck argv[1] keinen gültigen Zeiger, so führt seine Verwendung beim Aufruf der Funktion printf zu einem undefinierten Verhalten der Applikation.

Siehe auch: if

Es soll also auch der zweite Aufruf von printf nur dann erfolgen, wenn mindestens ein Parameter angegeben wurde. Dies kann erreicht werden, indem beide (Ausdrucks-)Anweisungen zu einer Anweisung zusammengesetzt werden. So arbeitet das folgende Beispiel wie gewünscht.

Beispiel:

#include <stdio.h>

int main(int argc, char *argv[])
{
        if (argc > 1)
        {
                printf("Es wurden %d Parameter angegeben.\n", argc-1);
                printf("Der erste Parameter ist '%s'.\n", argv[1]);
        }

        return 0;
}

In zusammengesetzten Anweisungen können neue Bezeichner deklariert werden. Diese Bezeichner gelten ab dem Zeitpunkt ihrer Deklaration und bis zum Ende des sie umschließenden Blocks. Die wesentliche Änderung von C89 zu C99 ist, dass in C89 alle Deklarationen vor allen Anweisungen stehen mussten. Im aktuellen Standard C99 ist dieser Zwang aufgehoben.

Ausdrucksanweisung

Bearbeiten

Ausdrucksanweisungen werden im Kapitel 6.8.3 Expression and null statements in C99 beschrieben.

Syntax:

Ausdruckopt ;

Der Ausdruck einer Ausdrucksanweisung wird als void-Ausdruck und wegen seiner Nebeneffekte ausgewertet. Alle Nebeneffekte des Ausdrucks sind zum Ende der Anweisung abgeschossen.

Beispiel:

#include <stdio.h>

int main(int argc, char *argv[])
{
        int a = 1, b = 2, c;             /* Deklarationen */

        c = a + b;                       /* Ausdrucksanweisung */
        printf("%d + %d = %d\n",a,b,c);  /* Ausdrucksanweisung */

        return 0;                        /* Sprung-Anweisung */
}

In der ersten Ausdrucksanweisung c = a + b; wird der Ausdruck c = a + b mit seinem Teilausdruck a + b ausgewertet. Als Nebeneffekt wird die Summe aus den Werten in a und b gebildet und in dem Objekt c gespeichert. Der Ausdruck der zweiten Ausdrucksanweisung ist der Aufruf der Funktion printf. Als Nebeneffekt gibt diese Funktion einen Text auf der Standardausgabe aus. Häufige Ausdrucksanweisungen sind Zuweisungen und Funktionsaufrufe.

Leere Anweisung

Bearbeiten

Wird der Ausdruck in der Ausdrucksanweisung weggelassen, so wird von einer leeren Anweisung gesprochen. Leere Anweisungen werden verwendet, wenn die Syntax der Sprache C eine Anweisung verlangt, jedoch keine gewünscht ist.

Beispiel:

void foo (char * sz)
{
	if (!sz) goto ende;

	/* ... */
	while(getchar() != '\n' && !feof(stdin))
		;

	/* ... */ 
	ende: ;
}

Verzweigungen

Bearbeiten

Die Auswahl-Anweisungen werden in C99 im Kapitel 6.8.4 Selection statements beschrieben.

Syntax:

if (Ausdruck) Anweisung
if (Ausdruck) Anweisung else Anweisung

In beiden Formen der if-Anweisung muss der Kontroll-Ausdruck von einem skalaren Datentypen sein. Bei beiden Formen wird die erste Unteranweisung nur dann ausgeführt, wenn der Wert des Ausdruckes ungleich 0 (null) ergibt. In der zweiten Form der if-Anweisung wird die Unteranweisung nach dem Schlüsselwort else nur dann ausgeführt, wenn der Kontrollausdruck den Wert 0 darstellt. Wird die erste Unteranweisung über einen Sprung zu einer benannten Anweisung erreicht, so wird die Unteranweisung im else-Zweig nicht ausgeführt. Das Schlüsselwort else wird stets jenem if zugeordnet, das vor der vorangegangenen Anweisung steht.

Beispiel:

 #include <stdio.h>

 int main(int argc, char *argv[])
 {
        if (argc > 1)
                printf("Erster Parameter: %s\n", argv[1]);

        return 0;
 }

Im vorangegangenen Beispiel prüft das Programm, ob mindestens ein Parameter dem Programm übergeben wurde und gibt ggf. diesen Parameter aus. Wurde jedoch kein Parameter dem Programm übergeben, so wird die Ausdrucksanweisung printf("Erstes Argument: %s\n", argv[1]); nicht ausgeführt.

Soll auch auf den Fall eingegangen werden, dass der Kontrollausdruck 0 ergeben hatte, so kann die zweite Form der if-Anweisung verwendet werden. Im folgenden Beispiel genau eine der beiden Unteranweisungen ausgeführt.

Beispiel:

#include <stdio.h>

int main(int argc, char *argv[])
{
        if(argc > 1)
                printf("Erster Parameter: %s\n", argv[1]);
        else
                puts("Es wurde kein Parameter übergeben.");

        return 0;
}

Die if-Anweisung stellt, wie der Name schon sagt, eine Anweisung dar. Daher kann eine if-Anweisung ebenso als Unteranweisung einer anderen Anweisung verwendet werden. Wird eine if-Anweisung als Unteranweisung einer anderen if-Anweisung verwendet, so ist darauf zu achten, dass sich ein eventuell vorhandenes else stets an das voranstehende if bindet.

Beispiel:

#include <stdio.h>

int main(int argc, char *argv[])
{
        if (argc > 1)
                if (argc == 2)
                        puts("Es wurde genau ein Parameter übergeben.");
        else
                puts("Es wurde kein Parameter übergeben.");

        return 0;
}

Die Formatierung des Quelltextes im letzten Beispiel erweckt den Eindruck, dass der Text Es wurde kein Argument übergeben. nur dann ausgegeben wird, wenn der Ausdruck argc > 1 den Wert 0 ergibt. Jedoch ist Ausgabe des Textes davon abhängig, ob der Ausdruck argc == 2 den Wert 0 ergibt. Somit wird beim Fehlen eines Parameters kein Text ausgegeben und im Fall von mehreren Parametern erhalten wir die Fehlinformation, dass keine Parameter übergeben worden seien.

Soll das gewünschte Verhalten erreicht werden, so kann die if-Anweisung, welche die erste Unteranweisung darstellt, durch eine zusammengesetzte Anweisung ersetzt werden. Noch einmal auf Deutsch: sie kann geklammert werden. So findet im folgenden Beispiel das Schlüsselwort else vor sich eine zusammengesetzte Anweisung und vor dieser Anweisung jenes if, welches mit dem Kontrollausdruck argc > 1 behaftet ist.

Beispiel:

#include <stdio.h>

int main(int argc, char *argv[])
{
        if (argc > 1)
        {
                if(argc == 2)
                        puts("Es wurde genau ein Parameter übergeben.");
        } else
                puts("Es wurde kein Parameter übergeben.");

        return 0;
}

Ebenso wird die zusammengesetzte Anweisung verwendet, wenn mehrere Anweisungen bedingt ausgeführt werden sollen. Da die if-Anweisung stets nur eine Anweisung als Unteranweisung erwartet, können zum bedingten Ausführen mehrerer Anweisungen, diese wiederum geklammert werden.

Im nächsten Beispiel findet das letzte else als erste Unteranweisung eine if-Anweisung mit einem else-Zweig vor. Diese (Unter-)Anweisung ist abgeschlossen und kann nicht mehr erweitert werden. Daher kann sich an eine solche if-Anweisung das letzte else nicht binden. Es gibt keine Form der If-Anweisung mit zwei Else-Zweigen. Somit arbeitet das folgende Programm auch ohne Klammern wie erwartet.

Beispiel:

#include <stdio.h>

int main(int argc, char *argv[])
{
        if (argc > 1)
                if (argc == 2)
                        puts("Es wurde genau ein Parameter übergeben.");
                else
                        puts("Es wurden mehr als ein Parameter übergeben.");
        else
                puts("Es wurde kein Argument übergeben.");

        return 0;
}

Im letzten Beispiel zum Thema der if-Anweisung soll noch gezeigt werden, wie sich ein Programm verhält, bei dem in eine Unteranweisung über einen Sprung aufgerufen wird.

Beispiel:

#include <stdio.h>

int main(void)
{
        goto marke;

        if (1==2)
                marke: puts("Ich werde ausgegeben.");
        else
                puts("Ich werde nicht ausgegeben!");

        return 0;
}

Obwohl der Ausdruck 1==2 offensichtlich den Wert 0 liefert, wird der else-Zweig nicht ausgeführt.

Die switch-Anweisung wird im Kapitel 6.8.4.2 The switch statement in C99 besprochen.

Syntax:

switch (Ausdruck) Anweisung

Die switch-Anweisung erlaubt eine Verzweigung mit mehreren Sprungzielen. Ihr Vorteil gegenüber der if-Anweisung ist eine bessere Übersicht über den Programmfluss.

Der Ausdruck muss einen ganzzahligen Datentyp haben. Er ist der Kontrollausdruck. Der ganzzahlige Datentyp des Kontrollausdrucks ist eine Einschränkung gegenüber der if-Anweisung, die in dem Bedingungs-Ausdruck einen skalaren Datentyp verlangt.

Siehe auch: if

Der Wert des Kontrollausdrucks bestimmt, zu welcher case-Anweisung einer zugehörigen Anweisung gesprungen wird. In fast allen Fällen ist die zugehörige Anweisung eine zusammengesetzte Anweisung ({}), welche die verschiedenen case-Anweisungen aufnimmt.

Beispiel:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
        int a=0, b=0;

        switch(argc)
                case 0: puts("Kein Programmname verfügbar.");

        switch(argc)
        {
                case 3: b = atoi (argv[2]);
                case 2: a = atoi (argv[1]);
                        printf("%d + %d = %d\n.", a, b, a+b);
        }

        return 0;
}

Im letzten Beispiel werden zwei switch-Anweisungen gezeigt. Die erste switch-Anweisung zeigt, dass geschweifte Klammern nach dem Standard C99 nicht zwangsläufig notwendig sind. Jedoch wird in einem solchen Fall wohl eher eine if-Anweisung verwendet werden. In der zweiten Ausgabe von Programmieren in C werden die geschweiften Klammern bei der switch-Anweisung noch verlangt.

Eine case-Anweisung bildet ein mögliches Sprungziel, bei dem die Programmausführung fortgesetzt wird. Die zweite switch-Anweisung im letzten Beispiel definiert zwei case-Anweisungen. Es werden zwei Sprungziele für den Fall definiert, dass argc den Wert 3 bzw. den Wert 2 hat. Der Ausdruck von case muss eine Konstante sein. Dabei darf der Wert des Ausdruck nicht doppelt vorkommen.

switch(var)
{
	case 2+3: ;
	case 1+4: ; /* illegal */
}

Hat ein case-Ausdruck einen anderen Typen als der Kontrollausdruck, so wird der Wert des case-Ausdruckes in den Typen des Kontrollausdruckes gewandelt.

Wird zu einem der beiden case-Anweisungen gesprungen, so werden auch alle nachfolgenden Anweisungen ausgeführt. Soll die Abarbeitung innerhalb der zugehörigen Anweisung abgebrochen werden, so kann die break-Anweisung eingesetzt werden. So verhindert die Anweisung break; im nachfolgenden Beispiel, dass beide Meldungen ausgegeben werden, wenn kein Parameter beim Programmaufruf angegeben worden sein sollte. Jedoch fehlt eine Anweisung break; zwischen case -1: und case 0:. Dies hat zur Folge, dass in beiden Fällen die Meldung Kein Parameter angegeben ausgegeben wird. Der Ausdruck argc - 1 nimmt den Wert -1 an, wenn auch kein Programmname verfügbar ist.

Beispiel:

#include <stdio.h>

int main (int argc, char *argv[])
{
        switch (argc - 1)
        {
                case -1: case 0: puts("Kein Parameter angegeben");
                        break;
                case 1: puts("Ein Parameter angegeben.");
        }
        return 0;
}

Siehe auch: break

Ergibt der Bedingungsausdruck einen Wert, zu dem es keinen entsprechenden Wert in einer Case-Anweisung gibt, so wird auch in keinen case-Zweig der zugehörigen Anweisung von switch gesprungen. Für diesen Fall kann eine Anweisung mit der Marke default: benannt werden. Bei der so benannten Anweisung wird die Programmausführung fortgesetzt, wenn kein case-Zweig als Sprungziel gewählt werden konnte. Es darf jeweils nur eine Marke default in einer switch-Anweisung angeben werden.

Um Bereiche abzudecken kann man auch "..." schreiben.
Hinweis: Die Bereichsabdeckung ist nicht standardkonform, es handelt sich hierbei um eine eigene Erweiterung eines Compilers (z.B. gcc).

#include <stdio.h>

int main()
{
   char puffer[256];
   printf("Geben Sie bitte Ihren Nachnamen ein.");
   fgets(puffer,256,stdin);
   switch(puffer[0])
   {
      case 'A'...'M':   /* nicht standardkonform! */
                        printf("Sie stehen in der ersten Haelfte des Telefonbuches.");
                        break;
      case 'N'...'Z':   /* nicht standardkonform! */
                        printf("Sie stehen in der zweiten Haelfte des Telefonbuches.");
                        break;
   }
   return 0;
}

Siehe auch: Benannte Anweisung

Schleifen

Bearbeiten

Schleifen (Iterations-Anweisungen) werden im Kapitel 6.8.5 Iteration statements in C99 beschrieben.

Die while-Anweisung ist Thema des Kapitels 6.8.5.1 The while statement in C99.

Syntax:

while (Ausdruck) Anweisung

Der Kontrollausdruck muss von einem skalaren Datentypen sein. Er wird vor einer eventuellen Ausführung der zugehörigen Anweisung (Schleifenrumpf) ausgewertet. Der Schleifenrumpf wird ausgeführt, wenn der Kontrollausdruck einen Wert ungleich 0 ergeben hatte. Nach jeder Ausführung des Schleifenrumpfs wird Kontrollausdruck erneut ausgewertet um zu prüfen, ob mit der Abarbeitung des Schleifenrumpfs fortgefahren werden soll. Erst wenn der Kontrollausdruck den Wert 0 ergibt, wird die Abarbeitung abgebrochen. Ergibt der Kontrollausdruck schon bei der ersten Auswertung den Wert 0, so wird der Schleifenrumpf überhaupt nicht ausgeführt. Die while-Anweisung ist eine kopfgesteuerte Schleife.

Sowohl die while-Anweisung, wie auch deren zugehörige Anweisung (Schleifenrumpf) bilden je einen Block.

Beispiel:

#include <stdio.h>

int main(int argc, char *argv[])
{
        while (argc > 0 && *++argv)
                puts(*argv);

        return 0;
}

Siehe auch: do, for, Block

Die do-Anweisung wird im Kapitel 6.8.5.2 The do statement in C99 beschrieben.

Syntax:

do Anweisung while (Ausdruck);

Im Unterschied zur while-Anweisung wertet die do-Anweisung den Kontrollausdruck erst nach der Ausführung einer zugehörigen Anweisung (Schleifenrumpf) aus. Die Ausführung des Schleifenrumpfs wird solange wiederholt, bis der Kontrollausdruck den Wert 0 ergibt. Dadurch, dass der Kontrollausdruck erst nach der Ausführung des Schleifenrumpfes ausgewertet wird, ist mindestens eine einmalige Ausführung des Schleifenrumpfes garantiert. Die do-Anweisung ist eine fußgesteuerte Schleife.

Sowohl die do-Anweisung, wie auch deren zugehörige Anweisung (Schleifenrumpf) bilden je einen Block.

Siehe auch: while, for, Block

Neben der klassischen Rolle einer fußgesteuerten Schleife bietet sich die do-Anweisung an, wenn ein Makro mit mehreren Anweisungen geschrieben werden soll. Dabei soll das Makro der Anforderung genügen, wie eine Anweisung, also wie im folgenden Codefragment verwendet werden zu können.

#include <stdio.h>
#define  makro(sz) do { puts(sz); exit(0); } while(0)

	/* ... */
	if (bedingung)
		makro("Die Bedingung trifft zu");  
	else
		puts("Die Bedingung trifft nicht zu");
	/* ... */

Bei der Definition des Makros fehlt das abschließende Semikolon, das in der Syntax der do-Anweisung verlangt wird. Dieses Semikolon wird bei der Verwendung des Makros (in der if-Anweisung) angegeben. Die do-Anweisung ist eine Anweisung und da der Kontrollausdruck bei der Auswertung den (konstanten) Wert 0 ergibt, wird der Schleifenrumpf (zusammengesetzte Anweisung) genau einmal ausgeführt. Zu diesem Thema äußert sich auch das Kapitel 6.3 der FAQ von dclc.

Die for-Anweisung ist Thema des Kapitels 6.8.5.3 The for statement in C99.

Syntax:

for (Ausdruck-1opt; Ausdruck-2opt; Ausdruck-3opt) Anweisung

Syntax (C99):

for (Ausdruck-1opt; Ausdruck-2opt; Ausdruck-3opt) Anweisung
for (Deklaration Ausdruck-2opt; Ausdruck-3opt) Anweisung

Die for-Anweisung (erste Form bei C99) verlangt bis zu drei Ausdrücke. Alle drei Ausdrücke sind optional. Werden die Ausdrücke Ausdruck-1 oder Ausdruck-3 angegeben, so werden sie als void-Ausdrücke ausgewertet. Ihre Werte haben also keine weitere Bedeutung. Der Wert von Ausdruck-2 stellt hingegen den Kontrollausdruck dar. Wird dieser ausgelassen, so wird ein konstanter Wert ungleich 0 angenommen. Dies stellt eine Endlosschleife dar, die nur durch eine Sprunganweisung verlassen werden kann.

Zu Beginn der for-Anweisung wird der Ausdruck-1 ausgewertet. Der Wert von Ausdruck-2 muss von einem skalaren Datentypen sein und sein Wert wird vor einer eventuellen Ausführung der zugehörigen Anweisung (Schleifenrumpf) ausgewertet. Nach einer Ausführung des Schleifenrumpfs wird der Ausdruck-3 ausgewertet. Wird der Schleifenrumpf nicht ausgeführt, so wird auch nicht der Ausdruck-3 ausgewertet.

Beispiel:

#include <stdio.h>

int main(int argc, char *argv[])
{
        int i;

        for (i = 0; i < 10; ++i)
                printf("In der for-Anweisung: i = %2d\n", i);

        printf("Nach der for-Anweisung: i = %d\n\n", i);

        i = 0;
        while ( i < 10)
        {
                printf("In der while-Anweisung: i = %2d\n", i);
                ++i;
        }

        printf("Nach der while-Anweisung: i = %d\n", i);

        return 0;
}

Das letzte Beispiel zeigt, wie eine for-Anweisung durch eine while-Anweisung ersetzt werden könnte. Es soll nicht unerwähnt bleiben, dass die beiden Formen nicht das Selbe darstellen. Zum Einen stellt die for-Anweisung eine Anweisung dar, während in dem Beispiel die while-Anweisung von einer Ausdrucksanweisung begleitet wurde. Würden wir beide Anweisungen zusammenfassen, so würden wir einen Block mehr definieren.

Sowohl die for-Anweisung, wie auch deren Schleifenrumpf bilden je einen Block.

Auch wenn alle drei Ausdrücke optional sind, so sind es die Semikola (;) nicht. Die Semikola müssen alle angegeben werden.

Mit C99 ist die Möglichkeit eingeführt worden, eine Deklaration angeben zu können. Dabei ersetzt die Deklaration den Ausdruck-1 und das erste Semikolon. Bei der Angabe der Definition wurde keineswegs die Angabe eines Semikolons zwischen der Deklaration und dem Ausdruck-2 vergessen. In dieser Form ist die Angabe der Deklaration nicht optional, sie muss also angegeben werden. Eine Deklaration wird immer mit einem Semikolon abgeschlossen. Wird diese Form der for-Anweisung verwendet, so ergibt sich das oben fehlende Semikolon durch die Angabe einer Deklaration.

Der Geltungsbereich der mit Deklaration deklarierten Bezeichner umfasst sowohl Ausdruck-2, Ausdruck-3 wie auch Anweisung, dem Schleifenrumpf. Der Bezeichner steht auch innerhalb von Deklaration zur Verfügung, soweit dies nach der Syntax von Deklarationen in C definiert ist.

Beispiel:

#include <stdio.h>

int main(int argc, char *argv[])
{
        for (int i = 0; i < 10; ++i)
        {
                int j = 0;
                printf("i = %2d, j = %d\n", i, j);
                ++j;
        }

        /* i und j sind hier nicht verfügbar */

        return 0;
}

Siehe auch: while, do, Block

Sprunganweisungen

Bearbeiten

Die Sprunganweisungen werden im Kapitel 6.8.6 Jump statements von C99 besprochen. Sie haben einen (bedingungslosen) Sprung zu einer anderen Stelle im Programm zur Folge.

Die goto-Anweisung ist Thema des Kapitels 6.8.6.1 The goto statement in C99.

Syntax:

goto Bezeichner ;

Mit der goto-Anweisung kann die Programmausführung bei einer benannten Anweisung fortgesetzt werden. Dabei muss die benannte Anweisung in der gleichen Funktion angegeben worden sein. Da der Name der Anweisung in der gesamten Funktion gültig ist, kann auch „nach vorne“ gesprungen werden.

Siehe auch: Benannte Anweisung

Bei einem Sprung in den Geltungsbereich eines Bezeichners darf dieser Bezeichner nicht ein Feld mit variabler Länge bezeichnen. Entsprechend der Regeln für einen Block werden die Objekte angelegt, diese dürfen jedoch nicht initialisiert worden sein, da die Deklaration übersprungen wurde.

Beispiel:

/* Vorsicht! undefiniertes Verhalten */
#include <stdio.h>

int main (void)
{
        goto weiter;
        {
                int i = 99;
                weiter:
                printf("i = %d\n", i); /* i ist nicht initialisiert! */
        }
        return 0;
}

In dem letzten Beispiel ist das Objekt i in der Funktion printf nicht initialisiert. Daher ist das Verhalten des Programms undefiniert.

Siehe auch: Block

Die Verwendung der goto-Anweisung hat gelegentlich einen, für den Menschen schwer lesbaren Programmcode zur Folge. Wie hoch die Lesbarkeit eines Quelltextes für einen Menschen als Qualitätsmerkmal für ein Programm bewertet wird, dass für einen Rechner geschrieben wurde, ist individuell verschieden. Dennoch soll nicht verschwiegen werden, dass die goto-Anweisung einen schlechten Ruf besitzt und viele Programmierer von ihrer Verwendung abraten. Dieser sollte jedoch nicht dazu führen, dass auf die goto-Anweisung verzichtet wird, obwohl ihre Verwendung eine einfachere Programmstruktur zur Folge gehabt hätte.

continue

Bearbeiten

Syntax:

continue ;

Die Anweisung continue; darf nur in den Schleifenanweisungen while, do und for verwendet werden. Sie wird im oder als Schleifenrumpf angegeben. Die continue-Anweisung bricht die Abarbeitung des Schleifenrumpfs ab und prüft die Bedingungsanweisung der Schleife erneut. So ist in den folgenden Quelltextfragmenten die continue-Anweisung mit der Anweisung goto weiter; austauschbar.

Hinweis: Die Sprungmarke weiter: ist für die Funktion der continue-Anweisung nicht erforderlich.

        for (int i = 0; i < 10; ++i)
        {
                /* ... */
                continue;
                /* ... */
                weiter: ;
        }
        int i = 0;
        while (i < 10)
        {
                /* ... */
                continue;
                /* ... */
                ++i;
                weiter: ;
        }
        int i = 0; 
        do
        {
                /* ... */
                continue;
                /* ... */
                ++i;
                weiter: ;
        } while (i < 10);

Das folgende Beispiel gibt eine Folge von Multiplikationen aus. Dabei wird jedoch die Multiplikation ausgelassen, bei der das Ergebnis eine 10 ergeben hat.

Beispiel:

#include <stdio.h>

int main (void)
{
        for(int i = 0; i < 10; ++i)
        {
                int erg = 2 * i;

                if(erg == 10) continue;

                printf("2 * %2d = %2d\n", i, erg);
        }

        return 0;
}

Siehe auch: break, Schleifen

Die break-Anweisung ist Thema der Kapitels 6.8.6.3 The break statement in C99.

Syntax:

break ;

Die Anweisung break; bricht die for, do, while oder switch-Anweisung ab, die der break-Anweisung am nächsten ist. Bei einer for-Anweisung wird nach einer break-Anweisung der Ausdruck-3 nicht mehr ausgewertet.

Beispiel:

#include <stdio.h>

int main (void)
{
        int i;
        for(i = 0; i < 10; ++i)
                if ( i == 5)
                        break;

        printf("i = %d\n", i);

        return 0;
}

Das Programm im letzten Beispiel gibt eine 5 auf der Standardausgabe aus.

Die Anweisung return; wird in dem Kapitel 6.8.6.4 The return statement in C99 beschrieben.

Syntax:

return Ausdruckopt ;

Die return-Anweisung beendet die Abarbeitung der aktuellen Funktion. Wenn eine return-Anweisung mit einem Ausdruck angegeben wird, dann wird der Wert des Ausdrucks an die aufrufende Funktion als Rückgabewert geliefert. In einer Funktion können beliebig viele return-Anweisungen angegeben werden. Jedoch muss dabei darauf geachtet werden, dass nachfolgender Programmcode durch den Programmfluss noch erreichbar bleibt.

Beispiel:

#include <stdio.h>
#include <string.h>

int IsFred(const char *sz)
{
        if (!sz)
                return 0;
        if (!strcmp(sz, "Fred Feuerstein"))
                return 1;
        return 0;
	puts("Dies wird nie ausgeführt.");
}

Der Ausdruck in der return-Anweisung ist optional. Dennoch gelten für ihn besondere Regeln. So darf der Ausdruck in Funktionen vom Typ void nicht angegeben werden. Ebenso darf der Ausdruck nur in Funktionen vom Typ void weggelassen werden.

Hat der Ausdruck der return-Anweisung einen anderen Typ als die Funktion, so wird der Wert des Ausdruckes in den Typ gewandelt, den die Funktion hat. Dies geschieht nach den gleichen Regeln, wie bei einer Zuweisung in ein Objekt vom gleichen Typen wie die Funktion.

Begriffserklärungen

Bearbeiten

Die Begriffe in diesem Abschnitt werden im Kapitel 6.8 Statements and blocks in C99 erklärt.

Anweisung

Bearbeiten

Eine Anweisung ist eine Aktion, die ausgeführt wird.

Eine Anweisung wird in einer Sequenz (sequence point) ausgeführt. Jedoch kann eine Anweisung in mehrere Sequenzen aufgeteilt sein.

Gelegentlich ist die Aussage zu lesen, dass in der Sprache C alle Anweisungen mit einem Semikolon abgeschlossen werden. Dies ist nicht richtig. Lediglich die Ausdrucksanweisung, die do-Anweisung und die Sprung-Anweisungen werden mit einem Semikolon abgeschlossen. So verwendet folgendes Programm kein Semikolon.

#include <stdio.h>

int main (void)
{
        if (printf("Hallo Welt\n")) {}
}

Ein Block ist eine Gruppe von möglichen Deklarationen und Anweisungen. Bei jedem Eintritt in einen Block werden die Objekte der Deklarationen neu gebildet. Davon sind lediglich Felder mit einer variablen Länge (neu in C99) ausgenommen. Initialisiert werden die Objekte mit der Speicherdauer automatic storage duration und Felder mit variabler Länge jeweils zu dem Zeitpunkt, wenn die Programmausführung zu der entsprechenden Deklaration kommt und innerhalb der Deklaration selbst nach den Regeln für Deklarationen der Sprache C. Die Deklaration wird dann wie eine Anweisung betrachtet. Die Speicherdauer der Objekte ist automatic storage duration, wenn nicht der Speicherklassenspezifizierer static angegeben wurde.

Nach 5.2.4.1 Translation limits aus C99 wird eine Verschachtelungstiefe bei Blöcken von mindestens 127 Ebenen garantiert.

Siehe auch:

Bearbeiten