Willkommen beim dritten Teil des C-Kurses!

Heute behandeln wir ein Thema, welches ihr mit besonderer Sorgfalt durcharbeiten solltet, da es euch immer wieder in C / C++ begegnen wird: Der Zeiger. Auf neu-Deutsch auch oft als Pointer bezeichnet.
 
 
Zeiger

Wie immer am Anfang ein kleines Beispielprogramm:
 

void main ( void ) 
{
    int zahl; 
    int *zeiger;

     
    zahl=5;
    zeiger=&zahl;
}

Wie wir am oberen Beispiel sehen können, zeichnet sich die Variable 'zeiger' dadurch aus, das sie mit einem Sternchen beginnt. Damit wird dem Compiler gesagt, das es sich hierbei um einen Zeiger handelt. Bevor ich nun in ewige Verdammnis gestürzt werde, weil ich immer noch nicht sagte, was ein Zeiger ist: Ein Zeiger beinhaltet nicht einen Variablenwert, sondern zeigt nur auf die Adresse, wo der Variablenwert hinterlegt ist.

Arbeiten wir unser Beispiel ab, dann wird auch am ehesten die obere Darstellung, was ein Zeiger ist, klar.

Wir erzeugen die Variable 'zahl' und den Zeiger 'zeiger'. Der Variablen 'zahl' wird der Wert 5 zugeordnet. Der Zeiger 'zeiger' wird die Adresse der Variable 'zahl' zugewiesen. Dies geschieht durch den Adressoperator & !

Grundsätzlich wird ein Variable durch einen vorangestellten Stern als Zeiger deklariert!

Bsp.:
 

int *pointer1;

float *pointer2;

Der Vorteil von Zeigern ist der, das in ihnen nur eine Adresse und keine Variablen stehen. Dadurch sind sie extrem flexibel und schnell. Zu beachten ist: Der Zeiger muß denselben Datentyp besitzen, auf den er zeigt! Folgendes funktioniert also nicht:
 

/* DIESES PROGRAMM LAEUFT SO NICHT !!! */
void main ( void
{
    int zahl=5; 
    float *zeiger;

     
    /* in der Folgezeile liegt der Fehler! */
    zeiger=&zahl; 
}

Damit wir auch Vorteile aus der Benutzung von Zeigern ziehen können, wollen wir uns einmal anschauen, was man alles mit Zeigern machen kann. Da dies im übrigen sehr viel ist, werden wir uns hier mit dem grundlegenden beschäftigen.

Zugriff auf den Variablenwert, auf den ein Zeiger zeigt erfolgt mittels des *-Operators! Man bezeichnet ihn auch als Inhalts-Operator

Aber Vorsicht: NICHT MIT DEM MULTIPLIKATOR VERWECHSELN! Das sind zwei verschiedene Operatoren!

Der Compiler entscheidet anhand des Zusammenhangs, ob es sich um einen Zeiger-Operator oder um eine Multiplikation handelt.
 

/* Beispiel für die Anwendung eines Zeigers */ 
#include <stdio.h>
void main ( void
{
    int zahl=5; 
    int *zeiger;

     
    zeiger=&zahl;
    printf("\nZahl = %d \n",zahl);

     
    *zeiger=10;
    printf("\nJetzt ist Variable Zahl = %d \n",zahl); 
}

Starten wir nun das Programm, so erhalten wir als Ausgabe:
 

Zahl = 5

Jetzt ist Variable Zahl = 10

Wie immer eine Erläuterung, was passiert ist:

Dem Zeiger 'zeiger' wurde die Adresse der Variable 'zahl' zugewiesen. Somit steht in 'zeiger' die Ardresse, wo im Speicher die Variable 'zahl' steht. Als erstes geben wir unsere Variable 'zahl' aus.

Nun wird in die Adresse ( ! ) , die in 'zeiger' gespeichert ist, der Wert 10 geschrieben! Dadurch, daß in dieser Adresse der Wert der Variable 'zahl' steht, schreiben wir in die Variable 'zahl' den Wert 10 hinein.

Diesen Effekt sehen wir, wenn wir das Programm starten: Erst steht in der Variablen 'zahl' der Wert 5 und nach dem überscheiben der Wert 10.

Man sagt auch: Durch einen Zeiger wird ein Objekt referenziert.

Keine Panik :-) In diesem Satzt steht nichts anderes, als das der Zeiger auf die Variable zeigt.
Wenn man ehrlich ist,klingt alles immer noch recht theoretisch, aber alles kann durch etwas Übung klarer werden.

Nein, wir steigen nicht in den Gärungsprozeß, sondern in ein weiteres Beispiel ein :-)
 

#include <stdio.h>
void main (  void
{
    /* Variablen vom Typ Integer */ 
    int a=1 , b=2 ; 

     
    /* Zeiger auf eine Integervariable */
    int *zeiger; 

     
    /* 'zeiger' zeigt auf a */
    zeiger = &a ;

     
    /* 'b' wird mit dem Wert von 'a' geladen. */
    b = *zeiger ; 

     
    /* 'a' wird mit dem Wert 2 geladen */
    *zeiger = 2 ; 
}

Es ist wichtig, daß die oberen Beispiele verstanden werden!

Klasse! Doch Zeiger müssen doch zu was gut sein, oder ? Den wahren Nutzen der Zeiger können wir erkennen, wenn wir zum nächsten Lernabschnitt, den Feldern, oder auf neu-Deutsch Arrays , kommen. Doch zu beginn das Grundlegende:
 
 
Felder

Felder, also Gruppen oder Aneinanderreihungen von Variablen eines Typs kann man als Felder auffassen.
 

int feld [ 10 ] ;

erzeugt also ein Feld von 10 Elementen des Typs Integer.
 
 

0 1 2 3 4 5 6 7 8 9

 
Die Elemenente sind feld[ 0 ] .... feld[ 9 ] . 

Richtig bemerkt, die Feldindizes fangen bei 0 an.
Schauen wir mal, was man mit Zeigern und Feldern alles machen kann:
 

#include <stdio.h>
void main ( void ) 
{
    /* Das Feld mit 10 Elementen wird erzeugt */ 
    int feld [ 10 ] ; 

     
    /* Variable vom Typ Integer wird erzeugt */ 
    int var; 

     
    /* Ein Zeiger auf Integer-Werte wird erzeugt */
    int *zeiger; 

     
    /* 'zeiger' zeigt auf das erste Element von 'feld' */
    zeiger = &feld [ 0 ] ;

     
    /* var enthält den Wert von 'feld [ 0 ]' */
    var = *zeiger; 

     
    /* var enthält den Wert von 'feld [ 2 ]' */
    var = *( zeiger + 2 );

     
    /* var enthält den Wert von 'feld [ 2 ]' */ 
    var = feld [ 2 ] ; 
}

An diesem Beispiel ist zu sehen, das
 

zeiger = &feld [ 0 ];

var = *( zeiger + 2 );

und
 

var = feld [ 2 ];

gleichwertig sind. Wieso ?

Dazu schauen wir uns mal die erste Zuweisung genauer an.

'zeiger' wird mit der Adresse von 'feld [ 0 ]' geladen, zeigt also auf 'feld [ 0 ]'.Jetzt kommst: Die Adresse von 'zeiger' wird um 2 Elemente vom Typ 'zeiger' erhöht. Damit zeigt der Ausdruck auf das zweite Feldelement, also auf 'feld [ 2 ]'. Nun wird der Inhalt von 'feld [ 2 ]' in 'var' gespeichert.

Damit sind beide Ausdrücke gleichwertig.

Bisher hatten sich sicher viel gefragt, wie man ganze Zeichenketten oder auch Sätze in Variablen speichern kann. Wer schon andere Programmiersprachen kennt, fragt sich, ob es nicht so etwas wie Strings, also Variablentypen für Zeichenketten, gibt. Um hier mit einem Zitat zu antworten: Im Prinzip schon, in der Praxis nein :-)
 
 
 
Strings und deren Erzeugung

Es gibt zwei prinzipielle Arten Strings zu generieren.
 

/* String als Feld */ 

char zeichen [ ] = "hallo";

oder
 

/* String als Zeiger */ 

char *zeichen = "hallo";

Was machen nun beide Anweisungen ?

Wird ein String durch ein Feld erzeugt, so ist das generierte Feld gerade so groß, damit der String hineinpaßt. Bei genauerer Betrachtung ist das Feld aber 5+1 Zeichen groß.
Wieder ein Mysterium von C ? 5 Elemente für die 5 Buchstaben von 'hallo' - OK , wo aber kommt das 6. Element her ?

Dazu müssen wir uns anschauen, wie Zeichenketten intern gespeichert werden.
Damit das System weiß, das der String zu Ende ist steht hinter der Zeichenkette immer noch ein '\0'. Das ist ein sogenanntes Nullzeichen.
 
 

"hallo" wird intern dargestellt durch
h a l l o \0

Wird ein String durch einen Zeiger erzeugt, so wird irgendwo im Speicher,der. Der Zeiger zeigt auf das erste Element des Strings. Auch hier wird mit einem Nullzeichen abgeschlossen.

Auch hier ein kleines Beispiel:
 

/* Ein kleines Beispiel für Strings */ 
#include <stdio.h>

 
void main ( void )
    char text1 [ ] = "Jetzt haben wir sogar Strings\n\n";
    char *text2 = "Jetzt auch als Zeiger\n\n";

     
    /* hier wird die Feld-Variante ausgegeben */
    printf ("%s ",text1);

     
    /* hier wird die Zeiger-Variante ausgegeben */ 
    printf ("%s ",text2);
}

Als kleine Übung versuchen sie zu erklären, was passiert, wenn sie folgendes kleines Programm starten würden. Mit dem bisher gelernten, dürfte es zu schaffen sein:
 

/* Übungsaufgabe für Strings */ 
#include <stdio.h>

 
void main ( void )
{
    char *text = "Dies ist ein Test\n\n";

     
    printf ("%s ",(text + 5) );
}

 

Soviel erstmal zum Thema Zeiger, die Erste. Wir werden uns später weiterführend mit Zeigern beschäftigen. Aber da alles in kleinen verstehbaren Portionen zu genießen ist, soll es diesmal genügen.

Die Zeiger sind ein wesentlicher Bestandteil der Sprache C ! Es sollte also auch nicht davor zurückgeschreckt werden, bei Unklarheiten mir eine Mail zu schreiben, bzw. eine Nachricht im Pinboard unter C-Kurs / C-Kurs-Talk zu schreiben.
 
 
 
 
 
...das Obligatorische

Autor: Sebastian Cyris \ PCD Bascht

Dieser C-Kurs dient nur zu Lehrzwecken! Eine Vervielfältigung ist ohne vorherige Absprache mit dem Autor verboten! Die verwendete Software unterliegt der GPL und unterliegt der Software beiliegenden Bestimmungen zu deren Nutzung! Jede weitere Lizenzbestimmung die der benutzten Software beiliegt, ist zu beachten!