Pointer auf Array -WTF? [C++]

no idea

Lt. Junior Grade
Registriert
Feb. 2004
Beiträge
452
ich brauche mal eine verständniss erklärung im bezug auf das folgende programm

#include <iostream>
int array[10] = {-4, -5, -8, -9, -8, -1, 0, 1, 9, 3};
int *array_ptr;
int main()
{
array_ptr = array;
while ((*array_ptr) != 0)
++array_ptr;
std::cout << (array_ptr - array) << '\n';
array_ptr = array;
while ((*array_ptr) >= -5)
++array_ptr;
std::cout << (array_ptr - array) << '\n';
return (0);
}

so wie ich das verstehe wird die ADRESSE des pointers hochgezählt bzw. die Speicheradresse des arrays womit gleichzeitig das array selbst hochgezählt wird.
aber wie kann denn das sein?
wenn ich die speicheradresse hochzähle, dass ich auch gleich im nächsten array feld lande?!

rfc-thx
 
Hallo,

array_ptr ist eine eigene (globale) Variable, die eine Speicheradresse enthält. Durch array_ptr = array; weist du dieser die Anfangsadresse deines Arrays zu. Danach würde die Dereferenzierung (*array_ptr) den Wert des ersten Arrayelements liefern. Durch ++array_ptr wird nun der Inhalt der Variable array_ptr (also die Speicheradresse) um 4 Bytes erhöht, sodass dieser Zeiger auf das Zweite Element des Arrays zeigt. Das ganze ändert aber nichts an dem Ursprungsarray, da du ja nur den Inhalt des Zeigers veränderst.

ph4nt0m
 
1.) Wenn du ein Feld anlegst, dann hast du eigentlich nicht mehrere Elemente, sondern einen Pointer auf das erste Element des Feldes. Der Code feld ist eigentlich nur eine andere Schreibweise für *(feld+i).

2.) Wenn du zu einem Pointer einen Wert addierst z.B. feld + 3, dann wird nicht einfach die Adresse um 3 erhöht, also von 4711 auf 4714, sondern es wird um 3 mal die Größe eines Elementes erhöht. Wie groß ein Element ist, weiß der Compiler anhand des Pointertyps. Wenn man z.B. einen Integer mit 32Bit (4Byte) verwendet, dann ist feld+3 die Adresse von Feld + 3*4, also wird aus 4711 + 3*4 = 4723. Das ist auch gar nicht so viel Rechenaufwand, weil der PC ja binär ist und so der Compiler aus jedem x*4 gleich ein x<<2 macht, also einfach x um 2 Stellen nach links schieben, was fast keine Performance braucht. Deshalb sind auch alle Datentypen eine Potenz von 2. (8Bit, 16Bit, 32Bit, 64Bit etc.)

3.) In unserem Fall haben wir ein Feld mit 10 Elementen. Den pointer arr_ptr setzen wir auf dieselbe Adresse wie array. Wenn man auf arr_ptr zugreift, dann greift man auf array[0] zu. Wenn man arr_ptr um eins erhöht, dann wird einfach zu der Adresse, die in arr_ptr gespeichert ist (z.B. 4711) ein Element addiert. Dadurch zeigt der Pointer dann auf das zweite Element (array[1]) usw.

4.) Man kann die Pointer und Feldschreibweise beliebig mischen. Man kann z.B. auch auf arr_ptr[3] zugreifen. Wenn arr_ptr gerade auf array[2] steht, dann greift man eben auf (array+2)[3], also auf array[5] zu.

5.) Einen Pointer stellt man sich einfach als Integer-Variable vor, in der einfach nur eine Adresse steht. Was auf dieser Adresse steht, ist eigentlich ziemlich egal. Wichtig ist eigentlich nur die Länge des Elements dort. Ein Pointer ist immer gleich lang (bei 32Bit Systemen 32Bit). Wenn man die Zuweisung pointer2=pointer1 (bzw. pointer2=feld1, da ein Feld ja in Wirklichkeit ja nur ein Pointer ist) macht, dann passiert nichts anderes, als dass die Adresse, die im ersten Pointer gespeichert ist, auf den zweiten kopiert. Was an dieser Adresse steht, ist vollkommen egal und es wird auch gar nicht überprüft, ob da überhaupt etwas steht. Wenn man nun pointer1[815] ändert, dann wird einfach ein Wert auf die Adresse pointer1+815 geschrieben. Ob der Wert überhaupt in unserem Feld liegt, wird nicht geprüft. Dafür hat der Programmierer zu sorgen. Man kann beliebig irgendwo hin schreiben. Manchmal stürzt das Programm ab, weil es die Adresse nicht gibt, oft wird aber auch irgendetwas überschrieben und dann kann man nicht mehr sagen, was dann passiert, also aufpassen. Greift man nachher auf pointer2[815] zu, dann steht da auch der Wert drin, den man gerade draufgeschrieben hat, weil pointer2+815 ja auch nur eine Adresse ist und auf dieser Adresse steht dann ein anderer Wert.

6.) Dass das Programm, das du da gepostet hast, nur zur Demonstration dient und man solchen Code nie schreiben sollte, versteht sich denke ich einmal von selbst, da es absolut unlesbar ist und man so etwas mit einer for Schleife lösen sollte. Wenn man das richtige Element erreicht hat, kann man ein break machen. Dadurch ist gewährleistet, dass man auch immer innerhalb seiner Arraygrenzen bleibt, es ist deutlich schneller, viel besser lesbar etc.
Variablen sollte man auch nur dann global definieren, wenn es einen guten Grund hat. Weiters glaube ich, dass array ein Schlüsselwort ist, aber da bin ich mir nicht mehr sicher, also im Zweifselfall vermeiden.
Eine saubere Variante wäre z.B. das hier:

Code:
#include <iostream>
int main()
{
 int arr[10]={-4, -5, -8, -9, -8, -1, 0, 1, 9, 3};
 int i;

 for(i=0;i<10;i++)
 {
   if(arr[i]==0)
    break;
 }
cout << arr[i] << endl; //endl ist das \n, eventuell muss man dafür noch irgendwas einbinden.

for(i=0;i<10;i++)
{
   if(arr[i]<5)
    break;
}

cout << arr[i] << endl;
}
 
danke für die antworten.

ps.: ich weiß: das is total bescheuert geschrieben aber so sieht ne klausur-frage bei meinem c++ prof aus -geil was?:)
 
Ok bei Anfängern ist das vielleicht für das Verständnis ganz gut, aber mir wäre diese Syntaxglauberei mittlerweile zu blöd.
 
Dein Code stimmt auch nicht mit dem des OP überein. Es werden im Original nämlich keine Inhalte des Feldes ausgegeben, sondern nur berechnete Offsets. Aber genau daran sieht man eben, dass solche Pointer-Konstrukte tunlichst vermieden werden sollten. Dass es immer noch Professoren gibt, die ihre Studenten mit so einem Müll verunsichern, ist mehr als traurig. Diese Herrschaften sollten sich einmal mit Java beschäftigen und sich überlegen, warum diese Programmiersprache versucht, auf unsichere Sprachelemente von C++ zu verzichten.

j o e
 
Ich denke, es soll nur das Konzept von Pointern und Zeigerarithmetik verdeutlicht werden und nicht eine reale Umsetzung in dieser Art und Weise nahe gelegt werden. Das finde ich durchaus hilfreich. Um zu erkennen, dass solcher Code Mist ist, muss man ihn erstmal verstehen können. Und es hilft ungemein beim Verständnis von fremdem Code, wenn man diese Sprachelemente zumindest kennt und versteht (beherschen im Sinne von selber schreiben muss man sie ja deshalb noch lange nicht).

Spätestens wenn man auch in Java über Nullpointer-Exceptions stolpert, wird einem klar, dass das auch nur alles kaschierte Zeiger sind.
 
Zuletzt bearbeitet:
Zurück
Oben