Zeiger Verständnis



  • Was ist der Unterschied von

    #include <stdio.h>
    
    int main() {
        int zahl;
        int *zeiger;
        zahl = 34;
        *zeiger = zahl;
    
    }
    

    zu

    #include <stdio.h>
    
    int main() {
        int zahl;
        int *zeiger;
        zahl = 34;
        zeiger = &zahl;
    
    }
    

    ? Ich bin von Zeigern ein wenig verwirrt. Wenn ich nun dem Zeiger eine Variable oder einen Wert zuweisen will, muss ich dann ein Sternchen vor den jeweiligen Zeiger machen oder nicht? Wann muss ich ein & machen, wann nicht?

    Wenn ich "int *zahl" die zahl "100" zuweisen möchte, schreibe ich dann

    int *zahl;
    zahl = 100;
    

    oder

    int *zahl;
    *zahl = 100;
    


  • #include <stdio.h>
    
    int main() {
        int zahl;
        int *zeiger;
        zahl = 34;
        *zeiger = zahl;
    
    }
    

    Ist so undefiniert. Weil zeiger auf nix ordentliches zeigt, was dereferenziert werden könnte.
    Wenn zeiger auf was ordentliches zeigen würde, dann hätte das, worauf er zeigt, jetzt den Wert 34. Also, eigentlich wird dieser Wert so oder so 34 haben, es sei denn, es gibt direkt eine Schutzverletzung. Und wenn nicht, dann geht dein Programm später kaputt. Oder möglicherweise gar nicht. Weil das halt "undefiniert" ist.

    #include <stdio.h>
    
    int main() {
        int zahl;
        int *zeiger;
        zahl = 34;
        zeiger = &zahl;
    
    }
    

    Hier wird zeiger was ordentliches zugewiesen, welches bereits den Wert 34 besitzt.
    Mit & greifst du auf die Adresse eines Objektes zu. Weil Zeiger Adressen halten. Und wenn du an dem Wert, der hinter der Adresse steht, interessiert bist, dereferenzierst du den Zeiger mit einem *.



  • #include <stdio.h>
    
    int main() {
        char string[10000];
        char *ptr;
        int ascii[256];
        int i;
    
        //Read user input
        printf("Geben Sie etwas ein: ");
        scanf("%s",string);
    
        //Every element of ascii code has counter value, first 0
        for(i = 0; i < 256; i++) {
            ascii = 0;
        }
    
        //Count
        for(ptr = string; *ptr != '\0'; ptr++) {
            ascii[*ptr]++;
        }
    
        //Output
        for(i = 0; i < 256; i++) {
            if(ascii[i] != 0) {
                printf("%c = %i\n", i, ascii[i]);
            }
        }
    
        return 0;
    }
    

    Folgender Ausschnitt interessiert mich hier:

    //Count
        for(ptr = string; *ptr != '\0'; ptr++) {
            ascii[*ptr]++;
        }
    

    Hier wird der zeigt der Zeiger [i]ptr* auf den string, welcher zuvor eine Eingabe erhalten hat, richtig? Aber warum? Oder wird hier etwas anderes gemacht? Auch verwirrt mich die Zeile danach, in welcher der Zeiger *ptr in den eckigen Klammern des Arrays steht. Wenn meine Vermutung von oben richtig wäre, würde ja immer ein Buchstabe in den eckigen Klammern stehen. Daraus schließe ich, dass meine Vermutung falsch ist. Nur was passiert dann wirklich?

    Auch bin ich an dem Geschehen des Folgenden interessiert:

    //Every element of ascii code has counter value, first 0
        for(i = 0; i < 256; i++) {
            ascii[i] = 0;
        }
    

    Wenn ich diese Zeile im Programm entferne, kommen wahllose Zahlen heraus, d.h. es wird nicht richtig gezählt. Aber warum genau? Greift das Array hier auf zufällige Werte im Speicher zu, weil diese noch nicht = 0 gesetzt wurden?



  • Dein Programm zählt das Vorkommen von Zeichen in einem String.

    Die Zeichen sind aber auch nur Zahlenwerte. Damit kann man rechnen.

    for(ptr = string; *ptr != '\0'; ptr++) {
            ascii[*ptr]++;
        }
    

    mal als while-Schleife

    ptr = string; // lasse ptr auf den string zeigen
    while (*ptr != '\0') {  // solange der Wert an der Stelle auf die ptr verweist, ungleich 0 ist, mache
      ascii[*ptr]++;        // nimm den Wert an der Stelle auf die ptr verweist, als Index in dem Array ascii und erhöhe den Wert dort um 1
      ptr++;                // lasse ptr auf den nachfolgenden Wert zeigen
    }
    

    CrispyTurtleAlligator schrieb:

    Greift das Array hier auf zufällige Werte im Speicher zu, weil diese noch nicht = 0 gesetzt wurden?

    Ja.

    Evtl kannst du dir das mit den Zeigern so merken:

    int *zeiger;
    

    Bei der Definition gibst du den * mit an. Und davor steht der Typ (int).
    Dann ist *zeiger vom typ int

    Dabei ist es aber egal ob da

    int  *zeiger;
    int * zeiger;
    int*  zeiger;
    

    steht. Alles dasselbe.


  • Mod

    CrispyTurtleAlligator schrieb:

    Hier wird der zeigt der Zeiger ptr auf den string, welcher zuvor eine Eingabe erhalten hat, richtig?

    Nein. ptr zeigt auf ein Zeichen in string. Zudem wird der Wert dauernd verändert. Beim ersten Durchlauf der Schleife zeigt er auf das erste Zeichen ( ptr=string ), beim zweiten Durchlauf auf das nächste ( ptr++ ) und so weiter.

    Auch verwirrt mich die Zeile danach, in welcher der Zeiger *ptr in den eckigen Klammern des Arrays steht. Wenn meine Vermutung von oben richtig wäre, würde ja immer ein Buchstabe in den eckigen Klammern stehen.

    So ist es. Es steht ein Wert vom Typ char in den Klammern.

    Daraus schließe ich, dass meine Vermutung falsch ist.

    Wieso? Buchstaben sind auch nur Zahlen.

    Auch bin ich an dem Geschehen des Folgenden interessiert:

    //Every element of ascii code has counter value, first 0
        for(i = 0; i < 256; i++) {
            ascii[i] = 0;
        }
    

    Wenn ich diese Zeile im Programm entferne, kommen wahllose Zahlen heraus, d.h. es wird nicht richtig gezählt. Aber warum genau?

    Weil du nicht willkürlich Zeilen aus einem Programm entfernen kannst, besonders wenn du sie nicht verstehst, und erwarten kannst, dass dies keine Auswirkungen hat? Code ist kein zusammengewürfelter Haufen von Zeichen. Code ist Logik pur. Du musst von jedem Zeichen in deinem Code genau wissen wo und warum du es setzt!

    Greift das Array hier auf zufällige Werte im Speicher zu, weil diese noch nicht = 0 gesetzt wurden?

    Ein Array greift auf gar nichts zu. Drück dich genau aus! Das Array enthält Werte. Der Algorithmus verlangt, dass diese zu Beginn des Zählvorganges 0 sein müssen. Daher muss man sie auf 0 setzen. (Lokale) Variablen werden in C nicht automatisch mit 0 initialisiert, daher muss man das selber machen. Ansonsten kann da alles mögliche drinstehen, in der Praxis wird das normalerweise irgendwelcher Datenmüll sein.



  • Mal angenommen ich tippe nun das Wort "Programm" ein. Dann wird demnach das P in ascii[0], das r in ascii[1], ..., aufrufbar sein. Für mich stellt sich dann die Frage, warum?

    //Count
        for(ptr = string; *ptr != '\0'; ptr++) {
            ascii[*ptr]++;
        }
    

    ptr zeigt ja zuerst auf das P. Daraufhin steht doch eigentlich in den Klammern des Arrays ascii ein P bzw. eine 80, laut der ASCII Tabelle. Oder liege ich hier erneut falsch? Ich sehe hier einfach keinen Zusammenhang, warum dann das P über ascii[0] und nicht über ascii[80] aufrufbar ist. Ich stelle mich glaube ich gerade einfach nur dämlich an.


  • Mod

    CrispyTurtleAlligator schrieb:

    Mal angenommen ich tippe nun das Wort "Programm" ein. Dann wird demnach das P in ascii[0], das r in ascii[1], ..., aufrufbar sein.

    Nein, wird es nicht.

    Für mich stellt sich dann die Frage, warum?

    Wie kommst du überhaupt darauf? Du erklärst es doch selber richtig:

    ptr zeigt ja zuerst auf das P. Daraufhin steht doch eigentlich in den Klammern des Arrays ascii ein P bzw. eine 80, laut der ASCII Tabelle. Oder liege ich hier erneut falsch?

    So ist es richtig.

    Ich sehe hier einfach keinen Zusammenhang, warum dann das P über ascii[0] und nicht über ascii[80] aufrufbar ist.

    Da ist ja auch kein Zusammenhang! Wie kommst du darauf, dass das P in ascii[0] gezählt würde?



  • CrispyTurtleAlligator schrieb:

    Mal angenommen ich tippe nun das Wort "Programm" ein. Dann wird demnach das P in ascii[0], das r in ascii[1], ..., aufrufbar sein.

    Nein, das ist falsch.

    CrispyTurtleAlligator schrieb:

    Für mich stellt sich dann die Frage, warum?

    //Count
        for(ptr = string; *ptr != '\0'; ptr++) {
            ascii[*ptr]++;
        }
    

    ptr zeigt ja zuerst auf das P. Daraufhin steht doch eigentlich in den Klammern des Arrays ascii ein P bzw. eine 80, laut der ASCII Tabelle. Oder liege ich hier erneut falsch?

    Soweit richtig. (Besser: es ist ein 'P'. Die einfachen Hochkommas kennzeichnen das Zeichen)

    CrispyTurtleAlligator schrieb:

    Ich sehe hier einfach keinen Zusammenhang, warum dann das P über ascii[0] und nicht über ascii[80] aufrufbar ist. Ich stelle mich glaube ich gerade einfach nur dämlich an.

    Deine erste Annahme ist ja falsch.
    Bei einer falschen Annahme kannst du mit Logik nicht weiter machen. Es kommt was falsches raus.
    In ascii['P'] bzw. ascii[80] steht auch kein P. Da steht die Anzahl des Vorkommens von 'P' in deinem Text drin.

    Du hast ein https://de.wikipedia.org/wiki/Histogramm von deinem Text. (Die Klassenbreite ist ein Zeichen)



  • Ich bin davon ausgegangen, weil mir Xcode folgendes ausspuckt, siehe Bild auf Link. http://fs2.directupload.net/images/150820/4hyvt4n9.png

    Dabei geht es aber wohl eher darum, dass das P in string[0], r in string[1], ... steht.

    In den Klammern steht als tatsächlich ein 'P', daraufhin ein 'r', ..., 'm'. Sämtliche Werte wurden ja zuvor gleich 0 gesetzt, da ja ansonsten nicht richtig gezählt wird. Somit hat eben das 'P' bzw. die 80 eben den Wert 0, richtig? Und sobald der Buchstabe einmal vorhanden ist, wird durch das ascii[*ptr]++ der Wert um eins erhöht. Wenn das nun alles so richtig ist, dann bin ich damit zufrieden und bedanke mich bei allen für die Hilfsbereitschaft und die Geduld mit mir. 🙂


  • Mod

    CrispyTurtleAlligator schrieb:

    Dabei geht es aber wohl eher darum, dass das P in string[0], r in string[1], ... steht.

    Nicht "eher darum", sonder es geht darum! Dir ist schon klar, dass string und ascii zwei ganz unterschiedliche Arrays sind?

    In den Klammern steht als tatsächlich ein 'P', daraufhin ein 'r', ..., 'm'. Sämtliche Werte wurden ja zuvor gleich 0 gesetzt, da ja ansonsten nicht richtig gezählt wird. Somit hat eben das 'P' bzw. die 80 eben den Wert 0, richtig? Und sobald der Buchstabe einmal vorhanden ist, wird durch das ascii[*ptr]++ der Wert um eins erhöht.

    Tut mir leid, aber das ist kompletter Blödsinn. Ich komme mir so langsam verarscht vor.



  • SeppJ schrieb:

    CrispyTurtleAlligator schrieb:

    Dabei geht es aber wohl eher darum, dass das P in string[0], r in string[1], ... steht.

    Nicht "eher darum", sonder es geht darum! Dir ist schon klar, dass string und ascii zwei ganz unterschiedliche Arrays sind?

    In den Klammern steht als tatsächlich ein 'P', daraufhin ein 'r', ..., 'm'. Sämtliche Werte wurden ja zuvor gleich 0 gesetzt, da ja ansonsten nicht richtig gezählt wird. Somit hat eben das 'P' bzw. die 80 eben den Wert 0, richtig? Und sobald der Buchstabe einmal vorhanden ist, wird durch das ascii[*ptr]++ der Wert um eins erhöht.

    Tut mir leid, aber das ist kompletter Blödsinn. Ich komme mir so langsam verarscht vor.

    Warum ist das kompletter Blödsinn?

    //Read user input
        printf("Geben Sie etwas ein: ");
        scanf("%s", string);
    

    Dadurch wird eine Eingabe erwartet. Die Eingabe wird anschließend durch die Variable string aufrufbar sein.

    //Every element of ascii code has counter value, first 0
        for(i = 0; i < 256; i++) {
            ascii[i] = 0;
        }
    

    Hier wird der Wert von ascii[0], ascii[1], ... auf 0 gesetzt.

    //Count
        for(ptr = string; *ptr != '\0'; ptr++) {
            ascii[*ptr]++;
        }
    

    Bei der Eingabe von 'Programm' zeigt ptr nun zuerst auf das P. Wenn dieses ungleich \0 ist, dann wird der Wert für ascii['P'] um eins erhöht. Dann wird durch das ptr++ von 'P' weiter zu 'r' gegangen.



  • CrispyTurtleAlligator schrieb:

    Warum ist das kompletter Blödsinn?

    Er hat es doch bereits geschrieben - string und ascii sind zwei unterschiedliche Arrays. Und der Wert der Zelle des einen Arrays wird wiederum als Index für das zweite Array verwendet. Und darauf wird dann inkrementiert.

    Der Code durchsucht ja den String nach der Häufigkeit der Buchstaben, deswegen wird der Wert des Buchstaben als Index verwendet. Anfangen tust du mit der Häufigkeit 0 für alle Buchstaben. Und das Inkrementiert sich dann halt je nachdem, welcher Index verwendet wird.


  • Mod

    CrispyTurtleAlligator schrieb:

    SeppJ schrieb:

    CrispyTurtleAlligator schrieb:

    Dabei geht es aber wohl eher darum, dass das P in string[0], r in string[1], ... steht.

    Nicht "eher darum", sonder es geht darum! Dir ist schon klar, dass string und ascii zwei ganz unterschiedliche Arrays sind?

    In den Klammern steht als tatsächlich ein 'P', daraufhin ein 'r', ..., 'm'. Sämtliche Werte wurden ja zuvor gleich 0 gesetzt, da ja ansonsten nicht richtig gezählt wird. Somit hat eben das 'P' bzw. die 80 eben den Wert 0, richtig? Und sobald der Buchstabe einmal vorhanden ist, wird durch das ascii[*ptr]++ der Wert um eins erhöht.

    Tut mir leid, aber das ist kompletter Blödsinn. Ich komme mir so langsam verarscht vor.

    Warum ist das kompletter Blödsinn?

    Weil es nicht das ist, was passiert und es völlig unverständlich ist, wie du überhaupt da drauf gekommen bist.

    //Read user input
        printf("Geben Sie etwas ein: ");
        scanf("%s", string);
    

    Dadurch wird eine Eingabe erwartet. Die Eingabe wird anschließend durch die Variable string aufrufbar sein.

    //Every element of ascii code has counter value, first 0
        for(i = 0; i < 256; i++) {
            ascii[i] = 0;
        }
    

    Hier wird der Wert von ascii[0], ascii[1], ... auf 0 gesetzt.

    //Count
        for(ptr = string; *ptr != '\0'; ptr++) {
            ascii[*ptr]++;
        }
    

    Bei der Eingabe von 'Programm' zeigt ptr nun zuerst auf das P. Wenn dieses ungleich \0 ist, dann wird der Wert für ascii['P'] um eins erhöht. Dann wird durch das ptr++ von 'P' weiter zu 'r' gegangen.

    Diese Beschreibung ist 100% richtig. Wenn du sie mit dem vergleichst, was ich "vollkommenen Blödsinn" schimpfte, wirst du feststellen, dass sie völlig unterschiedlich sind.

    Falls du mit dem "vollkommenen Blödsinn" bereits das gleiche ausdrücken wolltest: Hast du nicht. Und da in der Programmierung, wie schon erklärt, jedes einzelne Zeichen wichtig ist, tendieren viele Programmierer dazu, auch im Alltag so zu denken. Man muss sich eben ganz genau und korrekt ausdrücken. Aber hier ist das nicht einmal der Fall, ich bin schließlich gewohnt, dass Leute sich manchmal ungenau ausdrücken. Aber ich kann nicht einmal im Ansatz erkennen, wie du mit deiner ersten Beschreibung vielleicht den richtigen Sachverhalt ungeschickt ausgedrückt haben könntest. Daher habe ich die Beschreibung "vollkommenen Blödsinn" genannt.



  • dachschaden schrieb:

    CrispyTurtleAlligator schrieb:

    Warum ist das kompletter Blödsinn?

    Er hat es doch bereits geschrieben - string und ascii sind zwei unterschiedliche Arrays. Und der Wert der Zelle des einen Arrays wird wiederum als Index für das zweite Array verwendet. Und darauf wird dann inkrementiert.

    Der Code durchsucht ja den String nach der Häufigkeit der Buchstaben, deswegen wird der Wert des Buchstaben als Index verwendet. Anfangen tust du mit der Häufigkeit 0 für alle Buchstaben. Und das Inkrementiert sich dann halt je nachdem, welcher Index verwendet wird.

    Ja, ich habe doch zugegeben, dass ich mich da vertan habe. In dem letzten Beitrag und vor allem in dem Bereich, den er zitiert hat, war aber gar nicht mehr die Rede davon. In dem Zitat ist von string gar keine Rede mehr, sondern nur von dem ASCII Array.



  • SeppJ schrieb:

    Falls du mit dem "vollkommenen Blödsinn" bereits das gleiche ausdrücken wolltest: Hast du nicht. Und da in der Programmierung, wie schon erklärt, jedes einzelne Zeichen wichtig ist, tendieren viele Programmierer dazu, auch im Alltag so zu denken. Man muss sich eben ganz genau und korrekt ausdrücken. Aber hier ist das nicht einmal der Fall, ich bin schließlich gewohnt, dass Leute sich manchmal ungenau ausdrücken. Aber ich kann nicht einmal im Ansatz erkennen, wie du mit deiner ersten Beschreibung vielleicht den richtigen Sachverhalt ungeschickt ausgedrückt haben könntest. Daher habe ich die Beschreibung "vollkommenen Blödsinn" genannt.

    Dann bedanke ich mich mal dafür, dass du das so eng siehst, damit ich mich in der Hinsicht verbessere. 😉



  • Moin!
    Ich will auch noch zur Verwirrung beitragen. 🙂

    @CrispyTurtleAlligator:

    Die Ausgabe dieses Programms kannst Du nachvollziehen?

    #include <stdio.h>
    
    #define HISTSIZE 6
    
    int main(void){
      int arr[] = { 3,3,  5,5,5,5,5,5,5,5,5,5,5,5,5,  1,1,1,  -1 };
    
      int histogram[HISTSIZE]={0};
      for(int* ptr=arr; *ptr!=-1; ++ptr)
        ++histogram[*ptr];
    
      for(int i=0; i<HISTSIZE; ++i)
        printf("Zahl %d, Haeufigkeit: %d\n", i, histogram[i]);
    }
    
    Zahl 0, Haeufigkeit: 0
    Zahl 1, Haeufigkeit: 3
    Zahl 2, Haeufigkeit: 0
    Zahl 3, Haeufigkeit: 2
    Zahl 4, Haeufigkeit: 0
    Zahl 5, Haeufigkeit: 13
    


  • Furble Wurble schrieb:

    Moin!
    Ich will auch noch zur Verwirrung beitragen. 🙂

    @CrispyTurtleAlligator:

    Die Ausgabe dieses Programms kannst Du nachvollziehen?

    #include <stdio.h>
    
    #define HISTSIZE 6
    
    int main(void){
      int arr[] = { 3,3,  5,5,5,5,5,5,5,5,5,5,5,5,5,  1,1,1,  -1 };
    
      int histogram[HISTSIZE]={0};
      for(int* ptr=arr; *ptr!=-1; ++ptr)
        ++histogram[*ptr];
    
      for(int i=0; i<HISTSIZE; ++i)
        printf("Zahl %d, Haeufigkeit: %d\n", i, histogram[i]);
    }
    
    Zahl 0, Haeufigkeit: 0
    Zahl 1, Haeufigkeit: 3
    Zahl 2, Haeufigkeit: 0
    Zahl 3, Haeufigkeit: 2
    Zahl 4, Haeufigkeit: 0
    Zahl 5, Haeufigkeit: 13
    
    int arr[] = { 3,3,  5,5,5,5,5,5,5,5,5,5,5,5,5,  1,1,1,  -1 };
    

    Das legt ein Array fest, welches keine Anzahl der Elemente in den eckigen Klammern benötigt, weil C das automatisch anhand der Anzahl der Elemente in den geschweiften Klammern macht.

    int histogram[HISTSIZE]={0};
      for(int* ptr=arr; *ptr!=-1; ++ptr)
        ++histogram[*ptr];
    

    Dadurch wird ein Array mit 6 Elementen initialisiert. Die Werte dieser Elemente werden allesamt auf 0 gesetzt. Daraufhin zeigt der Zeiger auf die erste 3 aus arr[]. Solange der Wert, auf den der Pointer zeigt ungleich -1 ist, wird die for-Schleife weiter durchgeführt. In der Schleife wird zuerst der Wert von histogram[3], ... um eines erhöht. Die -1 in arr[]; dient dazu, um der Schleife ein Ende zu verpassen.

    Schließlich wird mit einer weiteren Schleife das im Programm erarbeitete ausgegeben.

    Korrekt? Was kann man besser formulieren?



  • Perfekt.

    Dementsprechend ist das auch klar?

    #include <stdio.h>
    
    #define HISTSIZE 127
    
    int main(void){
      char arr[] = { 'H', 'a', 'l', 'l', 'o', 0 };
      int histogram[HISTSIZE]={0};
    
      for(char* ptr=arr; *ptr!=0; ++ptr)
        ++histogram[*ptr];
    
      for(int i=0; i<HISTSIZE; ++i)
        printf("Zahl %d, Haeufigkeit: %d\n", i, histogram[i]);
    }
    

    Zur Kontrolle die ASCII Tabelle auf Wikipedia.

    Der Ablauf ist natürlich derselbe. Bist Du jetzt überrascht wg. der Ausgabe?



  • Warum sollte ich überrascht sein? Vielleicht, weil anstelle von Buchstaben die Häufigkeit von Zahlen ausgegeben wird? Das liegt an dem %d, welches anstelle von dem %c genutzt wird. Übrigens danke für die Mühe, mir das zu verdeutlichen. 😉



  • Als ich den Thread gestern Abend entdeckt habe, dachte ich da sei noch Erklärungsbedarf.
    Wenn ich mir den Thread heute allerdings bei Lichte betrachte, hattest Du's ja schon geschnallt gehabt, bevor ich überhaupt in die Diskussion eingestiegen bin...ein wenig überflüssig also...

    Naja...war mir ein Vergnügen! 🙂


Log in to reply