Sprachen / C / Strukturen

Strukturen

Einführendes Beispiel

Wenn du bereits objektorientiert programmiert hast, wirst du einige Gemeinsamkeiten zwischen Strukturen und Klassen erkennen. Strukturen ermöglichen eine strukturierte Zusammenfassung von Variablen.

Strukturen/strukturen
#include 

struct zwei_d
{
  int x;
  int y;
};

struct drei_d_koon
{
  struct zwei_d xundy;
  int hoehe;
}
/* Dies ist die Instanz (Deklaration) von drei_d_koon */
koord_1; 

struct anyChars
{
  char q;
  char w;
} 
/* Die Instanz wird gleichzeitig initialisiert. */
zeichen = {'?','#'}; 
    
int main()
{ 
  koord_1.xundy.x = 2;
  koord_1.xundy.y = 5;
  koord_1.hoehe = 20;
    
  struct zwei_d nurXY; 
  nurXY.x = 222;
  nurXY.y = 111;

  printf("koord_1:  x = %d, y = %d, h = %d\n",
    koord_1.xundy.x, koord_1.xundy.y,koord_1.hoehe );
            
  printf("nurXY:    x = %d, y = %d\n",
    nurXY.x, nurXY.y);
           
  printf("zeichen:  q = %c, w = %c\n",
    zeichen.q, zeichen.w);
    
  return 0;
} 
      
koord_1:  x = 2, y = 5, h = 20
nurXY:    x = 222, y = 111
zeichen:  q = ?, w = #

Anmerkungen: Nach der Strukturdefinition muss ein Semikolon folgen. Bei der Initialisierung von Strukturen muss die Initialisierungsliste die gleiche Reihenfolge der Variablen haben, wie bei der Definition.

Wenn Strukturen definiert werden, können sie gleichzeitig deklariert werden (drei_d_koon) oder erst später (zwei_d => struct zwei_d nurXY). Es ebenfalls mögliche eine Strukturdefinition-, Deklaration- und Initialisierung in einem Rutsch vorzunehmen. Strukturen können beliebig tief verschachtelt werden. Wie in strukturen.c erkennbar ist, kann der Zugriff auf die Strukturvariablen über die Punktnotation erfolgen.

Strukturen und Zeiger

Strukturen/strukturen_und_zeiger
#include 

struct adresse
{
  char *stadt;
  char *strasse;
  int hausnummer;
} zuhaus = {"Bremen","Ceeweg",4};

int main()
{
  struct adresse *z_zuhaus = &zuhaus ;
  printf("direkt   : stadt = %s, strasse = %s, hausnummer = %d\n",\
    zuhaus.stadt, zuhaus.strasse, zuhaus.hausnummer);
  printf("indirekt1: stadt = %s, strasse = %s, hausnummer = %d\n",\
    (*z_zuhaus).stadt, (*z_zuhaus).strasse, (*z_zuhaus).hausnummer);
  printf("indirekt2: stadt = %s, strasse = %s, hausnummer = %d\n",\
    z_zuhaus->stadt, z_zuhaus->strasse, z_zuhaus->hausnummer);
    
  return 0;
} 
      
direkt   : stadt = Bremen, strasse = Ceeweg, hausnummer = 4
indirekt1: stadt = Bremen, strasse = Ceeweg, hausnummer = 4
indirekt2: stadt = Bremen, strasse = Ceeweg, hausnummer = 4

Es natürlich auch möglich Zeiger in auf Strukturen zu deklarieren. Der Zugriff auf die Strukturelemente von diesen Zeigern wird durch zwei syntaktische Gebilde ermöglicht: (*z_zuhaus).strasse) dereferenziert den Zeiger, aber der Derefenzierungsoperator und der Zeiger müssen in Klammern eingeschlossen werden, da der Punktoperator eine höhere Priorität besitzt. Es ist zwar eine soziale Norm den Elementverweisoperator zu verwenden (z_zuhaus->strasse) (der zum vorigen Ausdruck äquivalent ist), weil die Schreibweise angeblich unleserlich und umständlich ist. Ich bin jedoch anderer Meinung: Der Elementverweisoperator fügt der C-Syntax einen weiteren unnötigen Konstrukt hinzu. Es wird verschleiert, dass hier eine Dereferenzierung, Klammerung aufgrund der Operatorpriorisierung und Punktnotation auf den dereferenzierten und eingeklammerten Strukturzeiger vorgenommen wird. Syntaktischer Zucker den keiner braucht. Insbesondere neigen Anfänger dazu, diesen Operator zu verwenden ohne zu wissen, was dahinter steckt, was für das Erlernen der Sprache nicht förderlich ist.

Arrays von Strukturen

Strukturen/arrays_von_strukturen
#include 
  
struct zwei_d 
{
  int x;
  int y;
} koord[2] = { {3,7},
               {1,9}
             };
            
int main(void)
{
  for(int i = 0; i < sizeof(koord) / sizeof(koord[0]);i++)
    printf("x = %d, y = %d\n", koord[i].x, koord[i].y );
  
  return 0;
} 
      
x = 3, y = 7
x = 1, y = 9

Das letzte Beispiel zeigt, wie Arrays von Strukturen und vor allem wie diese in einer Schleife durchiteriert werden können. Da sizeof() lediglich die Größe in Byte ermittelt, ist es ratsam diese Ziffer durch die Größe eines Elementes zu dividieren, um so die Anzahl der Elemente im Array zu ermitteln.

Struct als Funktionsparameter

Strukturen/struct_als_funktionsparameter
#include 
#include 

struct person 
{
  int alter;
  char name [20];
} 
per_A;

void accountname(struct person p);
void accountname2(struct person *p);

int main(void)
{    
  printf("\nWie heißen sie?\n");
  scanf("%s", per_A.name);
  printf("\nWie alt sind sie?\n");
  scanf("%d", &per_A.alter);
  accountname(per_A);
  printf("\n\t\tIch bedanke mich bei ihnen %s.",per_A.name);
  accountname2(&per_A);
  printf("\n\t\tIch bedanke mich bei ihnen %s.\n",per_A.name);

  return 0;
}

void accountname(struct person p)
{
  printf("\nIhr neuer Accountname lautet %s%d.",\
  p.name, p.alter);
  strcpy(p.name, "Dumpfbacke");
}

void accountname2(struct person *p)
{
  printf("\noder ihr neuer Accountname lautet %d%s.",\
    (*p).alter, (*p).name) ;
  strcpy((*p).name, "Dumpfbacke");
} 
      
Wie heißen sie?
Simba

Wie alt sind sie?
12

Ihr neuer Accountname lautet Simba12.
                Ich bedanke mich bei ihnen Simba.
oder ihr neuer Accountname lautet 12Simba.
                Ich bedanke mich bei ihnen Dumpfbacke.

Anmerkung: Beachten sie die unterschiedliche Syntax der Funktion scanf() Dieser Funktion werden Adressen übergeben und weil Zeiger bereits Adressen enthalten, wird der Adressoperator nicht mit angegeben. Für Grunddatentypen ist dies jedoch notwendig (&amp;per_A.alter).

Es gibt zwei Möglichkeiten Strukturen Funktionen zu übergeben (wie bei jeder Datenstruktur): Entweder by Reference oder by Value. Beide Methoden haben ihre Vor- und Nachteile: Der Vorteil von passing by Value ist der, dass die Funktion auf den Funktionsparameter keine Seiteneffekte ausübt. Es wird eine Kopie erstellt und sobald die Funktion terminiert, verschwindet die Kopie ins Nirwana. Doch genau dieser Sachverhalt kann auch gleichzeitig ein Nachteil sein: Manchmal ist es wünschenswert den Wert in der Funktion zu verändern, damit man nicht die Kopie returnieren und neu zuweisen muss, um die Manipulation dauerhaft zu sichern. Der andere Nachteil ist, dass Funktionsaufrufe teuer sind. Die ganze Kopie der Struktur muss übergeben werden. Mit passing by Reference wird nur der Zeiger übergeben.

Verkettete Listen

Strukturen/verkettete_listen
#include 
#include 

/*a programming language struct.*/
struct lang
{
  char *name;
  char *para;
  int  jahr;
  struct lang *next;
};

void fill_lang(struct lang *, char [], char [], int);
void prnt_whl_lst(struct lang *);

/*main creates two structs, fills them and "ties" them together.*/
int main()
{
  struct lang *c = (struct lang *) malloc(sizeof(struct lang));
  fill_lang(c,"C","imperativ",1972);
  struct lang *java = (struct lang *) malloc(sizeof(struct lang));
  fill_lang(java,"Java","objektorientiert",1995);
  (*c).next = java;
  prnt_whl_lst(c);
  return EXIT_SUCCESS;
}

/*fill a list with a name, with the paradigma and the year.*/
void fill_lang (struct lang *l, char *n, char *p, int j)
{
  (*l).name = n;
  (*l).para = p;
  (*l).jahr = j;
}

/*prints the whole list.*/
void prnt_whl_lst(struct lang *head)
{
  struct lang *iterator = head;
  puts("\nAlle Listenelemente werden ausgegeben.");
  for(;iterator != NULL; iterator = (*iterator).next)
  {
    printf("\nName: %s\n", (*iterator).name);
    printf("Paradigma: %s\n", (*iterator).para);
    printf("Erscheinungsjahr: %d\n", (*iterator).jahr);
  }
} 
      
Name: C
Paradigma: imperativ
Erscheinungsjahr: 1972

Name: Java
Paradigma: objektorientiert
Erscheinungsjahr: 1995
Autor: behalx
Erstellt am: 20.01.2010
Zuletzt modifiziert: 21.04.2011
Lizenz:
Creative Commons License