C: Wozu Zeiger?

Moin,

ich hab noch nicht verstanden, wozu man Zeiger braucht. Alle Beispiele des Tutorials das ich bearbeite waren bisher auch ohne Zeiger lösbar und schienen auch nicht aufwändiger, unsicherer oder sonst großartig anders zu funktionieren.

Kann mir jemand ein (möglichst simples) Beispiel nennen, das mir veranschaulicht, dass Zeiger tatsächlich nötig sein können?

thx
moe.

Kann mir jemand ein (möglichst simples) Beispiel nennen, das
mir veranschaulicht, dass Zeiger tatsächlich nötig sein
können?

C kennt ken Pass-by-Value für komplexe Datentypen. Wenn du zB eine struct an eine Funktion übergeben willst, dann musst du das per Zeiger machen. Oder wenn du einer Funktion ein Datum übergeben willst, dass durch diese Funktion verändert werden soll, dann musst du der Funktion einen Zeiger übergeben.

Beispiel:

int some\_function( int\* a ) {
 \*a = (\*a + 42)/23
}

int main( void ) {
 int some\_value = 4711;

 some\_function( &some\_value );

 /\* some\_value hat jetzt einen anderen Wert \*/
}

Hallo,

ohne jede Wertung, ob gut oder nötig:

  1. C funktioniert nur mit Zeigern.
  2. Windows funktioniert nur mit Zeigern (kein Zufall, siehe 1).

Folge: will ich Windows, brauch ich Zeiger (auch z.B. in Pascal). Weitergehende Fragen sind philosophisch.

Gruss Reinhard

[Bei dieser Antwort wurde das Vollzitat nachträglich automatisiert entfernt]

Hallo Flaming Moe,

Kann mir jemand ein (möglichst simples) Beispiel nennen, das
mir veranschaulicht, dass Zeiger tatsächlich nötig sein
können?

Wo zeiger in C ‚nötig‘ sind, läßt sich
klar sagen:

Bei der Rückgabe von

  • Feldern
  • Funktionen
    aus Funktionen.

Das erlaubt C imho nicht.

Ansonsten kann man Zeiger häufig durch
direkte Indizierung in ein Array mit
Werten (über den Integer-Index) umgehen.

In manchen Fällen führt das zu verbesserten
Programmen, in manchen nicht.

Beispiel:

 #include 
 /\* 
 const char ( funktion\_1() ) []
 {
 static char char\_array[100] = "wichtige Daten #1";
 return char\_array;
 }
 \*/
 const char \* funktion\_2() 
 {
 static char char\_array[100] = "wichtige Daten #2";
 return char\_array;
 }
 
 const char (\* funktion\_3() ) []
 {
 static char char\_array[100] = "wichtige Daten #3";
 return &char\_array;
 }
 
 int main()
 {
 /\*
 puts ( funktion\_1() );
 \*/
 puts ( funktion\_2() );
 puts ( \*funktion\_3() );
 return 0;
 }

Wir versuchen in diesem Beispiel, das
char-array ‚direkt‘, also als Feld
zurückzugeben, um es auszudrucken.

Das geht nicht. funktion_1 liefert: ‚cannot return array‘
als Compilerfehler.

Wir könnten nun versuchen, einfach die Feldadresse
von char-array in eine Variable zu kopieren und
diese zurückzuliefern - also einen Zeiger zu verwenden.
Das geht, siehe funktion_2.

Wollen wir aber wirklich das array char_array
herausholen, benutzen wir einen zeiger auf das Feld
selbst, die Dereferenzierung 'puts ( *funktion_3() );
liefert uns das Feld, welches wir ausdrucken können.

Grüße

CMБ

Dynamische Datenstrukturen
Hallo,

sobald du Datenstrukturen brauchst, deren Größe sich zur Laufzeit ändert, brauchst du Zeiger.
Einfachstes Bespiel ist eine Linked List. (s. z.B. http://en.wikipedia.org/wiki/Linked_List - schön Ausführlich).

HTH,
Moritz

Hallo Moritz

sobald du Datenstrukturen brauchst, deren Größe sich zur
Laufzeit ändert, brauchst du Zeiger.
Einfachstes Bespiel ist eine Linked List. (s. z.B.
http://en.wikipedia.org/wiki/Linked_List - schön Ausführlich).

Ich denke mal, gerade bei der ‚linked list‘ stimmt
das nicht so ganz direkt :wink:

Du kannst zwar eine ‚linked list‘ über Zeiger
realisieren, musst es aber nicht. Ich hab schon
(in Fortran) schöne schnelle einfachverkettete
Listen geschrieben.

Du brauchst ein Array mit Daten (hast Du sowieso)
und ein Array mit Indices (simples int-Array).
Der Inhalt jedes Feldes des int-Aarrays ist die
Position (der Index) des Nächsten in der Liste.

‚In Software‘ ist das sogar noch simpler als mit
Zeigern zu realisieren. Möglicherweise ist es
auch schneller.

Grüße

CMБ

Hallo,

Du kannst zwar eine ‚linked list‘ über Zeiger
realisieren, musst es aber nicht. Ich hab schon
(in Fortran) schöne schnelle einfachverkettete
Listen geschrieben.

Du brauchst ein Array mit Daten (hast Du sowieso)
und ein Array mit Indices (simples int-Array).
Der Inhalt jedes Feldes des int-Aarrays ist die
Position (der Index) des Nächsten in der Liste.

Das geht, aber es geht nur, wenn du ein Array im Nachhinein vergrößern kannst, oder vorher eine vernünftige Obergrenze für die Anzahl der Listenelemente hast. Man kann natürlich die meisten Zeigeroperationen mit Arrays emulieren, aber ich halte das weder für sinnvoll noch für elegant.

Grüße,
Moritz

Hallo Moritz

[linked list ohne Zeiger]

Das geht, aber es geht nur, wenn du ein Array im Nachhinein
vergrößern kannst, oder vorher eine vernünftige Obergrenze für
die Anzahl der Listenelemente hast.

Du hast natürlich recht, wenn man den „Spezialfall“
betrachtet, dass man eine Liste ‚in place‘, also
durch direktes neuallokiieren der Elemente bei
der Listenkonstruktion, erzeugen möchte.

Das kann man zwar in C++ (und Java) in „Objekten“
verstecken, in C (möglicherweise) nicht (so einfach).

Man kann natürlich die meisten Zeigeroperationen
mit Arrays emulieren, aber ich halte
das weder für sinnvoll noch für elegant.

Im Falle eine einfachverketteten Liste, in der

  • die Maximalzahl der möglichen Elemente bekannt ist

  • die Liste, die auf einem int-Vektor ‚emuliert‘ wird,
    direkt als Indexfeld dient

halte ich die Implementation ohne Zeiger sowohl für ‚eleganter‘
als auch für ‚performanter‘.

Versuche es doch mal :wink:

Allerdings kann man ‚rekursive Algorithmen‘ in
Zeigerverkettungen prägnanter ausdrücken, da
hast Du zweifellos recht:wink:

Grüße

CMБ

Hallo moe,

ich hab noch nicht verstanden, wozu man Zeiger braucht. Alle
Beispiele des Tutorials das ich bearbeite waren bisher auch
ohne Zeiger lösbar und schienen auch nicht aufwändiger,
unsicherer oder sonst großartig anders zu funktionieren.

  1. Ein Zeiger passt immer in die Register der CPU.
  2. Es ist eine grundlegende Adressierungsart der CPU.
  3. Es ist meist effizienter (bezoge auf Speicher und Rechenzeit) einen Zeiger zu übergeben, als eine Kopie der Daten.

Kann mir jemand ein (möglichst simples) Beispiel nennen, das
mir veranschaulicht, dass Zeiger tatsächlich nötig sein
können?

Das Laden eines Programms in den Speicher durch das BS.

MfG Peter(TOO)