Tutoriumsinhalt

  • HW3: Häufige Fehler
  • Palme Testreport Explainer
  • Funktionen
  • Call-by-Reference
  • Arrays
  • Pointer
  • Strings
  • Pipes
  • Gruppenbeispiel 1: Besprechung

HW3 Besprechung - Häufige Fehler

  • Nur eine Schleife verwendet (Spezifikation: zwei Schleifen)
  • Codingstandard (Tabulatoren, Zeile zu lang, Einrückungen, ...)
  • Deutsche Variablennamen und deutsche Kommentare
  • Schlechte Variablennamen (i, tmp, ...)
  • Falsche Overflow Behandlung
  • Falsche Outputs

HW3 Besprechung - Häufige Fehler

  • Falsche Overflow Behandlung:
    • if(number < 0) ...
    • if((number * counter) < number) ...
    • if(number > INT_MAX - number) ...
    • if(number > INT_MAX) ...
    • if(nubmer * counter >= INT_MAX) ...
  • Richtige Overflow Behandlung:
    • if(number > INT_MAX / counter) ...
    • if(((double)number * (double)counter) > INT_MAX) ...

HW3 Beispiele - Gut oder schlecht?

HW3 Beispiele - Gut oder schlecht?

HW3 Beispiele - Gut oder schlecht?

Palme Testreport Explainer

Funktionen

 <Rueckgabewert-Typ> Funktion-Name (<Parameter1>, <Parameter2>...)
 {
   // Code
   return <Rueckgabewert>
 }

 int main()
 {
   // Aufruf:
   <Rueckgabewert-Typ> Ergebnis;
   Ergebnis = Funktion-Name(<Parameter1>, <Parameter2>...);
 } 

Rückgabewert der main-Funktion anzeigen

 > echo $?
 0
 

Funktionen - Beispiel

 int correctCode(int studentID)
 {
   ... code ...
   return points;
 }

 int main()
 {
   int num_studis = 85;
   int i = 0;
   for(i = 0; i < num_studis; i++)
   {
      printf("Student #%d received %d points!", i, correctCode(i));
   }
 } 

Funktionen - Void als Returnwert

 void printHello()
 {
   while(1)
   {
     int studentID = 0;
     printf("Please enter your studentID: ");
     scanf("%d", &studentID);

     if(studentID == 0)
     {
       return;
     }
     printf("Hello %d!\n", studentID);
   }
 }

 int main()
 {
   printHello();
 } 

Rekursive Funktionen

 int fibonacci(int num, int a, int b)
 {
   if(num == 0)
   {
     return a;
   }
   else
   {
     return fibonacci(num - 1; b, a + b);
   }
 }

 int main()
 {
   int num = 15;
   int fib = fibonacci(num, 0, 1);
   printf("%dth fibonacci number = %d", num, fib);

 } 

Arrays

  • Hintereinander liegende Daten vom gleichen Typ
  • Größe kann nicht mehr verändert werden, muss bei Deklaration bekannt sein
  • Zugriff über [ ]
  • Deklaration:
    <typ> name[<size>];
  • Initialisiertes Array:
    <typ> name[] = {<value1>, <value2>, ...};
  • Zugriff:
    name[<index>] = <value>;

Beispiel

1int main() { 2 int fibo[5]; 3 fibo[0] = 1; 4 fibo[1] = 1; 5 fibo[2] = fibo[1] + fibo[0]; 6 fibo[3] = fibo[2] + fibo[1]; 7 fibo[4] = fibo[3] + fibo[2]; return 0; }
0x1000
0x1004
0x1008
0x100C
0x1010
0x1014
fibo   0x1000
0x1004
0x1008
0x100C
0x1010
0x1014
fibo   0x10001
0x1004
0x1008
0x100C
0x1010
0x1014
fibo   0x10001
0x10041
0x1008
0x100C
0x1010
0x1014
fibo   0x10001
0x10041
0x10082
0x100C
0x1010
0x1014
fibo   0x10001
0x10041
0x10082
0x100C3
0x1010
0x1014
fibo   0x10001
0x10041
0x10082
0x100C3
0x10105
0x1014

Variable-length-Arrays

  • GCC akzeptiert Arrays mit variabler Länge (C99 Standard)
  • Beispiel
    int size = numberOfHornsOnAUnicorn();
    int array[size];
    
  • Gefährlich zu verwenden, da diese Arrays am Stack liegen → normal 8MB maximale Größe, kann jedoch auch nur 64kB sein!
  • Ist das Array zu groß, stürzt das Programm ohne erkennbare Ursache ab
  • Have fun debugging!
  • Array als Funktionsparameter

    • Soll ein Array an eine Funktion als Parameter übergeben werden gibt es 3 Wege
    1. Array variabler Größe
      void foo(int bar[]) {
       [..]
      }
    2. Array fixer Größe
      void foo(int bar[8]) {
       [..]
      }
    3. Als Pointer
      void foo(int* bar) {
       [..]
      }

    Spezielle Arrays: Mehrdimensionale Arrays

    • Arrays können mehrere Dimensionen haben
    • 2-dimensionale Arrays:
      <typ> name[<rows>][<columns>];
    • Zugriff über Zeilen- und Spaltenindex:
      name[<row>][<column>] = <value>;
    • Beispiel Initialisierung:
      char matrix[3][3] = { {'A', 'B', 'C'}, {'D', 'E', 'F'},
            {'G', 'H', 'I'} };

    Mehr als 2 Dimensionen?

    • Ja, in C beliebig viele (so lange wir Speicher haben)
    • Schwer vorstellbar ab 4 Dimensionen, deshalb als Array von Arrays denken
    int cube[3][3][3];
    int hypercube[3][3][3][3];
    

    Beispiel: 4 Dimensionen

     int hypercube[3][3][3][3];
    

    Möglichkeit 1: 4D-Würfel

    Möglichkeit 2: Array von 3D Würfeln

    Mehrdimensionale Arrays als Parameter

    #include <stdio.h>
    
    void printMatrix3(char matrix[][3])
    {
      int y;
      for(y = 0; y < 3; y++)
      {
        printf("%c %c %c\n", matrix[y][0], matrix[y][1], matrix[y][2]);
      }
    }
    
    int main()
    {
      char matrix[3][3] = { {'A', 'B', 'C'}, {'D', 'E', 'F'},
          {'G', 'H', 'I'} };
      printMatrix3(matrix);
    }
    
    Achtung: Nicht mehr möglich als Pointer zu übergeben!

    Pointer

    • Pointer »zeigen« auf Variablen
    • Pointer enthält die Adresse einer Variable
    • Deklaration mit "*"
      <datentyp>* name;
    • Zugriff auf die Variable durch Dereferenzieren ebenfalls mit "*"
      *name = <value>;
    • Zuweisen einer Adresse durch den Adressoperator "&"
      name = &<variable>;

    Pointer und Pointee

    Pointer - Praxisbeispiel

    1int main() { 2 int a = 3; 3 int x = 2; 4 int* ptr = &a; 5 *ptr = 4; 6 ptr = &x; 7 *ptr = 8; return 0; }
    0x1000
    0x1004
    0x1008
    0x100C
    0x1010
    a   0x10003
    0x1004
    0x1008
    0x100C
    0x1010
    a   0x10003
    x   0x10042
    0x1008
    0x100C
    0x1010
    a   0x10003
    x   0x10042
    0x1008
    ptr   0x100C0x1000
    0x1010
    a   0x10004
    x   0x10042
    0x1008
    ptr   0x100C0x1000
    0x1010
    a   0x10004
    x   0x10042
    0x1008
    ptr   0x100C0x1004
    0x1010
    a   0x10004
    x   0x10048
    0x1008
    ptr   0x100C0x1004
    0x1010

    Call-by-Reference

    • Bei Funktionsaufruf nicht Variable, sondern Adresse übergeben
    • mehrere Rückgabewerte möglich
    • z.B. nützlich damit eine Funktion einen Wert sowie einen Fehlercode liefern kann

    Beispiel

    void getHourMinutes(int minutes, int* h, int* m)
    {
      *h = minutes / 60;
      *m = minutes % 60;
    }
    
    int main()
    {
      int hour = 0, minutes = 0;
      getHourMinutes(320, &hour, &minutes);
      printf("%d:%d\n", hour, minutes);
      return 0;
    }
    

    Strings - auch nur Arrays

    • String = Zeichenkette, »Text«
    • String ist nur ein Array von char (Zeichen)
    • Strings enden mit einem 0-Byte ('\0', nicht dem Zeichen 0!)
    • Deklaration (am häufigsten):
      char* text = "Hallo!";
    • Andere Varianten:
      char text[] = "Hallo!";
      char text[] = {'H', 'a', 'l', 'l', 'o', '!', '\0'};

    Strings: Vergleich

    • Funktion strcmp aus string.h verwenden
    • == funktioniert nicht, vergleicht nur die Speicheradressen
    •  char* str1 = "Hello";
       char* str2 = "World";
       if(strcmp(str1, str2) == 0)
       {
         // strings sind gleich
       }
       else
       {
         // strings sind ungleich
       }
      

    Strings: Zugriff auf einzelne Buchstaben

    • Zugriff durch Array-Schreibweise ([])
    • Erstes Zeichen hat Index 0!
    • Letztes Zeichen ist 0-Byte ('\0')
    •  char* str1 = "Hello";
       char c1 = str1[0]; // c1 = 'H'
       char c2 = str1[4]; // c2 = 'o'
       char c3 = str1[5]; // c3 = '\0'
      

    Strings: Funktionen

    • Weitere Funktionen die mit Strings arbeiten in string.h
    • http://www.cplusplus.com/reference/cstring/
    • Einbinden mit
      #include <string.h>
    • Nützliche Funktionen:
      strlen
      Länge des Strings (ohne 0-Byte!)
      strcpy
      String in einen anderen kopieren
      strcat
      Strings aneinanderhängen
      sprintf
      Wie printf, aber Ausgabe wird in String gespeichert

    Pipes

    Möglichkeit, die Ausgabe der einzelnen Befehle umzuleiten bzw. an andere Befehle weiterzuleiten.

    • Umleiten der Ausgabe in Datei
    • Standardeingabe von Datei lesen
    • Ausgabe als Eingabe für anderes Programm

    Pipes

    Ausgabe umleiten

    ./programm > ausgabe.txt

    Eingabe umleiten

    ./programm < eingabe.txt

    stderr umleiten

    ./programm 2> error.txt

    Pipes

    Beliebig kombinierbar

    ./programm < input.txt 1> output.txt 2> error.txt

    Stdout als stdin eines anderen programms

    ./programm | tail

    Returncode des letzten Programms

    echo $?

    Gruppenbeispiel 1: Besprechung / Livedemo

    Viel Erfolg beim Gruppenbeispiel!

    Abgabeschluss:

    • 10.11.2017 14:00:00 Uhr