ein Kapitel zurück                                           ein Kapitel weiter

Dieser Teil richtet sich an den Fortgeschrittenen User und soll demonstrieren wie man mit Hilfe des untypisierten void - Zeiger als Parameter einen Zeiger beliebigen Types übergeben kann. Weiterhin werden sie anhand eines Programms sehen wie wir mehrere Datentypen, mit einer Funktion zusammenpacken. Genauer gesagt wollen wir gemischte Objekte wie z.B. Strings UND Integer zusammen in das gleiche Array stecken können, wie dies bei Perl Standardmäßig möglich ist.

Folgende Aufgabe wollen wir lösen.....

'x', "String für ZS"
"String für SL" , 123456
1.2345, "String für DSD", 6.54321
55 , "String für IS"


Wir haben hier 4 Zeilen mit gemischten Datentypen. Für jede dieser Zeile wollen wir mit Hilfe einer Funktion einlesen und in einer für den Datentypen bestimmte Funktion, bearbeiten.

Zur Demonstration reicht die Ausgabe mittels printf aus. Sie können das ganze gerne selbst mal probieren bevor sie mit dem folgenden Programm fortfahren. Als erstes benötigen wir nun einen neuen Datentypen für unser Array von verschiedenen Objekten......

typedef struct MISC
{
   int tag;    /*Tagwert siehe enum*/
   void *obj;    /*Adresse des Objektes*/
   int (*func)();   /*Adresse der Funktion die Ausgeführt wird*/
}MISC;


Wir nennen unseren neuen Datentypen einfach MISC . Folgende Bedeutungen haben die Werte in der Struktur. int tag dient als Kennung für unser gemischtes Array. Die Tags und deren Bedeutung definieren wir mit Hilfe von enum..........

/*Kennung :
ZS_TAG für Zeichen&Sring | SL_TAG für String&Long
DSD_Tag für Double&String&Double | IS_TAG für Integer&String*/

enum{INVALID_TAG, ZS_TAG, SL_TAG, DSD_TAG, IS_TAG}TAG;


void *obj nutzen wir für die Adresse wo sich der Inhalt für das gemischte Array befindet. Einem typenlosen void-Zeiger als Parameter kann man jeden beliebigen Zeiger übergeben. Und das wollen wir ausnutzen.
In int(*func)() befindet sich die Adresse einer Funktion für die die Weiterverarbeitung des Datentypes. In unserem Fall wird nur der Inhalt des Datentypes ausgegeben.

Als müssen wir mehrer Objekte des Datentypes MISC festlegen. Man spricht dabei vom Verkapseln. Nehmen wir Beispielsweise den Datentypen SZ...........

typedef struct ZS
{
   char data;
   char zs[80];
}ZS;


...der ein einzelnes char-Zeichen und einen String von 80 Zeichen aufnehmen kann. Die weiteren Datentypen sind im Programm dokumentiert.

Jetzt benötigen wir noch Funktionen die den Inhalt unseres gemischten Arrays auf dem Bildschirm ausgeben. Wieder als Beispiel das Objekt ZS für Zeichen und String..........

int zs(ZS *char_string)
{
   printf("Funktion für Zeichen und String aufgerufen\n");
   printf("Zeichen : %c , String : %s\n",char_string-
   return 0;
}


Desweiteren benötigen wir noch eine Funktion in der wir unsere gemischten Datentypen wie z.B. ZS oder SL in unser gemischtes Array MISC packen....

void pack(MISC *bag, int nr, int Tag, void *adress, int (*function)())
{
   bag[nr].tag = Tag;
   bag[nr].obj = adress;
   bag[nr].func = function;
}


Die einzelnen Parameter finden sie im Programm beschrieben. Somit definieren wir jetzt unseren Datentypen ZS wie folgt...

ZS za = {'x', "String für ZS" };

Jetzt benötigen wir noch unsere Definition des gemischten Arrays.....

MISC Pack[4] ={0};

Und um diesen in unser gemischtes Array MISC zu packen müssen wir nur noch folgenden Funktionsaufruf durchführen....

pack(Pack, 0, ZS_TAG, &za, tag_func[ZS_TAG]);

Pack ist der Name des Arrays; 0 ist der Index (MISC Pack[0]); &za ist die Adresse des Inhaltes unseres gemischten Arrays; tag_func[ZS_TAG] ist der Funktionsaufruf für die Ausgabe des Datenobjektes. In tag_func[] haben wir die einzelnen Funktionen mit Hilfe von Funktionszeigern definiert....

int (*tag_func[])() = {dummy,zs,sl,dsd,is};

Die Ausgabe unserer gemischten Arrays erfolgt durch.....

(*Pack[i].func)(Pack[i].obj);

(*Pack[i].func) ist unser Funktionsaufruf und (Pack[i].obj) ist der Parameter und Inhalt den wir an die Funktion übergeben. Wollen wir uns nun das ganze Programm ansehen....

/*Download:zeiger1.c*/
#include <stdio.h>

typedef struct MISC
{
int tag; /*Tagwert siehe enum*/
void *obj; /*Adresse des Objektes*/
int (*func)(); /*Adresse der Funktion die Ausgeführt wird*/
}MISC;

/*Kennung : ZS_TAG für Zeichen&Sring | SL_TAG für String&Long DSD_Tag für Double&String&Double | IS_TAG für Integer&String*/
enum{ INVALID_TAG,ZS_TAG,SL_TAG,DSD_TAG,IS_TAG}TAG;

/*ZS für Zeichen & String*/
typedef struct ZS
{
char data;
char zs[80];
}ZS;

/*SL für String & Long*/
typedef struct SL
{
char sl[80];
long data;
}SL;

/*DSD für Double & String & Dounble*/
typedef struct DSD
{
double data_a;
char dsd[80];
double data_b;
}DSD;

/*IS für Integer & String*/
typedef struct IS
{
int data;
char is[80];
}IS;

/*Packt verschieden Datenobjekte zusammen. MISC *bag -> Struktur unseres Datenobjektes int nr -> Indexzähler für gemischtes Array int Tag -> Tagkennung (siehe enum) void *adress -> Adresse des gemischten Objektes int (*function)() -> Adresse der Funktion */
void pack(MISC *bag, int nr, int Tag, void *adress, int (*function)())
{
bag[nr].tag = Tag;
bag[nr].obj = adress;
bag[nr].func = function;
}

int zs(ZS *char_string)
{
printf("Funktion für Zeichen und String aufgerufen\n");
printf("Zeichen : %c , String : %s\n",char_string->data,char_string->zs);
return 0;
}

int sl(SL *str_long)
{
printf("Funktion für String und Long aufgerufen\n");
printf("String : %s , Long : %d\n",str_long->sl,str_long->data);
return 0;
}

int dsd(DSD *dstrd)
{
printf("Funktion für Double String Double aufgerufen\n");
printf("Double : %f , String : %s , Double : %f\n",
dstrd->data_a,dstrd->dsd,dstrd->data_b);
return 0;
}

int is(IS *intstr)
{
printf("Funktion für Integer und String aufgerufen\n");
printf("Integer : %d , String : %s\n",intstr->data,intstr->is);
return 0;
}

int dummy()
{
return 0;
}


int main()
{
ZS za = {'x', "String für ZS" };
SL sa = {"String für SL" , 123456 };
DSD da = {1.2345, "String für DSD", 6.54321};
IS ia = {55 , "String für IS"};
int (*tag_func[])() = {dummy,zs,sl,dsd,is};

MISC Pack[4] ={0};
int i;

pack(Pack, 0, ZS_TAG, &za, tag_func[ZS_TAG]);
pack(Pack, 1, SL_TAG, &sa, tag_func[SL_TAG]);
pack(Pack, 2, DSD_TAG,&da, tag_func[DSD_TAG]);
pack(Pack, 3, IS_TAG, &ia, tag_func[IS_TAG]);

for(i=0; i<4; i++)
(*Pack[i].func)(Pack[i].obj);
return 0;
}

Zugegeben das Programm mag etwas sinnlos erscheinen aber es zeigt relativ einfach wie man verschiedene Objekte in das selbe Array packen kann. Das ganze müsste man natürlich noch mit dynamischen Speicher machen. Wollen wir uns diese Beispiel nochmals anhand von MISC Pack[0] bildlich betrachten..........



Dies Bild stellt den ganzen Verlauf natürlich nur vereinfacht da.

ein Kapitel zurück          nach oben           ein Kapitel weiter


© 2001,2002 Jürgen Wolf