Wie versteht man Zeigerarithmetik??



  • Immer dann, wenn du einen Zeiger auf irgendeine Stelle irgendeines Arrays hast und ihn verschieben moechtest. Wobei du Pointerarithmetik in modernem C++ generell deutlich seltener sehen wirst, als in C-Programmen.



  • Max, schaust du dir das mal bitte an:
    http://www.c-plusplus.net/forum/p1330752#1330752

    Ein Zeiger belegt auf deinem Rechner vermutlich 4 Byte. Bleiben wir mal dabei.
    Ein Int-Zeiger ist nicht viel anderes als ein int selbst. Ein int speichert Zahlen. Ein Zeiger auf Int (Int-Zeiger) speichert, wo andere Ints gespeichert sind, also die Adressen der Ints. Das selbe gilt für ein char. Ein char speichert ein Zeichen. Ein char-Zeiger speichert die Adresse von einem anderen char.

    int zahl = 5;  // zahl ist irgendwo im Speicher gespeichert, sagen wir diese Speicherstelle heißt 0x01
    
    cout << zahl; // gibt zahl aus, also 5.
    
    int* adresseVonZahl = &zahl; // In adresseVonZahl steht nun 0x01, wir hätten auch direkt:
    // int* adresseVonZahl = (int*)0x01; machen können, lass das mal aber lieber ;)
    
    // gut, adresseVonZahl weiß wo sich unsere variable zahl befindet. gehen wir doch mal dahin.
    cout << adresseVonZahl; // gibt 0x01 aus.
    cout << *adresseVonZahl; // mit * wird zu der gespeicherten Adresse gegangen, also
    // wenn wir zu 0x01 gehen, sind wir bei unserer Variable zahl, also wird 5 ausgeben.
    

    Soweit, so klar?

    Machen wir jetzt ein bisschen Zeigerarithmetik:

    int a[2] = {11, 12}; // Sieht im Speicher so aus:
    /* Speicher ( Adresse:Name:Wert) 
     ----------------------- 
    |  1000 |  a[0]  |  11  | 
     ----------------------- 
    |  1004 |  a[1]  |  12  |         
     ----------------------- 
    */ 
    
    // Ein Integer ist bei dir vier Byte groß, also belegen wir vier Byte im Speicher. Danach kommt das nächste int.
    
    // holen wir uns doch die Adresse von erstem Wert
    int* ersteAdresse = &a[0]; // hier steht nun 1000 drin. Info: Bei Arrays ist &a[0] das selbe wie einfach nur a, also der Arrayname.
    
    cout << ersteAdresse << " " << *ersteAdresse; // gibt 1000 11 aus.
    
    // wir haben ein int array, wir wissen das ints vier byte groß sind, wir wissen das arraywerte im speicher nacheinander kommen
    // dann lass uns doch mal zum nächsten array wert wandern
    
    int* zweiteAdresse = ersteAdresse + 1; // unser compiler sieht hier, wir wollen ein int-adresse weiter 
    // gehen, der compiler macht dann daraus ungefähr(*):
    
    // int* zweiteAdresse = (int)ersteAdresse + 1*sizeof(int); nehme die 1000 und addiere vier bytes drauf, um zum nächsten zu gelangen
    // sizeof(int) deswegen, weil int nicht überall gleich groß ist. 
    
    cout << zweiteAdresse << " " << *zweiteAdresse; // gibt 1004 12 aus.
    
    // wir können auch direkt mehr weiter gehen:
    int* outOfSpace = ersteAdresse + 2; // achtung, da sind wir bei unserem array aber schon über die Grenze!!!
    
    (*) Den TE bloß nicht überstrapazieren.
    

    Mehr ist Zeigerarithmetik nicht.



  • @KasF
    Du musst auch dazuschreiben, dass die 0x01 und die 1000 nur von dir ausgedachte Beispieladressen sind.
    Diese Werte sind in realen Programmen ganz andere.



  • Anwendungsbeispiel:

    int a[5] = {1,2,3,4,5};
    
    // gebe mit hilfe der zeigerarithmetik all zahlen in a aus.
    
    int* adresse = a; // = &a[0];
    
    cout << *adresse; // 1
    
    adresse = adresse + 1; // gehe sizeof(int) bytes weiter, also zum nächsten wert
    
    cout << *adresse; // 2
    
    adresse = adresse + 1;
    cout << *adresse; // 3 , usw usf ..
    
    // das schreit nach einer schleife:
    
    adresse = a; // zurück zum anfang.
    for(int i = 0; i < 5; ++i)
    {
       cout << *adresse << " ";  // ausgeben
       adressen = adresse + 1;   // und eins weiter gehen
    }
    
    das kann man ein bisschen schöner machen:
    adresse = a; // zurück zum anfang.
    
    const unsigned int arrayGroesse = sizeof(a)/sizeof(int); // ergbibt 5! die gesamt größe des arrays durch die größe eines elements teilen.
    
    for(int i = 0; i < arrayGroesse; ++i)
    {
       cout << *adresse << " ";  // ausgeben
       ++adresse;   // und eins weiter gehen
    }
    

    Das reicht erstmals.



  • Sone schrieb:

    Du bist kein Programmierfachprofi.
    Dein Beispiel ist falsch und schlecht.

    Mein Code funktioniert, die eine Warnung bei der Zeigerzuweisung kann man verschmerzen.

    Siehe:

    #include <stdio.h>
    
    int main(){
      int a[] = {1, 3};
      int *pa=&a;
      pa = pa + a[0]; 
    
      for (int i = 0; i < 2; i++){
        printf("a[%i] = %i\n", i, a[i]);
      }
      return 0;
    }
    

    gcc -std=c99 -Wall -o "zeigerarithmetik" "zeigerarithmetik.c" (im Verzeichnis: F:\)
    zeigerarithmetik.c: In function 'main':
    zeigerarithmetik.c:5:11: warning: initialization from incompatible pointer type [enabled by default]
    Kompilierung erfolgreich beendet.

    ohoh schrieb:

    Sone schrieb:

    Du bist kein Programmierfachprofi.
    Dein Beispiel ist falsch und schlecht.

    Jup, sollte so heißen:

    int a[] = {1, 3};
    int *pa=a;
    pa+=1; // oder ++pa;  <--- Das ist FALSCH!
    

    Dein Code ist falsch.
    Der Threadstarter wollte mit den Werten einer Variable rechnen und nicht mit einer absoluten Zahl.
    Siehe dazu auch sein Verständnisproblem am Anfang, das du reingebracht hast, nachdem du mit konstanten Zahlen, anstatts mit Variablenwerten gerechnet hast.

    Deswegen steht bei mir a[0] und den += Operator versteht ein Anfänger nicht unbedingt, deswegen sollte man es ausgeschrieben hinschreiben.
    richtig ist also:
    pa = pa + a[0];

    so wie ich es zu Beginn schrieb.



  • den += Operator versteht ein Anfänger nicht unbedingt

    Du machst Scherze oder? Den sollte selbst ein absolute Anfänger ohne Probleme verstehen können.

    gcc -std=c99 -Wall -o "zeigerarithmetik" "zeigerarithmetik.c" (im Verzeichnis: F:\)
    zeigerarithmetik.c: In function 'main':
    zeigerarithmetik.c:5:11: warning: initialization from incompatible pointer type [enabled by default]

    👎 😮
    Wir sind hier im C++ Forum! Was ist denn mit dir los?



  • KasF schrieb:

    Max, schaust du dir das mal bitte an:
    http://www.c-plusplus.net/forum/p1330752#1330752

    Den Link kann ich nicht öffnen. Zumindest kommt die Meldung "Seiten-Ladenfehler".



  • silent_max schrieb:

    KasF schrieb:

    Max, schaust du dir das mal bitte an:
    http://www.c-plusplus.net/forum/p1330752#1330752

    Den Link kann ich nicht öffnen. Zumindest kommt die Meldung "Seiten-Ladenfehler".

    Also bei mir geht er, sonst versuch mal den: http://www.c-plusplus.net/forum/187711



  • Ich glaube, dass ich noch mindestens zwei Denkfehler habe.

    Folgendes Beispiel wollte ich in einem Code realisieren:

    /* Speicher ( Adresse:Name:Wert) 
     ------------------------ 
    |  1000 |  Zahl_1 |  05  | 
     ------------------------
    |  1004 |  Zahl_2 |  05  |         
     ------------------------ 
    */
    

    Auf Basis diesen Beispiels habe ich folgenden Code geschrieben.

    #include <iostream>
    using namespace std;
    
    int main()
    {
      int Zahl_1, Zahl_2, Zahl_3;
      int *pZahl_1 = &Zahl_1;
      int *pZahl_2 = &Zahl_2;
      int *pZahl_3 = &Zahl_3;
    
      cout << "Es werden zwei Zahlen miteinander addiert.\n";
      cout << "Geben Sie dazu zwei Zahlen ein!\n";
      cin  >> Zahl_2 >> Zahl_3;
      cout << "\n";
    
      Zahl_1 = Zahl_2 + Zahl_3;
    
      cout << Zahl_2 << " + " << Zahl_3 << " ergibt " << Zahl_1 <<"\n";
      cout << "\n";
    
      cout << "Adresse von " << Zahl_2 << ":          " << &Zahl_2 << "\n";
      cout << "Bytereservierung von " << Zahl_2 << ": " << sizeof(Zahl_2) << "\n"; 
      cout << "Adresse von " << Zahl_3 << "           " << &Zahl_3 << "\n";
      cout << "Bytereservierung von " << Zahl_3 << ": " << sizeof(Zahl_3) << "\n";
      cout << "Adresse von " << Zahl_1 << ":          " << &Zahl_1 << "\n";
      cout << "Bytereservierung von " << Zahl_1 << ": " << sizeof(Zahl_1) << "\n";
      cout << "\n";
    
      return 0;
    }
    

    Nun wird mir folgendes ausgegeben:

    Es werden zwei Zahlen miteinander addiert!
    Geben Sie dazu zwei Zahlen ein:
    5
    5
    
    5 + 5 ergibt 10
    
    Adresse von 5:          026F8E0
    Bytereservierung von 5: 4
    Adresse von 5:          026F8D4
    Bytereservierung von 5: 4
    Adresse von 10:         026F8EC
    Bytereservierung von 10: 4
    

    Nun zu meinen Fragen.

    1.) Ich dachte, wenn ich Zahl_1 und Zahl_2, beides 5, miteinander addiere, also 10, werden für die 10 insgesamt 8 Byte reserviert. Warum werden dann nur 4 Byte als Bytereservierung ausgegeben?

    2.) Ich dachte, dass die Adressen von den beiden 5er jeweils um 4 und das Ergebnis um 8 hochzählt, also dass es im Endeffekt so aussieht:

    Adresse von 5:  026F8E0
    Adresse von 5:  026F8E4
    Adresse von 10: 026F8EC
    

    Warum werden die Adressen willkürlich ausgewählt?

    Im Debugger bekomme ich folgende Werte:

    pZahl_1: 0x0019f928
    pZahl_2: 0x0019f91c
    pZahl_3: 0x0019f910
    

    Kann man überhaupt die Adressen so sortiern, dass sie jeweils um 4 Byte hochzählen?? Falls ja wie??

    Der Algorithmus

    sort();
    

    sortiert ja nur zwischen den Iteratoren first und last und ist nur für Container mit Random-Acces-Iteratoren geeigntet...



  • siehe
    http://de.wikipedia.org/wiki/Byte (kleinste addressierbare Speichereinheit, besteht unter C++ aus mindestens 8 Bits)
    http://de.wikipedia.org/wiki/Dualsystem

    silent_max schrieb:

    1.) Ich dachte, wenn ich Zahl_1 und Zahl_2, beides 5, miteinander addiere, also 10, werden für die 10 insgesamt 8 Byte reserviert. Warum werden dann nur 4 Byte als Bytereservierung ausgegeben?

    Zahl_1 ist auch nur eine int-Variable. Und int-Variablen sind immer gleich groß.

    silent_max schrieb:

    2.) Ich dachte, dass die Adressen von den beiden 5er jeweils um 4 und das Ergebnis um 8 hochzählt, also dass es im Endeffekt so aussieht:

    Adresse von 5:  026F8E0
    Adresse von 5:  026F8E4
    Adresse von 10: 026F8EC
    

    Warum werden die Adressen willkürlich ausgewählt?

    Warum nicht?

    silent_max schrieb:

    Kann man überhaupt die Adressen so sortiern, dass sie jeweils um 4 Byte hochzählen?? Falls ja wie??

    Ja. Die Elemente eines std::vector<int> Objekts liegen z.B. alle schön hintereinander im Speicher.



  • krümelkacker schrieb:

    silent_max schrieb:

    Kann man überhaupt die Adressen so sortiern, dass sie jeweils um 4 Byte hochzählen?? Falls ja wie??

    Ja. Die Elemente eines std::vector<int> Objekts liegen z.B. alle schön hintereinander im Speicher.

    So wie ich Dich verstehe, kann aber man die Adressen von zwei unterschiedlichen Variablen, also nicht im Vektor, aber nicht so sortieren, dass sie hinteraneinder um 4 Byte hochzählen??



  • Du kannst Adressen nicht sortieren. Wozu sollte das auch gut sein?



  • Belli schrieb:

    Du kannst Adressen nicht sortieren.

    Ich dachte, man kann Adressen sortieren. Jetzt weiß ich, dass man es nicht kann.

    Edit:
    Ich habe jetzt auf die Schnelle folgenden Code programmiert:

    #include <iostream>
    using namespace std;
    
    int main()
    {
      cout << "\t 5 Adressen um jeweils 4 Byte hochzaehlen lassen.\n";
      cout << "\n";
    
      int Zahl[5];
      int *pZahl= &Zahl[5];
      int a;
    
      cout << "Geben Sie fuenf Zahlen ein.\n";
      cin  >> a;
    
      for(int i=0; i<5; i++)
      {
        cout << "Zahl[" << i << "]:";
        cin  >> i;
      }
    
      cout << "Die Adresse der jeweiligen Zahl lautet wie folgt:\n";
    
      for(int i=0; i<5; i++)
      {
        cout << "Zahl[" << i << "]: " << &Zahl[i] << "\n";
      }
    
      return 0;
    }
    

    Wenn ich aber die Zahlen einlesen will, dann wir

    Zahl[1]
    

    übersprungen, also bekomme ich beim Einlesen der Zahlen folgendes raus:

    Zahl[0]:
    Zahl[2]:
    Zahl[3]:
    Zahl[4]:
    

    Komischerweise bei der Ausgabe der Adressen wird jedes Element angezeigt.

    Selbst im Debugger wird das Element Zahl[1] übersprungen.

    Wo liegt mein Fehler??



  • Was soll das überhaupt bewirken? 🙄



  • Schau bitte meinen Edit an.



  • &Zahl[5] ist die Adresse des 6. Elements in Zahl. Leider hat Zahl kein 6. Element. Etwas in i einzulesen macht wohl wenig Sinn.



  • silent_max schrieb:

    Ich habe jetzt auf die Schnelle folgenden Code programmiert:

    blablabla...
    liest irgendwann den Laufindex von cin ein...
    blablabla...
    

    Evtl. solltest Du das mit dem "auf die Schnelle" lassen, bzw. jedenfalls niemanden damit behelligen, sondern erstmal im stillen Kämmerlein schauen, was Phase ist...



  • Der Denkfehler liegt ganz woanders.

    Im Anhang der korrigiert Code.

    @cooky451: Vergleiche mal beide Codes.

    @FurbleWurble: Du bist mir zuvor gekommen mit Deinem Posting.

    Edit: Jetzt müsste es aber laufen.

    #include<iostream>
    using namespace std;
    
    int main()
    {
      cout << "\t 5 Adressen um jeweils 4 Byte hochzaehlen lassen.";
      cout << "\n";
    
      int Zahl[5];
      int *pZahl = Zahl[5];
      int a;
    
      cout << "Geben Sie fuenf Zahlen ein.\n";
      cin  >> a;
    
      for (int i=0; i<5; i++)
      {
        cout << "Zahl[" << i << "]:";
        cin  >> a;
      }
    
      cout << "Die Adresse der jeweiligen Zahlen lautet wie folgt: \n";
    
      for(int i=0; i<5; i++)
      {
        cout << "Zahl[" << i << "]:" << &Zahl[i] << "\n";
      }
    
      return 0;
    }
    


  • Was soll man dazu sagen? Nichts davon macht auch nur im entferntesten Sinn, das kompiliert nicht mal. 🙄



  • cooky451 schrieb:

    Was soll man dazu sagen? Nichts davon macht auch nur im entferntesten Sinn, das kompiliert nicht mal. 🙄

    Weil ich in Zeile 6 ein ; vergessen habe.

    Jetzt müsste es kompilieren.


Anmelden zum Antworten