vorheriges KapitelInhaltsverzeichnisStichwortverzeichnisFeedbacknächstes Kapitel


Tag C

Antworten

Tag 1: Einführung in Linux und die Programmiersprache C

Antworten zum Quiz

  1. C ist eine leistungsstarke, populäre und portierbare Sprache.
  2. Der Compiler prüft den Quellcode und übersetzt ihn, falls keine Fehler vorliegen, in Maschinenbefehle, die der Rechner verstehen kann. Sind Fehler aufgetreten, gibt der Compiler entsprechende Meldungen aus, die über die Art und den Ort der Fehler informieren.
  3. Bearbeiten, kompilieren und testen.
  4. gcc programm1.c -o meinprog
  5. Wenn Sie wollen, dass der Compiler alle Warnungen ausgibt und Debug- Informationen in das Programm aufnimmt, muss der Befehl folgendermaßen lauten:
    gcc -Wall -ggdb programm1.c -o meinprog
  6. C-Quelltextdateien sollten die Extension .c erhalten.
  7. Der Dateiname dateiname.txt ist kein gültiger Name für eine Quelltextdatei in C.
  8. Um die Probleme zu beheben, müssen Sie den Quellcode überarbeiten. Anschließend müssen Sie das Programm erneut kompilieren und austesten.
  9. Unter Maschinensprache versteht man die digitalen beziehungsweise binären Anweisungen, die vom Rechner verstanden werden. Da der Rechner mit C-Code nichts anfangen kann, muss der C-Code von einem C-Compiler in Maschinensprache übersetzt werden.
  10. Mit dem Debugger können Sie ein kompiliertes C-Programm Zeile für Zeile durchgehen. Auf diese Weise können Sie einerseits Programmfehler beheben und gleichzeitig ein besseres Verständnis für die Abläufe im Programm gewinnen.

Antworten zu den Übungen

  1. Der Editor kann unter Umständen ungewöhnliche Zeichen anzeigen. Dies hängt vom Verhalten Ihres Editors ab.
  2. Es berechnet die Fläche eines Kreises. Zuerst fordert es den Anwender auf, einen Radius anzugeben. Danach gibt es die errechnete Fläche auf dem Bildschirm aus.
  3. Dieses Programm gibt einen Block von 10 x 10 Zeichen des Buchstaben X aus. Ein ähnliches Programm finden Sie am Tag 5, »Grundlagen der Programmsteuerung«.
  4. Zeile 3. Sie werden wahrscheinlich eine ganze Reihe von Fehlermeldung erhalten, die wie folgt lauten:
    test.c:4: parse error before '{'
    test.c:6: parse error before string constant
    test.c:6: warning: data definition has no type or storage class
  5. Die erste der Fehlermeldungen gibt an, dass bereits vor der sich öffnenden geschweiften Klammer aus Zeile 4 ein Fehler aufgetreten ist. Da die Klammer das erste Zeichen in Zeile 4 ist, könnte sich das Problem auch am Ende der Zeile 3 befinden. Und um genau zu sein, wenn Sie das Semikolon am Ende von Zeile 3 entfernen, haben Sie den Fehler schon behoben.
  6. Hier liegt der Fehler woanders:
    /tmp/ccyNzE2u.o: In function 'main':
    /tmp/ccyNzE2u.o(.text+0x1f): undefined reference to 'tue_es'
    collect2: ld returned 1 exit status
  7. Wenn der Compiler versucht, eine ausführbare Datei zu erzeugen, kann er keine Definition für die Funktion tue_es() finden. Ändern Sie tue_es() in printf().
  8. Das Programm gibt jetzt einen Block von 10 x 10 Diamanten aus.

Tag 2: Die Komponenten eines C-Programms: Quellcode und Daten

Antworten zum Quiz

  1. Eine Gruppe von einer oder mehreren C-Anweisungen, die von geschweiften Klammern eingeschlossen ist, nennt man auch Block.
  2. Die einzige Komponente, die in allen C-Programmen vorhanden sein muss, ist die Funktion main().
  3. Jeder Text, der zwischen /* und */ steht, ist ein Programmkommentar und wird vom Compiler ignoriert. Kommentare werden verwendet, um Anmerkungen zu Struktur und Funktionsweise des Programms in den Quelltext aufzunehmen.
  4. Eine Funktion ist ein unabhängiger, mit einem Namen verbundener Abschnitt eines Programms, der eine bestimmte Aufgabe erledigt. Durch die Verwendung des Namens der Funktion kann ein Programm den Code dieser Funktion ausführen.
  5. Eine benutzerdefinierte Funktion wird vom Programmierer selbst erstellt, während Bibliotheksfunktionen zusammen mit dem Compiler oder dem Betriebssystem ausgeliefert werden.
  6. Eine #include-Direktive teilt dem Compiler mit, bei der Kompilierung den Code einer anderen Datei in Ihren Quellcode einzubinden.
  7. Kommentare sollten nicht verschachtelt werden. Bei einigen Compilern ist dies möglich, bei anderen jedoch nicht. Um die Portabilität Ihres Codes zu gewährleisten, sollten Sie Kommentare nicht verschachteln.
  8. Ja. Kommentare können beliebig lang sein. Ein Kommentar beginnt mit einem /* und endet erst, wenn ein */ auftaucht.
  9. Include-Dateien bezeichnet man auch als Header-Dateien.
  10. Eine Include-Datei ist eine separate Datei, die Informationen enthält, die der Compiler benötigt.

Antworten zu den Übungen

  1. Denken Sie daran, dass in einem C-Programm als Einziges die Funktion main() obligatorisch ist. Das folgende Codefragment ist das denkbar kürzeste Programm. Leider kann man damit jedoch nichts machen:
    int main(void)
    {
    return 0;
    }
  2. Man könnte dieses Programm auch wie folgt schreiben:
    int main(void) { return 0; }
  3. Betrachten Sie folgendes Programm:
    1 : /* Ueb02_02.c */
    2 : #include <stdio.h>
    3 :
    4 : void anzeigen_zeile(void);
    5 :
    6 : int main(void)
    7 : {
    8 : anzeigen_zeile();
    9 : printf("\n C in 21 Tagen!\n");
    10: anzeigen_zeile();
    11: printf("\n\n");
    12: return 0;
    13: }
    14:
    15: /* Zeile mit Sternchen ausgeben */
    16: void anzeigen_zeile(void)
    17: {
    18: int zaehler;
    19:
    20: for( zaehler = 0; zaehler < 34; zaehler++ )
    21: printf("*" );
    22: }
    23: /* Ende des Programms */
  4. a. Die Anweisungen stehen in den Zeilen 8, 9, 10, 11, 12, 20 und 21.
  5. b. Die einzige Variablendefinition steht in Zeile 18.
  6. c. Der einzige Funktionsprototyp steht in Zeile 4.
  7. d. Die Funktionsdefinitionen stehen in den Zeilen 16 bis 22.
  8. e. Kommentare stehen in den Zeilen 1, 15 und 23.
  9. Ein Kommentar ist jeglicher Text, der zwischen /* und */ steht. Sehen Sie im Folgenden einige Beispiele:
    /* Dies ist ein Kommentar. */
    /* ??? */
    /*
    Dies ist ein
    dritter Kommentar */
  10. Dies Programm gibt das Alphabet der Großbuchstaben aus. Sie werden das Programm besser verstehen, wenn Sie Tag 9, »Zeichen und Strings«, durchgearbeitet haben.
  11. Die Ausgabe lautet ABCDEFGHIJKLMNOPQRSTUVWXYZ.
  12. Dies Programm zählt die Anzahl der Zeichen und Leerzeichen, die Sie eingeben, und gibt die Anzahl aus. Auch dieses Programm werden Sie nach Tag 9 besser verstehen.

Tag 3: Anweisungen, Ausdrücke und Operatoren

Antworten zum Quiz

  1. Man nennt eine Anweisung dieser Art Zuweisung. Sie teilt dem Computer mit, die Werte 5 und 8 zu addieren und das Ergebnis der Variablen x zuzuweisen.
  2. Als Ausdruck bezeichnet man alles, was einen numerischen Wert zum Ergebnis hat.
  3. Die relative Rangfolge der Operatoren.
  4. Nach der ersten Anweisung ist der Wert von a gleich 10 und der Wert von x 11. Nach der zweiten Anweisung haben a und x beide den Wert 11. (Die Anweisungen müssen getrennt ausgeführt werden.)
  5. 1, denn dies ist der Rest von 10 geteilt durch 3.
  6. 19
  7. (5 + 3) * 8 / (2 + 2)
  8. 0
  9. Zur Bestimmung der Operatorenrangfolge können Sie die Tabelle im Abschnitt »Übersicht der Operator-Rangfolge« gegen Ende der dritten Lektion heranziehen. In der Tabelle sind die C-Operatoren und ihre Prioritäten angegeben.
  10. a. < hat eine höhere Priorität als ==.
  11. b. * hat eine höhere Priorität als +.
  12. c. != und == haben die gleiche Priorität, deshalb werden sie von links nach rechts ausgewertet.
  13. d. >= und > haben die gleiche Priorität. Verwenden Sie Klammern, wenn Sie mehr als einen Vergleichsoperator in einer Anweisung oder einem Ausdruck verwenden müssen.
  14. Zusammengesetzte Zuweisungsoperatoren ermöglichen Ihnen die Kombination von binären mathematischen Operationen mit Zuweisungen. Sie stellen eine verkürzte Schreibweise dar. Die am Tag 3 vorgestellten zusammengesetzten Operatoren lauten +=, -=, *=, /= und %=.

Antworten zu den Übungen

  1. Das Listing sollte sich problemlos ausführen lassen, auch wenn der Code schlecht strukturiert ist. Der Zweck dieses Listings ist, Ihnen zu zeigen, wie unwichtig Whitespace-Zeichen für die Ausführung des Programms und wie wichtig sie für die Lesbarkeit des Quellcodes sind.
  2. Im Folgenden sehen Sie das Listing aus Übung 1 in einer übersichtlicheren Form:
    #include <stdio.h>

    int x,y;

    int main(void)
    {
    printf("\nGeben Sie zwei Zahlen ein: ");
    scanf("%d %d",&x,&y);
    printf("\n\n%d ist größer\n",(x>y)?x:y);
    return 0;
    }
  3. Dieses Programm fordert Sie auf, zwei Zahlen einzugeben, und gibt dann die größere der beiden Zahlen aus.
  4. Die einzigen Änderungen, die in Listing 3.1 nötig sind, betreffen folgende Zeilen:
    17:      printf("\n%d     %d", a++, ++b);
    18: printf("\n%d %d", a++, ++b);
    19: printf("\n%d %d", a++, ++b);
    20: printf("\n%d %d", a++, ++b);
    21: printf("\n%d %d\n", a++, ++b);
  5. Das folgende Codefragment ist nur eine von vielen Lösungen. Es prüft, ob x größer gleich 1 und kleiner gleich 20 ist. Wenn diese beiden Bedingungen erfüllt sind, wird x der Variablen y zugewiesen. Andernfalls wird x nicht y zugewiesen, und y behält seinen Wert.
    if ((x >= 1) && (x <= 20))
    y = x;
  6. Der Code lautet:
    y = (x >= 1) && (x <= 20)) ? x : y;
  7. Auch hier gilt: Wenn die if-Anweisung WAHR ist, wird x der Variablen y zugewiesen, Andernfalls wird y sich selbst zugewiesen - d.h. der Wert ändert sich nicht.
  8. Der Code lautet:
    if (x < 1 && x > 10 )
    anweisung;
  9. a. 7
  10. b. 0
  11. c. 9
  12. d. 1
  13. e. 5
  14. a. WAHR
  15. b. FALSCH
  16. c. WAHR. Beachten Sie, dass hier nur ein einfaches Gleichheitszeichen steht, wodurch die if-Anweisung praktisch zu einer Zuweisung wird.
  17. d. WAHR
  18. Schreiben Sie eine if-Anweisung, die festlegt, ob eine Person rechtlich erwachsen ist (Alter 21) und noch nicht das Rentenalter (Alter 65) erreicht hat.
    if (alter < 18)
    printf("Sie sind noch nicht erwachsen");
    else if (alter >= 65)
    printf("Sie haben bereits das Rentenalter erreicht");
    else
    printf("Sie sind ein Erwachsener");
  19. Dieses Programm weist vier Fehler auf. Der erste befindet sich auf Zeile 3, die mit einem Semikolon und nicht mit einem Doppelpunkt abschließen sollte. Der zweite Fehler ist das Semikolon am Ende der if-Anweisung in Zeile 6. Der dritte Fehler wird sehr häufig gemacht: In der if-Anweisung wird der Zuweisungsoperator (=) statt des Vergleichsoperators (==) verwendet. Der letzte Fehler ist das Wort andernfalls in Zeile 8. Es sollte eigentlich else heißen. Der Code lautet korrekt:
    #include <stdio.h>
    int x= 1;
    int main(void)
    {
    if( x == 1)
    printf(" x ist gleich 1" );
    else
    printf(" x ist ungleich 1");
    return 0;
    }

Tag 4: Funktionen

Antworten zum Quiz

  1. Ja (zumindest sollte man es tun). Sie sollten die Techniken der strukturierten Programmierung einsetzen, wenn Sie ein guter C-Programmierer werden wollen.
  2. In der strukturierten Programmierung wird ein komplexes Programmierproblem in eine Reihe von kleineren Aufgaben zerlegt, die einzeln einfacher zu handhaben sind.
  3. Nachdem Sie Ihr Programm in eine Reihe von kleineren Aufgaben zerlegt haben, können Sie für jede Aufgabe eine eigene Funktion schreiben.
  4. Die erste Zeile einer Funktionsdefinition ist der Funktions-Header. Er enthält den Namen der Funktion, den Typ ihres Rückgabewertes und ihre Parameter.
  5. Eine Funktion kann entweder einen oder keinen Wert zurückliefern. Der Typ dieses Wertes kann jeder gültige C-Typ sein. Am Tag 14, »Zeiger für Fortgeschrittene«, zeige ich Ihnen, wie Sie von einer Funktion mehr als einen Wert zurückerhalten.
  6. 6. Eine Funktion, die keinen Wert zurückliefert, sollte mit dem Typ void deklariert werden.
  7. 7. Eine Funktionsdefinition ist eine komplette Funktion, einschließlich dem Header und den zugehörigen Anweisungen. Die Definition legt fest, welche Befehle ausgeführt werden, wenn die Funktion aufgerufen wird. Der Prototyp besteht aus einer Zeile, die identisch mit dem Funktions-Header ist, aber mit einem Semikolon abgeschlossen wird. Der Prototyp informiert den Compiler über den Funktionsnamen, den Typ des Rückgabewertes und die Parameterliste.
  8. 8. Lokale Variablen sind Variablen, die innerhalb einer Funktion deklariert sind.
  9. Lokale Variablen sind von anderen Variablen im Programm unabhängig.
  10. Die Funktion main() sollte die erste Funktion in Ihrem Listing sein.

Antworten zu den Übungen

  1. float tue_es(char a, char b, char c)
  2. Um aus diesem Header einen Funktionsprototyp zu machen, müssen Sie an das Ende der Zeile ein Semikolon setzen. Als Funktions-Header sollte diese Zeile von den in geschweiften Klammern stehenden Funktionsanweisungen gefolgt werden.
  3. void eine_zahl_ausgeben(int zahl)
  4. Dies ist eine void-Funktion. Wie in Übung 1 können Sie daraus einen Funktionsprototyp machen, indem Sie an das Ende der Zeile ein Semikolon setzen. Als Funktions-Header sollte diese Zeile von den in geschweiften Klammern stehenden Funktionsanweisungen gefolgt werden.
  5. a. int
  6. b. long
  7. Dieses Listing weist zwei Probleme auf. Zum einen wird die Funktion print_msg() als void deklariert, liefert aber einen Wert zurück. Sie sollten die return- Anweisung entfernen. Das zweite Problem befindet sich in Zeile 5. Bei dem Aufruf von print_msg() wird ein Parameter (ein String) übergeben. In dem Funktionsprototyp wurde aber angegeben, dass die Parameterliste der Funktion leer ist - weswegen ihr nichts übergeben werden sollte. Sehen Sie nachstehend das korrigierte Listing:
    #include <stdio.h>
    void print_msg( void );
    int main(void)
    {
    print_msg();
    return 0;
    }
    void print_msg( void )
    {
    puts( "Diese Nachricht soll ausgegeben werden." );
    }
  8. Am Ende des Funktions-Headers sollte kein Semikolon stehen.
  9. Es muss nur die Funktion groesser_von() geändert werden.
    int groesser_von( int a, int b)
    {
    int tmp;
    if (a > b)
    tmp = a;
    else
    tmp = b;
    return tmp;
    }
  10. Eine weitere, ebenfalls gültige Lösung wäre:
    int groesser_von( int a, int b)
    {
    return (a > b) ? a : b ;
    }
  11. Die folgende Funktion geht davon aus, dass die Zahlen Integer-Werte sind und die Funktion deshalb auch einen Integer zurückliefert.
    int produkt(int x, int y)
    {
    return (x * y);
    }
  12. Die Division durch Null erzeugt einen Fehler. Deshalb prüft die folgende Funktion, ob der zweite Wert Null ist, bevor die Division durchgeführt wird. Sie sollten nie voraussetzen, dass die übergebenen Werte korrekt sind.
    int teile(int a, int b)
    {
    if (b == 0)
    return 0;
    return (a / b);
    }
  13. 9. Statt main() wie im folgenden Beispiel könnte auch jede andere Funktion die Funktionen produkt() und teile() aufrufen.
    #include <stdio.h>

    int produkt(int x, int y);
    int teile(int a, int b);

    int main (void)
    {
    int zahl1 = 10,
    zahl2 = 5;
    int x, y, z;

    x = produkt(zahl1, zahl2);
    y = teile(zahl1, zahl2);
    z = teile(zahl1, 0);

    printf("zahl1 ist %d und zahl2 ist %d\n", zahl1, zahl2);
    printf("zahl1 * zahl2 gleich %d\n", x);
    printf("zahl1 / zahl2 gleich %d\n", y);
    printf("zahl1 / 0 gleich %d\n", z);

    return 0;
    }

    int produkt(int x, int y)
    {
    return (x * y);
    }

    int teile(int a, int b)
    {
    if (b == 0)
    return 0;
    return (a / b);
    }
  14. Eine Lösung könnte lauten:
    #include <stdio.h>

    float mittelwert (float a, float b, float c, float d, float e);

    int main (void)
    {
    float v, w, x, y, z, antwort;

    puts("Geben Sie 5 Zahlen ein:");
    scanf("%f%f%f%f%f", &v, &w, &x, &y, &z);

    antwort = mittelwert(v, w, x, y, z);

    printf("Der Mittelwert beträgt %f\n", antwort);

    return 0;
    }

    float mittelwert (float a, float b, float c, float d, float e)
    {
    return ((a+b+c+d+e)/5);
    }
  15. Die folgende Lösung verwendet Variablen vom Typ int. Sie funktioniert nur, wenn Werte kleiner oder gleich 19 eingegeben werden.
    #include <stdio.h>

    int drei_hoch(int exponent);

    int main (void)
    {
    int a = 4, b = 19;

    printf("3 hoch %d gleich %d\n", a, drei_hoch(a));
    printf("3 hoch %d gleich %d\n", b, drei_hoch(b));

    return 0;
    }

    int drei_hoch (int exponent)
    {
    if (exponent < 1)
    return 1;
    else
    return 3 * drei_hoch(exponent -1);
    }

Tag 5: Grundlagen der Programmsteuerung

Antworten zum Quiz

  1. In C ist der erste Indexwert eines Arrays immer 0.
  2. Die for-Anweisung enthält als Teil des Befehls Ausdrücke für die Initialisierung, Bedingung und Inkrementierung/Dekrementierung, während die while- Anweisung nur einen Bedingungsteil enthält.
  1. Ja. Eine while-Anweisung kann die gleichen Aufgaben erledigen wie eine for- Anweisung. Allerdings werden dann noch zwei weitere Schritte erforderlich. Sie müssen alle Variablen vor dem Start der Schleife initialisieren und das Inkrementieren beziehungsweise Dekrementieren innerhalb der while-Schleife vornehmen.
  2. Sie können Schleifen nicht überlappen. Eine verschachtelte Schleife muss komplett von einer äußeren Schleife umschlossen sein.
  3. Ja. Eine while-Anweisung kann in einer do...while-Anweisung untergebracht werden. Sie können jeden Befehl innerhalb eines Schleifenblocks verschachteln.
  4. Die vier Teile einer for-Anweisung lauten: Initialisierung, Bedingung, Inkrementierung und Anweisung(en).
  5. Die zwei Teile einer while-Anweisung lauten: Bedingung und Anweisung(en).
  6. Die zwei Teile einer do...while-Anweisung lauten: Bedingung und Anweisung(en).

Antworten zu den Übungen

  1. long array[50];
  2. Beachten Sie, dass das 50. Element in dem Array den Index 49 erhält. Dies liegt daran, dass Array-Indizes mit 0 beginnen.
    array[49] = 123,456;
  3. Wenn die Schleife beendet ist, enthält x den Wert 100.
  4. Wenn die Schleife beendet ist, enthält ctr den Wert 11. (cptr beginnt bei 2 und wird um 3 inkrementiert, solange sie kleiner als 10 ist.)
  5. Die innere Schleife gibt fünf X aus. Die äußere Schleife führt die innere Schleife 10-mal aus. Das bedeutet, dass insgesamt 50 X ausgegeben werden.
  6. Der Code lautet wie folgt:
    int x;
    for(x = 1; x <= 100; x +=3);
  7. Der Code lautet wie folgt:
    int x = 1;
    while(x <= 100)
    x += 3;
  8. Der Code lautet wie folgt:
    int x = 1;
    do
    {
    x += 3;
    }
    while(x <= 100)
  9. Dieses Programm endet nicht. Die Variable datensatz wird mit 0 initialisiert. Die while-Schleife überprüft dann, ob datensatz kleiner als 100 ist. 0 ist kleiner als 100, und deshalb wird die Schleife ausgeführt und gibt die zwei Meldungen aus. Anschließend wird die Bedingung erneut geprüft. 0 ist immer noch kleiner als 100, so dass die Schleife erneut ausgeführt wird. Damit dieser Code korrekt ausgeführt wird, muss datensatz innerhalb der Schleife wie folgt inkrementiert werden:
    datensatz = 0;
    while (datensatz < 100)
    {
    printf( "\nDatensatz %d ", datensatz );
    printf( "\nNächste Zahl..." );
    datensatz++;
    }
  10. Die Verwendung einer definierten Konstanten in Schleifen ist nichts Außergewöhnliches. Beispiele dafür finden Sie in den Wochen 2 und 3. Das Problem mit diesem Codefragment liegt woanders. Am Ende der for-Anweisung sollte kein Semikolon stehen. Dieser Fehler kommt sehr häufig vor.

Tag 6: Grundlagen der Ein- und Ausgabe

Antworten zum Quiz

  1. Es gibt zwei Unterschiede zwischen puts() und printf().
  2. printf() kann Variablenparameter ausgeben.
  3. puts() gibt immer ein Neue-Zeile-Zeichen nach dem String aus.
  4. Sie müssen bei Verwendung von printf() die Header-Datei stdio.h einbinden.
  5. a. \\ gibt einen Backslash aus
  6. b. \b gibt einen Backspace aus
  7. c. \n gibt einen Zeilenumbruch aus
  8. d. \t gibt einen Tabulator aus
  9. e. \a (für Alarm) gibt ein akustisches Signal aus
  10. a. %s für einen Zeichenstring
  11. b. %d für eine vorzeichenbehaftete Dezimalzahl
  12. c. %f für eine Fließkommazahl
  13. a. b gibt das Zeichen b aus
  14. b. \b gibt einen Backspace aus
  15. c. \ betrachtet das nächste Zeichen als Escape-Sequenz (siehe Tabelle 6.1)
  16. d. \\ gibt einen Backslash aus

Antworten zu den Übungen

  1. Die puts()-Anweisung gibt automatisch eine neue Zeile aus, printf() hingegen nicht.
    puts("");
    printf("\n");
  2. Der Code lautet:
    char c1, c2;
    unsigned int d1;
    scanf("%c %ud %c", c1, d1, c2);
  3. Ihre Lösung kann etwas anders aussehen.
    #include <stdio.h>

    int main(void)
    {
    int x;

    puts("Geben Sie einen Integer ein:");
    scanf("%d", &x);
    printf("Der eingegebene Wert lautete %d.\n", x);
    return 0;
    }
  4. Es kommt häufig vor, dass man Programme abändert, so dass sie nur besondere Werte akzeptieren. Die Lösung könnte folgendermaßen aussehen:
    #include <stdio.h>

    int main(void)
    {
    int x;

    puts("Geben Sie eine gerade Zahl ein:");
    scanf("%d", &x);
    while (x % 2 != 0)
    {
    printf("%d ist keine gerade Zahl.\nVersuchen Sie es erneut\n",x);
    scanf("%d", &x);
    }

    printf("Der eingegebene Wert lautete %d.\n", x);

    return 0;
    }
  5. Eine Lösung wäre:
    #include <stdio.h>

    int main(void)
    {
    int array[6], x, zahl;

    /* Durchlaufen Sie die Schleife 6-mal oder
    bis der letzte Wert 99 beträgt. */
    for(x = 0; x < 6 && zahl != 99; x++)
    {
    puts("Geben Sie eine gerade Zahl ein oder 99 zum Verlassen:");
    scanf("%d", &zahl);
    while (zahl % 2 == 1 && zahl != 99)
    {
    printf("%d ist keine gerade Zahl.\nVersuchen Sie es erneut\n",x);
    scanf("%d", &zahl);
    }
    array[x] = zahl;
    }

    /* Geben Sie sie jetzt aus. */
    for(x = 0; x < 6 && zahl != 99; x++)
    printf("Der eingegebene Wert lautete %d.\n", array [x]);

    return 0;
    }
  6. Die vorherigen Antworten sind bereits ausführbare Programme. Die einzige notwendige Änderung betrifft printf(). Um jeden Wert durch einen Tabulator getrennt auszugeben, muss die endgültige printf()-Anweisung wie folgt lauten:
    printf ("%d\t", array [x]);
  7. Sie können Anführungszeichen nicht innerhalb von Anführungszeichen setzen. Um Anführungszeichen ineinander zu verschachteln, müssen Sie Escape- Sequenzen verwenden:
    printf( "Jack sagte, \"Fischers Fritze fischt frische Fische.\"");
  8. Dieses Programm enthält drei Fehler. Der erste Fehler besteht in den fehlenden Anführungszeichen in der printf()-Anweisung, der zweite Fehler in dem fehlenden Adressoperator in dem Aufruf von scanf(). Der letzte Fehler liegt ebenfalls in der scanf()-Anweisung. Die Variable antwort ist vom Typ int, und der korrekte Konversionsspezifizierer für Integer-Werte lautet %d und nicht %f. Folgendes wäre korrekt:
    int hole_1_oder_2( void )
    {
    int antwort = 0;
    while (antwort < 1 || antwort > 2)
    {
    printf("1 für Ja, 2 für Nein eingeben");
    scanf( "%d", &antwort );
    }
    return antwort;
    }
  9. Sehen Sie hier die vollständige bericht_anzeigen()-Funktion.
    void bericht_anzeigen( void )
    {
    printf( "\nMUSTERBERICHT" );
    printf( "\n\nSequenz\Bedeutung" );
    printf( "\n=========\t=======" );
    printf( "\n\\a\t\tGlocke (Akustisches Signal)" );
    printf( "\n\\b\t\tBackspace" );
    printf( "\n\\n\t\tNeue Zeile" );
    printf( "\n\\t\t\tHorizontaler Tabulator" );
    printf( "\n\\\\\t\tBackslash" );
    printf( "\n\\\?\t\tFragezeichen" );
    printf( "\n\\\'\t\tEinfache Anführungszeichen" );
    printf( "\n\\\"\t\tDoppelte Anführungszeichen" );
    printf( "\n...\t\t...");
    }
  10. Eine Lösung wäre:
    /* Liest zwei Fliesskommazahlen ein und  */
    /* gibt ihr Produkt aus. */
    #include <stdio.h>

    int main(void)
    {
    float x, y;

    puts("Geben Sie zwei Werte ein: ");
    scanf("%f %f", &x, &y);
    printf("Das Produkt von %f und %f ist %f.\n", x, y, x*y);
    return 0;
    }
  11. Das folgende Programm liest zehn Integerwerte von der Tastatur ein und gibt ihre Summe aus:
    #include <stdio.h>

    int main(void)
    {
    int count, temp, gesamt = 0;

    for(count = 1; count <= 10; count++)
    {
    printf("Geben Sie den %d-ten Integer-Wert ein: ", count);
    scanf("%d", &temp);
    gesamt += temp;
    }

    printf("Die Gesamtsumme beträgt %d.\n", gesamt);

    return 0;
    }
  12. Eine Lösung wäre:
    #include <stdio.h>

    #define MAX 100

    int main(void)
    {
    int array [MAX];
    int count = -1, maximum, minimum, eingegeben, temp;

    puts("Geben Sie einen Integer pro Zeile ein.");
    puts("Geben Sie 0 ein, wenn Sie fertig sind.");

    do
    {
    scanf("%d", &temp);
    array[++count] = temp;
    } while (count < (MAX-1) && temp != 0);

    eingegeben = count;

    /* Suchen Sie den größten und kleinsten Wert. */
    /* Am Anfang ist der erste Wert sowohl */
    /* Maximum als auch Minimum . */
    maximum = minimum = array [0];

    for(count = 1; count < eingegeben; count++)
    {
    if (array[count] > maximum)
    maximum = array[count];
    if (array[count] < minimum)
    minimum = array[count];

    }

    printf("Der größte Wert ist %d.\n", maximum);
    printf("Der kleinste Wert ist %d.\n", minimum);

    return 0;
    }

Tag 7: Numerische Arrays

Antworten zum Quiz

  1. Alle, aber Arrays können nur Elemente eines Typs enthalten.
  2. 0. Unabhängig von der Größe eines Arrays beginnen in C alle Arrays mit dem Index 0.
  3. n-1.
  4. Das Programm lässt sich zwar kompilieren, kann aber zu Programmabstürzen oder unvorhersehbaren Ergebnissen führen.
  5. Setzen Sie in der Deklarationsanweisung hinter dem Array-Namen für jede Dimension ein Paar eckige Klammern. Jeder Satz eckiger Klammern enthält die Zahl der Elemente in der entsprechenden Dimension.
  6. 240. Diesen Wert erhalten Sie durch die Multiplikation von 2*3*5*8.
  7. array [0][0][1][1]

Antworten zu den Übungen

  1. Der Code lautet:
    int eins[1000], zwei[1000], drei[1000];
  2. Der Code lautet:
    int array [10] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
  3. Das Problem lässt sich auf mehrere Arten lösen. Die erste besteht darin, das Array bei seiner Deklaration zu initialisieren:
    int achtundachtzig[88] = { 88, 88, 88, 88, 88, 88, 88, 
    88, 88, ...... , 88 };
  4. Dieser Ansatz erfordert jedoch die Eingabe von achtundachtzigmal »88« in den geschweiften Klammern. Diese Methode eignet sich nicht besonders gut für große Arrays. Die Folgende ist da schon viel besser:
    int achtundachtzig[88];
    int x;

    for(x = 0; x < 88 x++)
    achtundachtzig[x] = 88;
  5. Der Code lautet:
    int stuff [12][10];
    int sub1, sub2;

    for(sub1 = 0; sub1 < 12; sub1++)
    for(sub2 = 0; sub2 < 10 ; sub2++)
    stuff [sub1][sub2] = 0;
  1. Der zweite Weg (der empfehlenswertere) besteht darin, die Werte in den for- Schleifen zu tauschen:
    int x, y;
    int array[10][3];
    int main(void)
    {
    for ( x = 0; x < 10; x++ ) /* geändert! */
    for ( y = 0; y < 3; y++ ) /* geändert! */
    array[x][y] = 0;
    return 0;
    }
  2. Dieser Fehler sollte leicht zu finden sein. Das Programm initialisiert ein Element in dem Array, das außerhalb des Gültigkeitsbereichs liegt. Wenn Sie ein Array mit zehn Elementen haben, gehen die Indizes der Elemente von 0 bis 9. Das Programm initialisiert das Array mit Indizes von 1 bis 10. Sie können aber das Element array[10] nicht initialisieren, da es nicht existiert. Die for-Anweisung sollte wie folgt geändert werden (zwei Möglichkeiten):
    for ( x = 1; x <= 9; x++ )  /* initialisiert 9 der 10 Elemente */
    for ( x = 0; x < 10; x++ )
  3. Beachten Sie, dass x <= 9 gleichbedeutend ist mit x < 10. Beides ist möglich, obwohl meist x < 10 verwendet wird.
  4. Sehen Sie im Folgenden eine von vielen möglichen Antworten:
    #include <stdio.h>
    #include <stdlib.h>

    int main(void)
    {
    int array[5][4];
    int a, b;

    for(a = 0 ; a < 5; a++)
    for(b = 0; b < 4; b++)
    array[a][b] = rand();

    /* Gibt die Array-Elemente aus. */
    for(a = 0 ; a < 5; a++)
    {
    for(b = 0; b < 4; b++)
    printf("%12d\t", array [a][b]);

    printf("\n"); /* Springt in eine neue Zeile */
    }

    return 0;
    }
  5. Der Code lautet:
    #include <stdio.h>
    #include <stdlib.h>

    int main(void)
    {
    short zufall[1000];
    int a;
    int total = 0;

    for(a = 0 ; a < 1000; a++)
    {
    zufall[a] = rand();
    total += zufall[a];
    }

    printf("Durchschnitt ist %d\n", total / 1000);

    /* Elemente in !0-Einheiten anzeigen. */
    for(a = 0 ; a < 1000; a++)
    {
    printf("Zufallszahl [%4d] = %d\n", a, zufall[a]);

    if (a % 10 == 0 && a > 0)
    {
    printf("Weiter mit Eingabetaste, Verlassen mit STRG-C.\n");
    getchar();
    }
    }

    return 0;
    }
  6. Sehen Sie nachstehend zwei Lösungsvorschläge:
  7. Lösung 1
    #include <stdio.h>

    int main(void)
    {
    int elemente[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
    int idx;

    for(idx = 0 ; idx < 10; idx++)
    printf("elemente[%d] = %d\n", idx, elemente[idx]);

    return 0;
    }
  8. Lösung 2
    #include <stdio.h>

    int main(void)
    {
    int elemente[10];
    int idx;

    for(idx = 0 ; idx < 10; idx++)
    elemente[idx] = idx;

    for(idx = 0 ; idx < 10; idx++)
    printf("elemente[%d] = %d\n", idx, elemente[idx]);

    return 0;
    }
  9. Der Code lautet:
    #include <stdio.h>

    int main(void)
    {
    int elemente[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
    int neues_array [10];
    int idx;

    for(idx = 0 ; idx < 10; idx++)
    neues_array[idx] = elemente[idx] + 10;

    for(idx = 0 ; idx < 10; idx++)
    printf("elemente[%d] = %d\nneues_array[%d] = %d\n",
    idx, elemente[idx], idx, neues_array [idx]);

    return 0;
    }

Tag 8: Zeiger

Antworten zum Quiz

  1. Der Adressoperator ist das kaufmännische Und (&).
  2. Es wird der Indirektionsoperator * verwendet. Wenn Sie dem Namen des Zeiger ein * voranstellen, beziehen Sie sich auf den Wert, auf den gezeigt wird.
  3. Ein Zeiger ist eine Variable, die die Adresse einer anderen Variablen enthält.
  4. Als Indirektion bezeichnet man den Zugriff auf den Inhalt einer Variablen mit Hilfe eines Zeigers auf diese Variable.
  5. Sie werden hintereinander im Speicher abgelegt, wobei die ersten Array-Elemente die niedrigeren Adressen erhalten.
  6. &daten[0] und daten.
  7. Eine Möglichkeit besteht darin, der Funktion die Länge des Arrays als eigenen Parameter zu übergeben. Die andere Möglichkeit besteht darin, einen zusätzlichen Wert in das Array mit aufzunehmen, beispielsweise Null, und damit das Ende des Arrays zu kennzeichnen.
  8. 8. Zuweisung, Indirektion, Adresse von, Inkrementierung, Dekrementierung und Vergleich.
  9. Die Subtraktion zweier Zeiger liefert die Anzahl der dazwischen liegenden Elemente. In diesem Fall ist die Antwort 1. Die Größe der Elemente im Array hat keine Bedeutung.
  10. Die Antwort ist immer noch 1.
  11. Die Übergabe als Wert bedeutet, dass die aufgerufene Funktion eine Kopie der Argumentvariablen erhält. Die Übergabe als Referenz bedeutet, dass die Funktion die Adresse der Argumentvariablen erhält. Der Unterschied liegt darin, dass bei der Übergabe als Referenz die Funktion die Möglichkeit hat, den Originalwert zu ändern, was bei der Übergabe als Wert nicht möglich ist.
  12. 12. Ein Zeiger vom Typ void kann auf C-Datenobjekte beliebiger Typen zeigen. Mit anderen Worten, es handelt sich um einen allgemeinen, einen generischen Zeiger.
  13. Durch die Verwendung eines void-Zeigers können Sie einen generischen Zeiger erzeugen, der auf ein beliebiges Datenobjekt zeigt. Am häufigsten werden void- Zeiger eingesetzt, um Funktionsparameter zu deklarieren, die Argumente verschiedener Typen akzeptieren.
  14. 14. Eine Typumwandlung liefert Informationen über den Typ des Datenobjekts, auf den der void-Zeiger zur Zeit zeigt. Sie müssen einen void-Zeiger umwandeln, bevor Sie ihn dereferenzieren können.

Antworten zu den Übungen

  1. char *char_zgr;
  2. Folgender Code deklariert einen Zeiger auf einen int und weist ihm dann die Adresse von kosten (&kosten) zu:
    int *z_kosten;
    p_cost = &cost;
  3. Direkter Zugriff: kosten = 100;
  4. Indirekter Zugriff: *z_kosten = 100;
  5. printf("Zeigerwert : %p, zeigt auf Wert : %d\n",
    z_kosten, *z_kosten);
  6. float *variable = &radius;
  7. Der Code lautet:
    daten[2] = 100;
    *(daten+2) = 100;
  8. Der folgende Code enthält auch die Antwort auf Übung 8:
    #include <stdio.h>

    #define MAX1 5
    #define MAX2 8

    int array1[MAX1] = { 1, 2, 3, 4, 5 };
    int array2[MAX2] = { 1, 2, 3, 4, 5, 6, 7, 8 };
    int total;

    int sumarrays(int x1[], int laen_x1, int x2[], int laen_x2);

    int main(void)
    {
    total = sumarrays(array1, MAX1, array2, MAX2);
    printf("Die Gesamtsumme beträgt %d\n", total);

    return 0;
    }

    int sumarrays(int x1[], int laen_x1, int x2[], int laen_x2)
    {

    int total = 0, count = 0;

    for (count = 0; count < laen_x1; count++)
    total += x1[count];

    for (count = 0; count < laen_x2; count++)
    total += x2[count];

    return total;
    }
  9. Siehe Antwort für Übung 7.
  10. Folgender Code ist nur eine mögliche Antwort:
    /* Übung 8.9 */

    #include <stdio.h>

    #define GROESSE 10

    /* Funktionsprototypen */
    void addarrays( int [], int []);

    int main(void)
    {
    int a[GROESSE] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
    int b[GROESSE] = {9, 8, 7, 6, 5, 4, 3, 2, 1, 0};

    addarrays(a, b);

    return 0;
    }

    void addarrays( int erstes[], int zweites[])
    {
    int total[GROESSE];
    int ctr = 0;

    for (ctr = 0; ctr < GROESSE; ctr ++ )
    {
    total[ctr] = erstes[ctr] + zweites[ctr];
    printf("%d + %d = %d\n", erstes[ctr], zweites[ctr], total[ctr]);
    }
    }

Tag 9: Zeichen und Strings

Antworten zum Quiz

  1. Die Werte des ASCII-Zeichensatzes reichen von 0 bis 255. Der Standardzeichensatz umfasst den Bereich 0 bis 127 und der erweiterte Zeichensatz den Bereich von 128 bis 255. Der erweiterte Teil des Zeichensatzes ändert sich je nach der länderspezifischen Konfiguration des Rechners.
  2. 2. Als den ASCII-Code des Zeichens.
  3. 3. Ein String ist ein Folge von Zeichen, die mit einem Nullzeichen abgeschlossen wird.
  4. 4. Eine Folge von einem oder mehreren Zeichen in doppelten Anführungszeichen.
  5. Um das abschließende Nullzeichen des Strings aufzunehmen.
  6. 6. Als eine Folge von ASCII-Zeichenwerten gefolgt von einer 0 (dem ASCII-Code für das Nullzeichen).
  7. a. 97
  8. b. 65
  9. c. 57
  10. d. 32
  11. a. I
  12. b. Ein Leerzeichen
  13. c. c
  14. d. Nullzeichen
  15. e. [Zeichenwert 2]
  16. a. 9 Byte. Eigentlich ist die Variable ein Zeiger auf einen String, und der String benötigt 9 Byte an Speicherplatz - 8 für den String und 1 für das Nullzeichen.
  17. b. 9 Byte
  18. c. 1 Byte
  19. d. 20 Byte
  20. e. 20 Byte
  21. a. E
  22. b. E
  23. c. 0 (Nullzeichen)
  24. d. Dies geht über das Ende des Strings hinaus. Es könnte irgendein Wert sein.
  25. e. !
  26. f. Er enthält die Adresse des ersten Elements des Strings.

Antworten zu den Übungen

  1. Der Code lautet:
    char buchstabe = '$';
  2. Der Code lautet:
    char array[21] = "Zeiger machen Spass!";
  3. Der Code lautet:
    char *array = "Zeiger machen Spass!";
  4. Der Code lautet:
    char *zgr;
    zgr = malloc(81);
    fgets(zgr,81,stdin);
  5. Das Folgende ist nur eine von mehreren möglichen Antworten. Sehen Sie im Folgenden ein komplettes Programm:
    /* Übung 9.5 */

    #include <stdio.h>

    #define GROESSE 10

    /* Funktionsprototypen */
    void kopiere_arrays( char [], char []);

    int main(void)
    {
    int ctr=0;
    char a[GROESSE] = {'1', '2', '3', '4', '5', '6',
    '7', '8', '9', '0'};
    char b[GROESSE];

    /* Werte vor dem Kopieren */
    for (ctr = 0; ctr < GROESSE; ctr ++ )
    {
    printf( "a[%d] = %c, b[%d] = %c\n",
    ctr, a[ctr], ctr, b[ctr]);
    }

    kopiere_arrays(a, b);

    /* Werte nach dem Kopieren */
    for (ctr = 0; ctr < GROESSE; ctr ++ )
    {
    printf( "a[%d] = %c, b[%d] = %c\n",
    ctr, a[ctr], ctr, b[ctr]);
    }

    return 0;
    }

    void kopiere_arrays( char quelle[], char ziel[])
    {
    int ctr = 0;

    for (ctr = 0; ctr < GROESSE; ctr ++ )
    {
    ziel[ctr] = quelle[ctr];
    }
    }
  6. Das folgende Programm ist eine von vielen möglichen Antworten:
    /* Übung 9.6 */

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

    /* Funktionsprototypen */
    char * vergleiche_strings( char *, char *);

    int main(void)
    {
    char *a = "Hallo";
    char *b = "Programmierer!";
    char *laenger;

    laenger = vergleiche_strings(a, b);

    printf( "Der längere String ist: %s\n", laenger );

    return 0;
    }

    char * vergleiche_strings( char * erster, char * zweiter)
    {
    int x, y;

    x = strlen(erster);
    y = strlen(zweiter);

    if( x > y)
    return(erster);
    else
    return(zweiter);
    }
  7. Diese Übung bleibt Ihnen überlassen!
  8. ein_string ist als ein Array von zehn Zeichen deklariert, wird aber mit einem String initialisiert, der länger als zehn Zeichen ist. ein_string muss größer sein.
  9. Wenn mit dieser Codezeile beabsichtigt wird, einen String zu initialisieren, ist der Code falsch. Sie sollten statt dessen besser *zitat oder zitat[100] verwenden.
  10. Ja.
  11. Nein. Sie können zwar einen Zeiger einem anderen zuweisen, aber mit Arrays geht das nicht. Sie sollten die Zuweisung in einen String-Kopierbefehl, wie strcpy(), umwandeln.
  12. Diese Übung bleibt Ihnen überlassen!

Tag 10: Strukturen

Antworten zum Quiz

  1. Die Datenelemente in einem Array müssen alle den gleichen Typ aufweisen. In einer Struktur dürfen die Elemente unterschiedlichen Typs sein.
  2. Der Punktoperator ist, wie der Name schon verrät, ein Punkt. Er dient dazu, um auf Elemente einer Struktur zuzugreifen.
  3. struct
  4. 4. Ein Strukturname ist an eine Strukturschablone gebunden und stellt somit keine wirkliche Variable dar. Eine Strukturinstanz ist eine Variable vom Typ einer Struktur, für die der Compiler bei der Deklaration Speicher reserviert hat und die Daten aufnehmen kann.
  5. Diese Anweisungen definieren eine Struktur und deklarieren eine Instanz namens meineadresse. Das Strukturelement meineadresse.name wird mit Bradley Jones initialisiert, meineadresse.adr1 mit RTSoftware, meineadresse.adr2 mit P.O. Box 1213, meineadresse.stadt mit Carmel, meineadresse.staat mit IN und meineadresse.plz mit 46032-1213.
  6. Die folgende Anweisung ändert zgr so, dass der Zeiger auf das zweite Array- Element zeigt:
    zgr++;

Antworten zu den Übungen

  1. Der Code lautet:
    struct zeit
    { int stunden;
    int minuten;
    int sekunden ;
    } ;
  2. Der Code lautet:
    struct daten
    { int wert1;
    float wert2, wert3;
    } info;
  3. Der Code lautet:
    info.wert1 = 100;
  4. Der Code lautet:
    struct daten *ptr;
    ptr = &info;
  5. Der Code lautet:
    ptr->wert2 = 5.5;
    (*ptr).wert2 = 5.5;
  6. Der Code lautet:
    struct daten
    { char name [21]
    };
  7. Der Code lautet:
    typedef struct
    { char adresse1[31];
    char adresse2[31];
    char stadt[11];
    char staat[3];
    char plz[11];
    } DATENSATZ;
  8. Der folgende Code verwendet zur Initialisierung die Werte aus der Quizfrage 5:
    DATENSATZ meineadresse = { "RTSoftware",
                               "P.O. Box 1213",
                               "Carmel", "IN", "46082-1213"};
  9. Dieses Codefragment weist zwei Fehler auf. Zum einen sollte die Struktur einen Namen erhalten. Zweitens ist die Initialisierung von zeichen falsch. Die Initialisierungswerte sollten in geschweiften Klammern stehen. Und so sieht der Code korrekt aus:
    struct tierkreis
    { char tierkreiszeichen [21];
    int monat ;
    } zeichen = { "Löwe", 8 } ;
  10. Die Deklaration von union ist nur in einer Hinsicht falsch. Es kann immer nur eine Variable der Union zur Zeit verwendet werden. Das gilt auch für die Initialisierung der Union. So sähe die korrekte Initialisierung aus:
    /* eine Union einrichten */
    union daten{
    char ein_wort[4];
    long eine_zahl;
    } generische_variable = { "WOW" } ;

Tag 11: Gültigkeitsbereiche von Variablen

Antworten zum Quiz

  1. Der Gültigkeitsbereich einer Variablen bezieht sich auf den Bereich, in dem Teile eines Programms Zugriff auf die Variable haben beziehungsweise in dem die Variable sichtbar ist.
  2. 2. Eine Variable mit lokaler Speicherklasse ist nur in der Funktion sichtbar, in der sie definiert ist. Eine Variable mit globaler Speicherklasse ist im gesamten Programm sichtbar.
  3. Durch die Definition einer Variablen innerhalb einer Funktion wird die Funktion lokal. Eine Definition außerhalb aller Funktionen macht sie global.
  4. 4. Automatisch (der Standard) oder statisch. Eine automatische Variable wird stets neu erzeugt, wenn die Funktion aufgerufen wird, und mit Ende der Funktion zerstört. Eine statische lokale Variable bleibt bestehen und behält ihren Wert zwischen den Aufrufen der Funktion, die sie enthält.
  5. 5. Eine automatische Variable wird bei jedem Funktionsaufruf neu initialisiert. Eine statische Variable wird nur beim ersten Funktionsaufruf initialisiert.
  6. Falsch. Wenn Sie Registervariablen deklarieren, sprechen Sie eine Bitte aus. Es gibt keine Garantien, dass der Compiler dieser Bitte nachkommt.
  7. 7. Eine nicht initialisierte globale Variable wird automatisch mit 0 initialisiert. Es ist jedoch immer besser, Variablen explizit zu initialisieren.
  8. 8. Eine nicht initialisierte lokale Variable wird nicht automatisch initialisiert. Sie kann deshalb einen beliebigen Wert enthalten. Nicht initialisierte Variablen sollte man nicht verwenden; denken Sie daher immer daran, Ihre Variablen vorab zu initialisieren.
  9. Da die übrig gebliebene Variable count lokal zu dem Block ist, hat die Funktion printf() nicht länger Zugriff auf eine Variable namens count. Der Compiler wird eine Fehlermeldung ausgeben.
  10. Wenn der Wert beibehalten werden soll, sollten Sie die Variable als statisch deklarieren. Für eine int-Variable namens vari lautete die Deklaration beispielsweise:
    static int vari;
  11. Das Schlüsselwort extern wird als Speicherklassen-Modifizierer verwendet. Es weist darauf hin, dass die Variable irgendwo sonst in dem Programm deklariert worden ist.
  12. Das Schlüsselwort static wird als Speicherklassen-Modifizierer verwendet. Es teilt dem Compiler mit, den Wert einer Variablen oder Funktion für die Dauer des Programms zu behalten. Innerhalb einer Funktion behält die Variable ihren Wert zwischen den Funktionsaufrufen.

Antworten zu den Übungen

  1. register int x = 0;
  2. Der Code lautet:
    /* Übung 11.2 */
    #include <stdio.h>
    void wert_ausgeben (int x);
    int main(void)
    {
    int x = 999;

    printf("%d\n", x);
    wert_ausgeben(x);

    return 0;
    }

    void wert_ausgeben (int x)
    {
    printf("%d\n", x);
    }
  3. Da Sie die Variable var als global deklarieren, müssen Sie sie nicht als Parameter übergeben.
    /* Übung 11.3 */

    #include <stdio.h>

    void wert_ausgeben(void);

    int var = 99;

    int main(void)
    {
    wert_ausgeben();

    return 0;
    }

    void wert_ausgeben (void)
    {
    printf("Der Wert ist %d.\n", var);
    }
  4. Ja, Sie müssen die Variable var übergeben, um sie in einer anderen Funktion auszugeben.
    /* Übung 11.4 */
    #include <stdio.h>

    void wert_ausgeben (int x);

    int main(void)
    {
    int var = 99;

    wert_ausgeben(var);

    return 0;
    }

    void wert_ausgeben (int x)
    {
    printf("Der Wert ist %d.\n", x);
    }
  5. Ja, ein Programm kann eine lokale und gleichzeitig eine gleichnamige globale Variable haben. In solchen Fällen haben die aktiven lokalen Variablen Priorität.
    /* Übung 11.5 */
    #include <stdio.h>

    void wert_ausgeben(void);

    int var = 99;

    int main(void)
    {
    int var = 77;
    printf ("Ausgabe in Funktion mit lokaler u. globaler Variablen.\n");
    printf("Der Wert von var ist %d.\n", var);
    wert_ausgeben();

    return 0;
    }

    void wert_ausgeben (void)
    {
    printf("Der Wert ist %d.\n", var);
    }
  6. Die Funktion eine_beispiel_funktion() weist nur ein Problem auf. Variablen müssen zu Beginn eines Blocks deklariert werden, so dass die Deklarationen von ctr1 und sternchen korrekt sind. Die andere Variable, ctr2, wird jedoch nicht zu Beginn des Blocks deklariert. Diese Art der Deklaration ist in C++ zulässig, aber nicht in C. Sehen Sie im Folgenden ein vollständiges Programm mit der korrigierten Funktion.
    /* Übung 11.6 */
    #include <stdio.h>

    void eine_beispiel_funktion( void );

    int main(void)
    {
    eine_beispiel_funktion();
    puts("");

    return 0;
    }

    void eine_beispiel_funktion( void )
    {
    int ctr1;

    for ( ctr1 = 0; ctr1 < 25; ctr1++ )
    printf( "*" );
    puts( "\nDies ist eine Beispielfunktion" );
    {
    char sternchen = '*';
    int ctr2; /* Damit wird der Fehler behoben. */
    puts( "\nEs gibt kein Problem\n" );
    for ( ctr2 = 0; ctr2 < 25; ctr2++ )
    {
    printf( "%c", sternchen);
    }
    }
    }
  7. Dies Programm läuft eigentlich fehlerfrei, aber es kann trotzdem noch verbessert werden. Zum einen besteht kein Grund, die Variable x mit 1 zu initialisieren, da sie bereits in der for-Anweisung mit 0 initialisiert wird. Außerdem ist es nicht nötig, die Variable anzahl als statisch zu deklarieren, denn das Schlüsselwort static hat in der main()-Funktion keine Auswirkung.
  8. Welche Werte haben sternchen und strich? Diese zwei Variablen werden nicht initialisiert. Da beide lokale Variablen sind, könnten sie jeden Wert enthalten. Denken Sie daran, dass dieses Programm, auch wenn es sich ohne Fehlermeldungen oder Warnungen kompilieren lässt, trotzdem noch zu einem Problem werden kann.
  9. Auch möchte ich Ihr Augenmerk auf ein zweites Problem lenken. Die Variable ctr wird als global deklariert, aber nur in funktion_ausgeben() verwendet. Diese Zuweisung ist nicht besonders glücklich. Das Programm wäre besser, wenn ctr eine lokale Variable zu der Funktion funktion_ausgeben() wäre.
  10. Das Programm gibt das folgende Muster unendlich oft aus:
    X==X==X==X==X==X==X==X==X==X==X==X==X==X==X==X==...
  11. Das Problem dieses Programms liegt in dem globalen Gültigkeitsbereich der Variablen ctr, denn main() und buchstabe2_ausgeben() verwenden beide die Variable ctr in ihren verschachtelten Schleifen. Da buchstabe2_ausgeben() den Wert ändert, wird die for-Schleife in main() nie abgeschlossen. Den Fehler können Sie auf verschiedene Arten beheben, aber am besten wäre es, wenn Sie sowohl in main() als auch in buchstabe2_ausgeben() eine lokale Variable ctr deklarierten.
  12. Außerdem ist es sinnvoll, die anderen globalen Variablen buchstabe1 und buchstabe2 in die Funktionen zu verschieben, in denen sie benötigt werden.
    #include <stdio.h>

    void buchstabe2_ausgeben(void);

    int main(void)
    {
    char buchstabe1 = 'X';
    int ctr;

    for( ctr = 0; ctr < 10 ; ctr++ )
    {
    printf("%c", buchstabe1);
    buchstabe2_ausgeben();
    }
    puts ("");
    return 0;
    }

    void buchstabe2_ausgeben(void)
    {
    char buchstabe2 = '=';
    int ctr; /* Diese Variable ist lokal */
    /* sie unterscheidet sich von ctr in main() */

    for( ctr = 0; ctr < 2 ; ctr++ )
    printf("%c", buchstabe2);
    }

Tag 12: Fortgeschrittene Programmsteuerung

Antworten zum Quiz

  1. Nie. (Es sei denn, die goto-Anweisung macht den Code wesentlich verständlicher.)
  2. Wenn das Programm auf eine break-Anweisung trifft, verlässt die Ausführung sofort die for-, while- oder do...while-Schleife, welche die break-Anweisung enthält. Wenn das Programm auf eine continue-Anweisung trifft, beginnt sofort der nächste Durchlauf der Schleife.
  3. 3. Eine Endlosschleife wird für immer ausgeführt. Man erzeugt sie, indem man eine for-, while- oder do...while-Schleife mit einer Bedingung verknüpft, die immer wahr ist.
  4. Die Ausführung ist beendet, wenn das Programm das Ende der Funktion main() erreicht oder die Funktion exit() aufgerufen wird.
  5. Der Ausdruck in einer switch-Anweisung kann zu einem Wert von Typ long, int oder char ausgewertet werden.
  6. Die default-Anweisung ist ein spezieller Fall in der switch-Anweisung. Wenn der Ausdruck in der switch-Anweisung in einen Wert resultiert, zu dem es keine übereinstimmende case-Konstante gibt, springt die Programmausführung zu default.
  7. Die Funktion exit() beendet das Programm. Dieser Funktion kann ein Wert übergeben werden, der an das Betriebssystem zurückgegeben wird.
  8. Die Funktion system() führt einen Befehl des Betriebssystems aus.

Antworten zu den Übungen

  1. continue;
  2. break;
  3. system ("/bin/ls");
  4. Dieses Beispiel ist korrekt. Sie brauchen keine break-Anweisung nach dem 'N'-Fall, da die switch-Anweisung hier sowieso endet.
  5. Vielleicht denken Sie, dass die Auffanglösung (default) am Ende der switch- Anweisung stehen muss, aber dem ist nicht so. Der default-Fall kann irgendwo in der switch-Anweisung stehen. Der Fehler in diesem Code liegt darin, dass am Ende der default-Anweisung keine break-Anweisung steht.
  6. Der Code lautet:
    if (option == 1)
    printf("Ihre Antwort lautete 1");
    else if (option == 2)
    printf("Ihre Antwort lautete 2");
    else
    printf("Sie haben nicht 1 oder 2 gewählt");

  7. Der Code lautet:
    do {
    /* beliebige C-Anweisungen. */
    } while (1);

Tag 13: Mit Bildschirm und Tastatur arbeiten

Antworten zum Quiz

  1. Ein Stream ist eine Folge von Bytes. C-Programme verwenden Streams für die Ein- und Ausgabe.
  2. a. Ein Drucker ist ein Ausgabegerät.
  3. b. Eine Tastatur ist ein Eingabegerät.
  4. c. Ein Modem ist beides, Ein- und Ausgabegerät.
  5. d. Ein Bildschirm ist ein Ausgabegerät. (Wenn es ein Touchscreen-Bildschirm ist, ist es sowohl Ein- als auch Ausgabegerät.)
  6. e. Ein Laufwerk kann beides sein, Ein- und Ausgabegerät.
  7. C-Compiler unterstützen drei vordefinierte Streams: stdin (die Tastatur), stdout (der Bildschirm) und stderr (der Bildschirm).
  8. a. stdout.
  9. b. stdout.
  10. c. stdin.
  11. d. stdin.
  12. e. fprintf() kann einen beliebigen Ausgabestream verwenden - beispielsweise stdout oder stderr.
  13. Gepufferte Eingaben werden erst an das Programm geschickt, wenn der Anwender die Eingabetaste drückt. Ungepufferte Eingaben werden Zeichen für Zeichen geschickt, sobald eine Taste gedrückt wird.
  14. Sie können zwischen zwei Leseoperationen jeweils nur ein Zeichen »zurückstellen«. Das EOF-Zeichen kann nicht mit ungetc() in den Eingabestream zurückgestellt werden.
  15. Mit einem Neue-Zeile-Zeichen, was dem Drücken der Eingabetaste seitens des Anwenders entspricht.
  16. a. Gültig.
  17. b. Gültig.
  18. c. Gültig.
  19. d. Nicht gültig, q ist kein gültiger Formatspezifizierer.
  20. e. Gültig.
  21. f. Gültig.
  22. Der wesentliche Unterschied ist, dass stderr gepuffert ist und stdout nicht.

Antworten zu den Übungen

  1. printf("Hallo Welt");
  2. Der Code lautet:
    fprintf(stdout, "Hallo Welt");
    puts("Hallo Welt");
  3. fprintf(stderr, "Hallo Standardfehlerausgabe");
  4. Der Code lautet:
    char puffer[31];
    scanf("%30[^*]s"", puffer);
  5. Der Code lautet:
    printf("Hans fragte, \"Was ist ein Backslash\?\"\nGrete sagte, \"Es ist ein \'\\\'\");
  6. Keine spezielle Antwort.

Tag 14: Zeiger für Fortgeschrittene

Antworten zum Quiz

  1. Der Code lautet:
    float x;
    float *px = &x;
    float **px = &px;
  2. Der Fehler besteht darin, dass ein einfacher Indirektionsoperator verwendet und folglich der Wert 100 px und nicht x zugewiesen wird. Die Anweisung sollte mit einem doppelten Indirektionsoperator geschrieben werden:
    **ppx = 100;
  3. array ist ein Array mit zwei Elementen. Jedes dieser Elemente ist selbst ein Array, das drei Elemente enthält. Jedes dieser drei Elemente ist ein Array, das vier int- Variablen enthält.
  4. array[0][0] ist ein Zeiger auf das erste vierelementige Array vom Typ int[].
  5. Der erste und der dritte Vergleich sind wahr, der zweite ist falsch.
  6. void funk(char *zgr[]);
  7. Die Funktion kann das nicht wissen. Normalerweise wird bei dieser Art von Funktion das Ende des Arrays mit einer Art Markierung versehen, wie zum Beispiel einem NULL-Zeiger.
  8. 8. Ein Zeiger auf eine Funktion ist ein Zeiger, der die Speicheradresse enthält, an der die Funktion gespeichert ist.
  9. char (*zgr)(char *x[]);
  10. Wenn Sie die Klammern um *zgr vergessen, ist die Zeile ein Prototyp einer Funktion, die einen Zeiger vom Typ char zurückliefert.
  11. Fangfrage! Ein void-Zeiger kann nicht inkrementiert werden, da der Compiler die Größe des Objekts, auf den der Zeiger zeigt, nicht kennt.
  12. 12. Eine Funktion kann einen Zeiger auf jeden beliebigen C-Variablentyp zurückliefern. Eine Funktion kann auch einen Zeiger auf Speicherbereiche wie Arrays, Strukturen und Unions zurückliefern.
  13. Die Struktur muss einen Zeiger auf eine Struktur des gleichen Typs enthalten.
  14. Wenn der Head-Zeiger gleich NULL ist, heißt das, dass die Liste leer ist.
  15. Jedes Element in der Liste enthält einen Zeiger, der auf das nächste Element in der Liste verweist. Auf das erste Element in der Liste verweist Head-Zeiger.
  16. a. var1 ist ein Zeiger auf einen Integer.
  17. b. var2 ist ein Integer.
  18. c. var3 ist ein Zeiger auf einen Zeiger auf Integer.
  19. a. a ist ein Array von 36 (3 * 12) Integer-Elementen.
  20. b. b ist ein Zeiger auf ein Array von zwölf Integer-Elementen.
  21. c. c ist ein Array von zwölf Zeigern auf Integer-Elemente.
  22. Was wird in den folgenden Zeilen deklariert?
  23. a. z ist ein Array von zehn Zeigern auf Zeichen.
  24. b. y ist eine Funktion, die ein Integer-Argument übernimmt und einen Zeiger auf ein Zeichen zurückliefert.
  25. c. x ist ein Zeiger auf eine Funktion, die ein Integer-Argument übernimmt und ein Zeichen zurückliefert.

Antworten zu den Übungen

  1. float (*funk)(int field);
  2. int (*menue-optionen[10])(char *titel);
  3. Ein Array von Funktionszeigern kann man beispielsweise zum Aufbau eines Menüs verwenden. Die Nummern der Menübefehle könnte man als Index zu den Funktionszeigern im Array verwenden. So würde beispielsweise nach der Auswahl der fünften Option im Menü die Funktion aufgerufen, auf die das fünfte Elemente im Array verweist.
  4. char *zgr[10];
  5. Ja, zgr wird als ein Array von zwölf Zeigern auf Integer-Werte deklariert und nicht als Zeiger auf ein Array von zwölf Integer-Werten. Der korrekte Code lautet:
    int x[3][12];
    int (*zgr)[12];
    zgr = x;
  6. Die folgende Lösung ist nur eine von vielen:
    struct freund
    {
    char name[32];
    char adresse[64];
    struct freund *next;
    };
  7. int funktion(char *zgr[]);
  8. 9. Unter der Voraussetzung, dass der Rückgabetyp void ist, lautet der Prototyp der Funktion zahlen() wie folgt:
    void zahlen(int *a, int *b, int *c);
  9. Um die Funktion zahlen() in Übung 9 aufzurufen, müssen Sie den Adressoperator verwenden:
    zahlen (&int1, &int2, &int3);
  10. 11. Auch wenn dies etwas verwirrend wirkt, ist es doch korrekt. Die Funktion übernimmt den Wert, auf den nbr zeigt, und multipliziert ihn mit sich selbst.

Tag 15: Mit Dateien arbeiten

Antworten zum Quiz

  1. ) um, die Windows zur Markierung des Zeilenendes verwendet "> Linux unterscheidet nicht zwischen binären Dateien und Dateien im Textmodus. Unter Windows wandelt ein Textmodus-Stream automatisch das Neue-Zeile- Zeichen ('\n'), das C zur Markierung des Zeilenendes verwendet, in die Zeilenumbruch/Wagenrücklauf-Kombination ("\n\r") um, die Windows zur Markierung des Zeilenendes verwendet.
  2. Um sicherzustellen, dass ein Programm, das binäre Daten einliest, auf Windows portierbar ist, müssen Sie beim Aufruf von fopen() das Zeichen b als Teil des Modus-Strings angeben.
  3. Die Datei mit fopen() öffnen.
  4. Wenn Sie fopen() verwenden, müssen Sie den Namen der zu öffnenden Datei angeben und den Modus, in dem geöffnet werden soll. Die Funktion fopen() liefert einen Zeiger auf den Typ FILE zurück. Dieser Zeiger wird in nachfolgenden Dateizugriffsfunktionen verwendet, um auf die spezielle Datei Bezug zu nehmen.
  5. Formatiert, zeichenweise und direkt.
  6. Sequentiell und wahlfrei.
  7. Der Wert von EOF ist eine symbolische Konstante, die -1 entspricht und das Ende einer Datei markiert.
  8. In binären Dateien ermittelt man das Ende der Datei mit Hilfe der Funktion feof(). In Textdateien können Sie sowohl nach dem EOF-Zeichen Ausschau halten als auch feof() verwenden.
  9. Der Dateipositionszeiger zeigt in einer gegebenen Datei auf die Position, an der die nächste Lese- oder Schreiboperation stattfinden wird. Sie können den Dateipositionszeiger mit rewind() oder fseek() verschieben.
  10. Wenn eine Datei das erste Mal geöffnet wird, zeigt der Dateipositionszeiger auf das erste Zeichen - sprich den Offset 0. Die einzige Ausnahme hierzu sind Dateien, die im Anhängen-Modus geöffnet wurden, da der Dateipositionszeiger in diesem Fall auf das Ende der Datei gesetzt wird.

Antworten zu den Übungen

  1. fcloseall();
  2. Der Code lautet:
    rewind(fp);
    fseek(fp, 0, SEEK_SET);
  3. Das lässt sich so nicht sagen. Wenn die Datei binäre Daten enthält, funktioniert dieser Code unter Umständen nicht wie erwartet, da die Daten in der Datei das EOF-Zeichen enthalten können. Es wäre besser, die feof()-Funktion zu verwenden.

Tag 16: Stringmanipulation

Antworten zum Quiz

  1. Die Länge eines Strings errechnet sich aus der Anzahl der Zeichen zwischen dem Anfang des Strings und dem abschließenden Nullzeichen (das nicht mitgezählt wird). Sie können die Stringlänge mit Hilfe der Funktion strlen() ermitteln.
  2. Bevor Sie einen String kopieren, müssen Sie sicherstellen, dass Sie genügend Speicherplatz für den neuen String reserviert haben.
  3. Konkatenation bedeutet Zusammenfügen. Im Zusammenhang mit Strings versteht man darunter, einen String an einen anderen anzuhängen.
  4. 1 "> Wenn Sie Strings vergleichen, bedeutet »größer als«, dass die ASCII-Werte des einen Strings höher sind als die des zweiten Strings.1
  5. Die Funktion strcmp() vergleicht zwei komplette Strings, während strncmp() nur eine bestimmte Anzahl von Zeichen innerhalb der Strings vergleicht.
  6. Die Funktion strcmp() vergleicht zwei Strings unter Berücksichtigung der Groß- und Kleinschreibung (das heißt, 'a' und 'A' werden als unterschiedliche Buchstaben betrachtet). Mit der Funktion strcasecmp() können die Vergleiche ohne Rücksicht auf die Groß- und Kleinschreibung durchgeführt werden. ('a' und 'A' werden als gleich betrachtet.)
  7. Die isascii()-Funktion prüft, ob ein Zeichen innerhalb des Wertebereichs 0 bis 127 liegt.
  8. Die Funktionen isascii() und iscntrl() würden beide wahr zurückliefern. Alle andern liefern falsch zurück.
  9. Der Wert 65 entspricht dem Zeichen 'A'. Die folgenden Makros liefern wahr zurück: isalnum(), isalpha(), isascii(), isgraph(), isprint() und isupper().
  10. Die Zeichentestfunktionen bestimmen, ob ein Zeichen eine bestimmte Bedingung erfüllt, zum Beispiel ob das Zeichen ein Buchstabe, ein Satzzeichen oder irgendetwas anderes ist.

Antworten zu den Übungen

  1. Wahr (1) oder Falsch (0).
  2. a. 65
  3. b. 81
  4. c. -34
  5. d. 0
  6. e. 12
  7. f. 0
  8. a. 65.000000
  9. b. 81.230000
  10. c. -34.200000
  11. d. 0.000000
  12. e. 12.00000
  13. f. 1000.0000
  14. Der string2 wird verwendet, ohne dass zuvor Speicher für den String reserviert wurde. Es ist daher unmöglich, vorherzusagen, wohin strcpy() den Wert von string1 kopiert.

Tag 17: Die Bibliothek der C-Funktionen

Antworten zum Quiz

  1. double.
  2. Auf den meisten Betriebssystemen einschließlich Linux entspricht time_t dem Typ long.
  3. Die Funktion time() liefert die Anzahl der Sekunden, die seit dem 1. Januar 1970 um Mitternacht verstrichen sind, zurück, die Funktion clock() liefert die Anzahl Millionstelsekunden seit Programmbeginn zurück.
  4. Nichts, die Funktion perror() gibt lediglich eine Meldung aus, die den Fehler beschreibt.
  5. 5. Eine Funktion, die eine beliebig lange Argumentenliste übernimmt, muss mindestens ein festes Argument haben. Dies wird benötigt, um der Funktion die Anzahl der Argumente mitzuteilen, die ihr bei jedem Aufruf übergeben werden.
  6. va_start() sollte verwendet werden, um die Argumentenliste zu initialisieren. va_arg() sollte verwendet werden, um auf die Argumente zuzugreifen, und va_end() sollte verwendet werden, um nach der Verarbeitung der Argumente aufzuräumen
  7. Bevor Sie ein Array mit bsearch() durchsuchen, müssen Sie es in aufsteigender Reihenfolge sortieren.
  8. 14
  9. 4
  10. 21
  11. 0, wenn die Werte gleich sind, >0, wenn der Wert von Element 1 größer ist als Element 2, und <0, wenn Element 1 kleiner ist als Element 2.
  12. NULL

Antworten zu den Übungen

  1. Der Code lautet:
    bsearch(meinname, namen, (sizeof(namen)/sizeof(namen[0])),
    sizeof(namen[0]), vergl_namen);
  2. Es gibt drei Fehler. Zum einen ist in dem Aufruf von qsort() keine Feldlänge angegeben. Zweitens sollten hinter dem Funktionsnamen qsort() keine Klammern stehen und drittens fehlt dem Programm die Vergleichsfunktion. qsort() verwendet vergleich_funktion(), die im Programm nicht definiert ist.
  3. Die Vergleichsfunktion liefert die falschen Werte zurück. Sie sollte einen positiven Wert zurückgeben, wenn element1 > element2, und einen negativen Wert, wenn element1 < element2.
  4. Wenn Sie beliebig lange Argumentenlisten verwenden, sollten Sie alle Makro- Tools verwenden. Dazu gehören va_list, va_start(), va_arg() und va_end(). Siehe Listing 17.5 für die korrekte Anwendung von beliebig langen Parameterlisten.

Tag 18: Vom Umgang mit dem Speicher

Antworten zum Quiz

  1. Die Funktion malloc() reserviert eine bestimmte Anzahl an Byte, während calloc() ausreichend Speicher für eine vorgegebene Anzahl an Elementen einer bestimmten Größe reserviert. Mit calloc() werden außerdem die Bytes im Speicher auf 0 gesetzt, wohingegen malloc() keine Initialisierung vornimmt.
  2. Der häufigste Grund für eine Typumwandlung einer numerischen Variablen liegt vor, wenn bei einer Division zweier Integer-Werte und der anschließenden Zuweisung des Ergebnisses an eine Fließkommavariable der Nachkommateil der Antwort erhalten bleiben soll.
  3. a. long
  4. b. int
  5. c. char
  6. d. float
  7. e. float
  8. Dynamisch reservierter Speicher wird zur Laufzeit reserviert - während das Programm ausgeführt wird. Die dynamische Speicherallokation ermöglicht es Ihnen, zum einem genau so viel Speicherplatz zu reservieren, wie benötigt wird, und zum anderen nur dann Speicher zu reservieren, wenn dieser benötigt wird.
  9. Die Funktion memmove() arbeitet auch dann korrekt, wenn sich die Speicherbereiche von Quelle und Ziel überlappen (im Gegensatz zu der Funktion memcpy()). Wenn sich Quell- und Zielbereiche nicht überlappen, sind die beiden Funktionen identisch.
  10. Indem man ein Bitfeld definiert, das 3 Bit groß ist. Da 23 gleich 8 sind, ist ein solches Feld groß genug, um die Werte von 1 bis 7 aufzunehmen.
  11. 2 Byte. Unter Verwendung von Bitfeldern könnten Sie folgende Struktur deklarieren:
    struct datum
    {
    unsigned monat : 4;
    unsigned tag : 5;
    unsigned jahr : 7;
    };
  12. Diese Struktur speichert das Datum in 2 Byte (16 Bit). Das 4-Bit-Feld monat kann Werte von 0 bis 15 enthalten, was für die Aufnahme der zwölf Monate ausreicht. Entsprechend kann das 5-Bit-Feld tag Werte von 0 bis 31 und das 7-Bit-Feld jahr Werte von 0 bis 127 aufnehmen Wir setzen dabei voraus, dass sich das Jahr aus der Addition von 1900 plus dem abgespeicherten Wert errechnet, so dass Jahreswerte von 1900 bis 2027 möglich sind.
  13. Obwohl sich diese Struktur auf den Jahresbereich 1900 bis 2027 korrekt anwenden lässt, ist es nicht ratsam, diese Struktur für Softwareprodukte zu verwenden, die möglicherweise länger als 20 Jahre im Einsatz sind.
  14. 16000
  15. 500
  16. Diese zwei Ausdrücke ergeben die gleiche Antwort. Die Verwendung des exklusiven OR mit dem binären Wert 11111111 führt zum gleichen Ergebnis wie die Verwendung des Komplement-Operators. Jedes Bit in den ursprünglichen Werten wird umgekehrt.

Antworten zu den Übungen

  1. Der Code lautet:
    long *zgr;
    zgr = malloc (1000 * sizeof(long));
  2. Der Code lautet:
    long *zgr;
    zgr = calloc (1000, sizeof(long));
  3. Mit einer Schleife und einer Zuweisung:
    int count;
    for(count = 0 ; count < 1000; count++)
    daten[count] = 0;
  4. Mit der memset()-Funktion:
    memset(daten, 0, 1000 * sizeof(float));
  5. Dieser Code wird sich ohne Fehler kompilieren und ausführen lassen. Und trotzdem sind die Ergebnisse nicht korrekt. Da sowohl zahl1 als auch zahl2 Integer-Variablen sind, ist das Ergebnis ihrer Division ein Integer-Wert. Dabei geht ein möglicher Nachkommateil der Antwort verloren. Um eine korrekte Antwort zu erhalten, müssen Sie den Typ des Ausdrucks in float umwandeln:
    antwort = (float) zahl1 / zahl2;
  6. Da p ein void-Zeiger ist, muss er zuerst vom Typ her umgewandelt werden, bevor er in einer Zuweisung verwendet werden kann. Die dritte Zeile sollte wie folgt lauten
    *(float*)p = 1.23;
  7. Nein. Wenn Sie Bitfelder verwenden, müssen Sie sie in der Struktur als Erstes aufführen. Die folgende Definition wäre korrekt:
    struct quiz_antworten {
    unsigned antwort1 : 1;
    unsigned antwort2 : 1;
    unsigned antwort3 : 1;
    unsigned antwort4 : 1;
    unsigned antwort5 : 1;
    char student_name[15];
    };

Tag 19: Prozesse und Signale

Antworten zum Quiz

  1. 1. Eine Prozess-ID ist eine eindeutige Nummer, die vom Betriebssystem vergeben wird, um einen laufenden Prozess zu identifizieren.
  2. Der Wertebereich für gültige Prozess-IDs liegt zwischen 1 bis einschließlich 32767.
  3. Die Funktion getpid() liefert die Prozess-ID des Prozesses zurück, der die Funktion aufruft, während getppid() die Prozess-ID des Elternprozesses zurückliefert.
  4. (a) Die Prozess-ID des Kindprozesses
  5. (b) 0
  6. Ein Zombie-Prozess ist ein bereits beendeter Prozess, der immer noch in der betriebssysteminternen Prozesstabelle darauf wartet, dass der Elternprozess seinen Exit-Code ermittelt.
  7. Die Funktion wait() wird immer warten, bis ein Kindprozess beendet ist, während die Funktion waitpid() angewiesen werden kann, direkt zurückzukehren, wenn keine Zombie-Kindprozesse existieren.
  8. 7. Nach einem erfolgreichen Aufruf von execl() wird der aktuelle Prozess durch das neue Programm ersetzt, so dass kein Code mehr in dem Programm, das ihn aufgerufen hat, ausgeführt wird.
  9. 1523
  10. SIGSTOP und SIGKILL

Antworten zu den Übungen

  1. Der folgende Code funktioniert für Befehle ohne Argumente:
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <sys/wait.h>

    int mein_system(char *befehl);

    int main (void)
    {

    mein_system ("/bin/ls");

    printf ("Fertig\n");

    return 0;
    }

    int mein_system(char *befehl)
    {
    pid_t pid;
    int status;

    pid = fork();
    if (pid == -1)
    return -1;
    if (pid == 0)
    {
    execl(befehl, befehl, NULL);
    }

    wait (&status);

    return status;
    }

Tag 20: Compiler für Fortgeschrittene

Antworten zum Quiz

  1. Der Begriff modulare Programmierung bezieht sich darauf, dass man bei größeren Programmprojekten aus Gründen der Übersichtlichkeit und Wartbarkeit den Quellcode auf mehrere Quelltextdateien aufteilt.
  2. Das main-Modul ist das Modul mit der main()-Funktion.
  3. Durch die Klammern wird sichergestellt, dass komplexe, als Argumente übergebene Ausdrücke zuerst voll ausgewertet werden - wodurch unerwünschte Nebeneffekte vermieden werden.
  4. Im Vergleich zu einer Funktion ist die Ausführung eines Makros schneller, geht aber auf Kosten eines größeren Programmumfangs.
  5. Der Operator defined() prüft, ob ein bestimmter Name definiert ist. Wenn ja, wird wahr zurückgeliefert, im anderen Fall falsch.
  6. 6. Auf ein #if muss ein korrespondierendes #endif folgen.
  7. #include kopiert den Inhalt der angegebenen Datei in die aktuelle Datei.
  8. 8. Ein #include in doppelten Anführungszeichen weist den Compiler an, die include-Datei in dem aktuellen Verzeichnis zu suchen. Ein #include-Anweisung, bei der der Dateiname in spitzen Klammern steht (<>), weist den Compiler an, in den Standardverzeichnissen zu suchen.
  9. __DATE__ wird verwendet, um das Kompilierungsdatum des Programms in das Programm aufzunehmen.
  10. argv[0] zeigt auf einen String, der den Namen des aktuellen Programms enthält

Antworten zu den Übungen

Aufgrund der vielen möglichen Lösungen gibt es zu den Übungen von Tag 20 keine Antworten.

Tag 21: Einführung in die GUI-Programmierung mit GTK+

Antworten zum Quiz

  1. Um gcc mitzuteilen, wo die GTK+-Headerdateien zu finden sind, ist es am bequemsten, die Option gtk-config --cflags in den Compiler-Aufruf mit aufzunehmen.
  2. Um gcc mitzuteilen, wo die GTK+-Bibliotheken zu finden sind, ist es am bequemsten, die Option gtk-config --libs in den Compiler-Aufruf mit aufzunehmen.
  3. 3. Eine Callback-Funktion dient dazu, bestimmte, vom Programmierer vorgegebene, Aktionen durchzuführen. Das Besondere an einer Callback-Funktion ist, dass sie so eingerichtet wird, dass sie automatisch aufgerufen wird, wenn ein bestimmtes GUI-Ereignis eintritt (beispielsweise wenn eine Schaltfläche angeklickt oder ein Menübefehl ausgewählt wird).

Antworten zu den Übungen

Aufgrund der vielen möglichen Lösungen gibt es zu den Übungen von Tag 21 keine Antworten.

1

vorheriges KapitelInhaltsverzeichnisStichwortverzeichnisFeedbackKapitelanfangnächstes Kapitel


© Markt&Technik Verlag, ein Imprint der Pearson Education Deutschland GmbH