next up previous contents
Next: Objektorientierter Ansatz Up: Vom information hiding zum Previous: Vom information hiding zum

Abstrakte Datentypen

Um abstrakte Datentypen in C verwirklichen zu können, müssen wir Zeiger benutzen. Eine Definitionsdatei unseres Beispieltyps STRING würde in C also wie folgt aussehen:

/*	( str_ih.h )  */

       #ifndef STR_IH_H
       #define STR_IH_H
       
        /* String-Definition : information hiding */
       
       struct String ;
       
       typedef struct String * STRING;
       
       void   setvalue  (STRING *s, const char *text);
            /* STRING muss lvalue sein */
       char * getvalue  (STRING s);
       void   cout      (STRING s);
       
       #endif

Der Datentyp STRING wird hier mit typedef als Zeiger auf eine zugrundeliegende Struktur String realisiert. Die Struktur von String bleibt unbekannt; sie wird nach außen nicht preisgegeben.

Auffallend sind vielleicht die Präprozessoranweisungen. Wir verwenden sie hier und im folgenden, um die Eindeutigkeit beim Import von Headerfiles zu gewährleisten. Das ermöglicht es uns, bedenkenlos include - Anweisungen verwenden zu können, ohne auf die genaue Hierarchie der importierten Dateien achten zu müssen; d.h. wurde die Datei bereits schon einmal importiert, so wird sie beim zweitenmal einfach ignoriert.

Der Zeiger auf STRING als Argument von setvalue ist unbedingt notwendig, da die Funktion neuen Speicherplatz für den STRING besorgt und diese Adresse zurückgeben muß!

Einschub:

Um nicht ständig Fehlerbehandlungen (bei Nullzeigern, Speicherallokierungsfehlern etc.) von Hand schreiben zu müssen, lagern wir sie aus in ein eigenes Modul:

/*      ( error.h )           */

      #ifndef ERROR_H
      #define ERROR_H
      
      
      #define NULLPTR "null pointer assignment\n"
      #define ALLOCMEM "cannot allocate memory\n"
      #define TYPE "type mismatch: wrong class\n"
      
      void fatalerror(char * mesg, int exitcode);
      
      #endif

Und der dazugehörige Code:

/*      ( error.c )         */

      #include <stdio.h>
      #include <unistd.h>
      #include "error.h"
      
      void fatalerror (char *m, int x)
      {
        fprintf ( stderr,"error : %s", m); 
        _exit(x);
      }

- Ende Einschub -

Unser Hauptprogramm soll folgendermaßen aussehen:

/*      ( main_ih.c )             */

      #include "str_ih.h"
      
        /* Hauptprogramm:  information hiding */
      
      int main()
      {
       STRING s;
       setvalue(&s,"Hallo\n");
       cout(s);
       printf("%s", getvalue(s));
       return 0;
      }

Nun benötigen wir noch die Implementierung:

/*      ( str_ih.c )               */

      #include "str_ih.h"
      #include "error.h"
      #include <stdio.h> 
      
      /* String-Implementation: information hiding */
      
      
      struct String {
          char * text;
      };
      
        
      void setvalue(STRING *s, const char *t)
      {
          if ( (s)==0)
            fatalerror(NULLPTR,1);
          *(s) = (struct String *) calloc (1, sizeof(struct String));
          if ( *(s) == 0 )
             fatalerror(ALLOCMEM,1);
         (*(s))->text=(char*)calloc(strlen(t)+1,sizeof(char));
          if ( (*(s))->text == 0) 
             fatalerror(ALLOCMEM,1);
          strcpy ( (*(s))->text,t);
      }
      
      void cout(STRING s)
      {
       if ( (s)==0 ) 
         return;
       fprintf(stdout,"%s",(s)->text);
      }
      
      char * getvalue(STRING s)
      {
        char *t;
        if ( (s)==0 || (s)->text==0)
          fatalerror(NULLPTR,1);
        t=(char*)calloc(strlen( (s)->text)+1,sizeof(char));
        if (t==0)
          fatalerror(ALLOCMEM,1);
        strcpy(t, (s)->text);
        return t;
      }

Die Struktur String enthält nur eine Komponente, nämlich den Zeiger auf den tatsächlichen Text. setvalue dient dazu, dem String einen Text zuzuweisen, getvalue dazu, um ihn wieder auszulesen, und cout gibt ihn auf stdout aus.

Ein Testlauf des Programms:

cn@cicero:/home/cn/seminar/aktuell/seminar/kap1 > /bin/ls
error.c	    main_ih.c   makefile    str_ih.h    str_oo.h    test2
error.h	    main_oo.c   str_ih.c    str_oo.c    test1       typescript
cn@cicero:/home/cn/seminar/aktuell/seminar/kap1 > make main_ih
gcc -c main_ih.c
gcc -c str_ih.c
gcc -c error.c
gcc -o main_ih main_ih.o str_ih.o error.o
cn@cicero:/home/cn/seminar/aktuell/seminar/kap1 > main_ih
Hallo
cn@cicero:/home/cn/seminar/aktuell/seminar/kap1 >



Christian Neher