C-Tutorial Kapitel 8
Aus Wirthi's Wiki
| C-Tutorial | |
|---|---|
| Allgemeines Kapitel 1 (Einleitung) Kapitel 2 (Blöcke) Kapitel 3 (Daten) Kapitel 4 (Kontrollanweisungen) Kapitel 5 (Ein- und Ausgabe) Kapitel 6 (Unterprogramme) Kapitel 7 (Felder und Strukturen) Kapitel 8 (Zeiger) | |
|
Dieses 8. Kapitel beschäftigt sich mit weiterführenden Themen wie Zeiger.
[bearbeiten] Zeiger
Zeiger sind für die C-Programmierung ein wichtiges Thema. Bis jetzt haben wir sie an einigen Stellen bereits verwendet, wenn auch nur verdeckt.
Eine Variable beschreibt zwei Fakten: zum einen den Datentyp des in ihr enthaltenten Wertes, zum anderen die Postition im Hauptspeicher, wo dieser Wert gespeichert ist. Die Variable "zeigt" also gewissermaßen in den Speicher. Im Prinzip ist also jede Variable ein Zeiger. Wenn man jedoch mit normalen Variablen arbeitet, merkt man davon nichts. Die Verwaltung der Adressen verläuft im Hintergrund, so dass weder der Benutzer noch der Programmierer etwas damit zu tun haben.
Allerdings ist es manchmal hilfreich, direkt mit Speicherstellen und damit mit Zeigern zu arbeiten. Wie man damit arbeitet und was das für Vorteile bringt, erfahren Sie in diesem Abschnitt.
Ein Zeiger ist im Prinzip eine (int-)Variable. In ihr ist jedoch kein zu verarbeitender Wert gespeichert, sondern eine Hauptspeicher-Adresse. Diese Adresse ist natürlich ebenfalls eine Zahl, allerdings keine sinnvoll lesbare; Sie gibt lediglich an, an welcher Position im Hauptspeicher die tatsächlich zu verwendenden Daten gespeichert sind. Eine Zeigerdeklaration schaut daher auch ähnlich einer Variablendeklaration aus. Zuerst wird der Datentyp des Zeigers geschrieben, dann ein Leerzeichen, anschließend kommt ein Stern, dann der Name des Zeigers und zum Schluss noch der Strichpunkt.
int *zeigerAufInt;
Um diesem Zeiger nun einen Wert (eine Adresse) zu zu weisen, müssen Sie die Adresse einer bestehenden Variablen in Erfahrung bringen. Dies geschieht mittels einer normalen Zuweisung und dem Adressoperator &.
zeigerAufInt = &intVariable;
Der Zeiger zeigerAufInt enthält nun die Adresse der Variablen intVariable. Nun können Sie mit diesem Zeiger (fast) wie bisher mit der gewöhnlichen Variablen arbeiten. Sie können Werte zuweisen, Werte auslesen, etc. Allerdings gibt es einen Unterschied. Wenn Sie jetzt mit dem Wert des Zeigers direkt rechnen - etwa "zeigerAufInt = zeigerAufInt + 1;" - würden Sie den Wert des Zeigers erhöhen, also die Adresse, auf die er zeigt. Das ist aber meist nicht das, was Sie tatsächlich wollen.
Es gibt aber eine Möglichkeit, auf den Wert der Speicherstelle zuzugreifen, auf die ein Zeiger zeigt: der Operator *. Dieser macht aus einem Zeiger eine normale Variable, wie folgendes Beispiel zeigt:
(*zeigerAufInt) = 12;
Es geschieht nun folgendes: "12" wird nun der Speicherstelle zugewiesen, auf die zeigerAufInt zeigt. Es wird dabei nicht der Zeiger ansich verändert, sondern eben die Speicherstelle, auf die er hinzeigt. Dies ist in unserem Beispiel eine int-Variable.
Nun nochmal alle Anweisungen in ein Beispiel verpackt:
#include <stdio.h>
void main(void)
{
int Zahl = 5;
int *Zeiger;
Zeiger=&Zahl;
*Zeiger=12;
printf("%d = %d", Zahl, *Zeiger);
}
- Erklärung
- Es wird eine int-Variable und eine int-Zeiger angelegt. Die Variable erhält den Wert 5.
- Der Zeiger wird so verändert, dass er auf die int-Zahl zeigt.
- Nun wird dem Inhalt des Zeigers (der Wert, auf den er zeigt) der Wert 12 zugewiesen. Damit trägt die int-Variable den Wert 12!
- Anschließend werden beide Werte, der Wert der int-Variablen und der Wert der Speichererstelle, auf die der Zeiger zeigt, ausgegeben. Die beiden haben den gleichen Wert 12, obwohl der int-Variablen nie ein anderer Wert als 5 zugewiesen wurde.
[bearbeiten] Zeiger als Parameter
Wenn Sie ein Unterprogramm aufrufen, können Sie diesem Parameter übergeben, aber keine Werte zurückgekommen. Eine Ausnahme davon ist natürlich der Funktionswert bei Funktionen. Dies hat einen guten Grund: Sie haben vorher gehört, dass Variablen eigentlich nur eine schöne Umschreibung für eine Speicherstelle sind. Sie beschreiben eigentlich eine Adresse im Speicher. Wenn Sie diese Adresse an ein Unterprogramm übergeben, macht C standardmäßig folgendes: es stellt fest, um was für einen Datentyp es sich handelt, legt eine lokale Variable dieses Types an (den Namen dieser Variablen legen Sie in der Parameterlister des Unterprogrammes fest!) und kopiert die Werte der übergebenen Variablen in diese neue Variablen. Es werden dabei wirklich die Werte, nicht die Adressen kopiert.
Wenn im Unterprogramm nun die Werte dieser lokalen Variablen verändert werden, ändert dies nichts an den Werten im aufrufenden Programm. Es werden ja lokale Kopien veränder. Sobald das aufgerufene Unterprogramm wieder beendet wird, sind auch die Kopien verschwunden. Die Originale (die als Parameter übergebenen Werte) wurden nie verändert.
Doch was ist, wenn Sie die übergebenen Parameter in Unterprogrammen verändern möchten und diese Änderung auch im aufrufenden Programm wirksam bleiben sollen? Ganz einfach, Sie verwenden Zeiger. Der Computer legt dann immer noch eine lokale Kopie der übergebenen Variablen an. In dieser Kopie steht allerdings kein Wert, sondern die Adresse einer Varaiblen, auf die Sie zugreifen können. Und dabei ist es ja egal, ob es sich dabei um den originalen Zeiger oder um eine Kopie davon handelt: beide zeigen auf die gleiche Speicherstelle!
Dieses System haben Sie übrigens schon kennen gelernt: beim Aufruf der Prozedur scanf wird ein Zeiger übergeben. Mittlerweile wissen Sie ja, dass man mit dem Adress-Operator & die Adresse einer Variablen erhält. Würden Sie scanf eine gewöhnliche Variable übergeben, dann könnte es zwar einen Wert von der Tastatur einlesen und diesen in die lokale Kopie ihres Parameters schreiben, allerdings würden Sie den Wert nie erhalten. Dies kann nur mittels Zeiger gemacht werden:
#include <stdio.h>
void erhoehe(int *zeiger)
{
*zeiger=*zeiger+1;
}
void main(void)
{
int Zahl;
printf("Zahl eingeben: ");
scanf("%d",&Zahl);
erhoehe(&Zahl);
printf("\nDie erhoehte Zahl lautet: %d\n",Zahl);
getch();
}
- Erklärung
- Das Unterprogramm erhoehe übernimmt einen Zeiger. Anschließend erhöht es den Wert der Speicherstelle, auf die der Zeiger zeigt, um eins. Diese Änderung ist damit auch im aufrufenden Programm sichtbar.
[bearbeiten] Felder und Zeiger
Das obenstehende (Zeiger als Parameter) gilt prinzipiell auch für Felder. Wenn jedoch Felder als Parameter übergeben werden, handelt es sich dabei bereits um Zeiger. Daher müssen Sie bei Feldern (und natürlich auch bei Strings) nicht explizit mittels & einen Zeiger erzeugen. Es genügt, einfach das Feld zu übergeben. Im Unterprogramm können Sie darauf ganz normal zugreifen:
#include <stdio.h>
void plus1(char feld[3])
{
feld[0]=feld[0]+1;
feld[1]=feld[1]+1;
feld[2]=feld[2]+1;
}
void main(void)
{
char fe[3];
int i;
for (i=0;i<3;i++)
{
printf("\nBitte %d eingeben: ",i);
scanf("%d",fe[i]);
}
plus1(fe);
for (i=0;i<3;i++) printf("\nDer Wert von %d ist: ",fe[i]);
getch();
}
[bearbeiten] Parameter von main
Das Unterprogramm main kann, wie jede andere Funktion, Parameter besitzen. Beispiele dafür sind die Kommandozeilenparameter: Unter DOS führt "copy *.* a:" das Programm copy.exe aus. Dem Hauptprogramm von copy werden zwei Parameter übergeben: "*.*" und "a:". Damit main Parameter entgegennehmen kann, müssen Sie diese Funktion geringfügig verändern:
void main(int argc, char *argv[])
Bei argc handelt es sich um eine normale int-Variable (engl. "argument count", "Parameter-Zähler"). Darin steht die Anzahl der angegeben Parameter. arvg ist etwas komplexer: es ist ein Array von Zeigern, die auf chars zeigen. Dabei handelt es sich jedoch nicht um einzelne zeichen, sondern jeweils um einen String.
#include <stdio.h>
void main(int argc,char *argv[])
{
int i;
printf("Es wurden %d Parameter angegeben",argc);
for (i=0; i<argc;i++) printf("Parameter %d: %s\n",i,argv[i]);
getch();
}
- Erklärung
- Zuerst wird ausgegeben, wie viele Parameter insgesammt angegeben wurden. Aber Achtung: Es gibt immer mindestens einen Parameter: In argc[0] steht die aufgerufene EXE-Datei, also der Name Ihres Programmes. Außerdem: da die Liste bei argv[0] anfängt, ist der maximal gültige Index von argv der Index [argc-1].
- In der for-Schleife werden alle dem Programm übergebenen Parameter, inklusive ihrer Nummer, ausgegeben.
[bearbeiten] Ende
Damit haben Sie das Ende dieses Tutorials. Aber keinesfalls das Ihrer Programmier-Karriere! Die hat gerade erst begonnen. Sie haben nun das Grundwissen, um sinnvolle Programme zu schreiben. Es liegt an Ihnen, was Sie daraus machen.
Ich würde mich sehr freuen, wenn Sie mir Ihre Meinung zu diesem Tutorial mitteilen könnten. Da ich ständig bemüht bin es zu verbessern, ist natürlich auch (konstruktive) Kritik willkommen! Schauen Sie einfach mal auf meiner Kontakt-Seite vorbei.
| Allgemeines - Kapitel 1 - Kapitel 2 - Kapitel 3 - Kapitel 4 - Kapitel 5 - Kapitel 6 - Kapitel 7 - Kapitel 8 |
