Zeigerarithmetik



  • Moin, ich hätte da mal eine kurze Frage, wenn jemand kurz Zeit hat wäre es freundlich sich mal eben dieses Beispiel anzuschauen :

    #include <iostream>
    #include <cstdlib>
    
    int main (int argc, char** argv) 
    {
    	const int N = 4;				// Letztes Element, da Zählung bei 0 beginnt
    	int a [N+1] = { 2,6,32,3, 1 };	// 0-4 (5 Elemente), ohne '+1' => 0-3 (4 Elemente)
    	int key = 3;					// Gesuchtes Element
    	int i = {0};					// Laufvariable
    
    	a[N] = key;						// Senitel
    	int *p = a;						// Zeiger auf Adresse des ersten Elements
    
    	while (*p++ != key);
    	i = p-a-1;
    
    	std::cout << "Gesuchtes Element ist an der Stelle "
    		<< i << std::endl;
    
    	std::system("PAUSE");
    	return 0;
    }
    

    Funktioniert auch alles soweit und ich verstehe den Großteil (hoffe ich zumindest). Jetzt gibt es aber diese Stelle hier, an der Schlussendlich das Ergebnis (die Position des gesuchten Elements) in i eingespeichert wird :

    i = p-a-1;
    

    Soweit so gut, meines Wissens nach zeigt der Bezeichner des Arrays aber immer auf den Beginn des Feldes. Wieso kann ich also nicht hingehen und einfach

    p-1
    

    sagen? Versuche ich das allerdings bekomme ich eine Fehlermeldung vom Compiler:

    Fehler 1 error C2440: 'Initialisierung': 'int *' kann nicht in 'int' konvertiert werden

    Letztlich funktioniert p-a-1 und p-a doch auch und der Ausdruck dessen ist ebenfalls ein integer.

    An dieser Stelle schon mal ein Dankeschön an alle, die sich die Zeit genommen haben!



  • p und a sind Zeiger und damit nur Adressen. Mit p - a berechnest du allerdings die Anzahl (keine Adresse mehr!) der Integer, um die p verschoben ist.

    Woher das - 1 ist aber klar?



  • Erst mal danke für die Antwort,
    Die -1 dient dazu, das Ergebnis an die interne Zählung ab 0 anzupassen, oder?
    Also ich denke, dass ist etwa verstanden habe, was du meinst. Sollte ich den Ausdruck besser so lesen : (p-a) -1 ?
    Um es mal in Worte zu fassen: Rechenoperationen mit Adressen funktionieren nur, wenn man auch eine andere Adresse als zweiten Operand hat. Das Ergebnis dieser Rechenoperation ist ein Integer und deshalb kann ich -1 abziehen, oder wie sollte ich das verstehen?

    ~ Sorry ich stell mich allgemein was Pointer angeht ziemlich dämlich an.



  • PointerManX schrieb:

    Die -1 dient dazu, das Ergebnis an die interne Zählung ab 0 anzupassen, oder?

    Nicht so ganz. Die while-Schleife ist so gestaltet, dass das aktuelle p mit dem key verglichen und dann um eins hochgezählt wird. Erst danach wird die Schleifenbedingung geprüft. (Nach der Schleife zeigt p also auf das Element hinter dem eigentlichen Fund. In diesem Fall allerdings dein Sentinel.)

    PointerManX schrieb:

    Also ich denke, dass ist etwa verstanden habe, was du meinst. Sollte ich den Ausdruck besser so lesen : (p-a) -1 ?
    Um es mal in Worte zu fassen: Rechenoperationen mit Adressen funktionieren nur, wenn man auch eine andere Adresse als zweiten Operand hat. Das Ergebnis dieser Rechenoperation ist ein Integer und deshalb kann ich -1 abziehen, oder wie sollte ich das verstehen?

    Ja, so wird er auch ausgewertet.
    Mit den Zeigern kann man nicht beliebig rechnen. Die Differenz ist aber definiert. (Man kann die Zeiger aber in normale Zahlen umwandeln, dann kann man damit ganz normal rechnen. Sollte aber normalerweise nicht gemacht werden.)

    Dazu musst du noch wissen, dass die Zeiger einen Typ haben, darüber wissen sie, dass bei einem 32-bit Integer bei einem Inkrement die Adresse um 4 (Byte) erhöht werden muss. (zB bei deinem p++ ) Oder auch, dass die Differenz der Adressen durch vier geteilt werden muss.



  • Die while-Schleife ist so gestaltet, dass das aktuelle p mit dem key verglichen und dann um eins hochgezählt wird. Erst danach wird die Schleifenbedingung geprüft.

    Die Schleifenbedingung ist doch, dass p mit key verglichen wird, oder was genau meinst du? Bezüglich dessen ist mir allerdings auch noch etwas unklar, vielleicht hast du ja eine Antwort :
    Bei mir im Buch steht es wird bei "*p++" eben erst der Wert an der Stelle p genommen und dann um eins inkrementiert. Was wäre aber wenn ich einen Schleifenkörper mit Code hätte (speziell der 1. Durchlauf ist gemeint).

    Sagen wir mal *(p+0) = 10, *(p+1) = 20.
    Würde p im ersten Durchlauf auf den Wert 10 oder 20 Zeigen?

    Ums mal generell zu fassen : Wird direkt nachdem die Bedingung geprüft wurde p erhöht, oder wird die Schleife dann erst ein mal durchlaufen?

    Den Rest hab ich soweit verstanden, viele Dank schon mal dafür !



  • Es wird der Wert in *p genommen und zwischengespeichert, dann wird p inkrementiert. ( *p++ )
    Danach wird geschaut ob der Wert von vorher nicht mit dem key übereinstimmt.

    Wenn das der Fall ist, wird die Schleife abgearbeitet (in diesem Fall ist sie leer) und das Spiel beginnt von vorne. Ansonsten wird die Schleife abgebrochen.

    Im ersten Durchlauf des Schleifenkörpers wäre das p bereits einmal inkrementiert.

    Mit einer for-Schleife oder einer Modifikation an der while-Schleife kann man das Verhalten natürlich ändern.



  • Ich wollte das mal an einem Beispiel ausprobieren aber irgendwie ist mir nie was passendes eingefallen.
    Vielen vielen Dank für die Unterstützung, das hat mich wirklich ein ganzes Stück weiter gebracht ! 🙂


Log in to reply