Zeichenkette einlesen und mittels Zeigerarithmetik die Anzahl der Zeichen ausgeben?



  • @Luks-Nuke sagte in Zeichenkette einlesen und mittels Zeigerarithmetik die Anzahl der Zeichen ausgeben?:

    Würde dann aber glaub ich dann auch in ein std::abs() packen.

    Wozu? Ende-Anfang ist der positive Wert. Das nochmal durch abs zu jagen stiftet bloss Verwirrung.



  • @hustbaer sagte in Zeichenkette einlesen und mittels Zeigerarithmetik die Anzahl der Zeichen ausgeben?:

    Wozu? Ende-Anfang ist der positive Wert. Das nochmal durch abs zu jagen stiftet bloss Verwirrung.

    Dem stimme ich zu. Aber ich glaube ich hatte Mal bei anderen Datenstrukturen negative Ergebnisse bekommen, vermutlich weil der Speicher nicht zwingend so ausgelegt ist, dass begin auch wirklich vor end im Speicher vorliegt. Aber davon hab ich herzlich wenig Ahnung.



  • @Luks-Nuke sagte in Zeichenkette einlesen und mittels Zeigerarithmetik die Anzahl der Zeichen ausgeben?:

    Aber ich glaube ich hatte Mal bei anderen Datenstrukturen negative Ergebnisse bekommen, vermutlich weil der Speicher nicht zwingend so ausgelegt ist, dass begin auch wirklich vor end im Speicher vorliegt. Aber davon hab ich herzlich wenig Ahnung.

    Wenn man mit Zeigern arbeitet und mit ++ zum nächsten Element kommt, dann funktioniert Ende-Anfang. Wenn man mit Iteratoren arbeitet und mit ++ zum nächsten Element kommt, dann funktioniert Ende-Anfang ebenso, vorausgesetzt Ende und Anfang sind halt Iteratoren und diese unterstützen operator - (z.B. Random-Access Iteratoren).

    Und wenn keiner der beiden Fälle vorliegt, dann kann man überhaupt nicht davon ausgehen dass Ende-Anfang irgendwas brauchbares ergibt - mit oder ohne abs.

    Also angenommen man hätte eine Deque-artige Datenstruktur mit einem einzigen Array wo der freie Bereich irgendwo in der Mitt liegen kann, und man wenn man über das Ende rausläuft am Anfang weiter macht... (Pacman Style).
    Dann kommt bei abs(ZeigerAufRangeEnde-ZeigerAufRangeAnfang) nicht unbedingt was sinnvolles raus. Da kann dann entweder die Grösse der Range rauskommen oder die Capacity minus Grösse der Range.

    Mir fällt auf jeden Fall nichts ein wo man abs brauchen und damit zu einem sinnvollen Ergebnis kommen würde.

    Falls es so einen Fall gibt, lasste es mich gerne wissen.



  • @hustbaer

    Ich kann mit meiner wagen Erinnerung daran jetzt leider kein Beispiel-Code liefern.

    Ich meine nur irgendwo aufgegriffen zu haben, dass der Speicher das nicht zwangsweise von links nach rechts abspeichert.

    Aber nach weiteren Gedanken macht das Sinn, denn wenn du einen Iterator inkrementierst zeigt er ja wohl auf die nachfolgende Adresse.



  • @Luks-Nuke sagte in Zeichenkette einlesen und mittels Zeigerarithmetik die Anzahl der Zeichen ausgeben?:

    Ich meine nur irgendwo aufgegriffen zu haben, dass der Speicher das nicht zwangsweise von links nach rechts abspeichert.

    Der Satz macht für mich keinen Sinn. Also vergessen wir mal Endianness, denn das würde alles nur unnötig kompliziert machen, und ich denke auch nicht dass du das meinst.

    Der Speicher speichert das was du ihm gibst, an der Adresse die du verwendest. An der selben Adresse kannst du den Wert danach wieder lesen. Und das war's dann auch schon. Wenn du was an Adresse X schreibst, dann steht das halt dort. Wenn du was an Adresse X+1 schreibst, dann steht das halt an Adresse X+1. Links und rechts/vorne-hinten/Anfang-Ende etc. sind Konzepte die wir da reininterpretieren, haben aber technisch aus Sicht des Speichers keine Bedeutung.

    Wo sie eine Bedeutung gewinnen ist wenn man anfängt Datenstrukturen zu implementieren. Da geht's dann aber darum wie die Datenstruktur aufgebaut ist, und was der Code den man schreibt um diese umzusetzen macht. Und nicht darum dass der Speicher irgendwie selbst irgendwas andersrum abspeichert.

    Aber nach weiteren Gedanken macht das Sinn, denn wenn du einen Iterator inkrementierst zeigt er ja wohl auf die nachfolgende Adresse.

    Er. Nö 🙂

    Der Iterator zeigt auf das nächste Element. Das muss nicht unbedingt an der nachfolgenden Adresse liegen. Das kann auch davort oder überhaupt ganz woanders liegen. Allerdings abstrahiert der Iterator das ganze soweit, dass bei IteratorAufEnde-IteratorAufAnfang wieder das richtige rauskommt. Bei (&*IteratorAufEnde)-(&*IteratorAufAnfang) könnte allerdings beliebiger Unfug rauskommen.

    Also. Wenn du mit ++ Zeiger weiterschiebst, dann darfst du danach auch die Zeiger subtrahieren. Und wenn du mit ++ Iteratoren weiterschiebst, dann darfst du danach Iteratoren subtrahieren. Was du nichst darfst ist mit ++ Iteratoren weiterschieben, und danach Zeiger auf die Elemente subtrahieren.

    Und da es in diesem Thread um char Strings ging die mit Standard Library Funktionen eingelesen werden: diese liegen immer "vorwärts" im Speicher, d.h. ein Weiterspringen zum nächsten Zeichen in Leserichtung entspricht einem Weiterspringen im Speicher zum Byte mit der nächst höheren Adresse. (OK, genaugenommen könnten es multi-byte Strings sein, also sowas wie UTF-8. Dann wäre es nicht das nächste Zeichen sondern die nächste Code-Unit.)



  • @hustbaer

    Ok stimmt, gibt ja vielerlei Iteratoren. Ich hatte mich mit der Aussage jetzt auf String Iteratoren bezogen.

    Danke jedenfalls für die Erläuterung, für mich allerdings nicht die einfachste Lektüre.



  • Erstmal danke für die vielen Antworten. Immerhin wusste ich schon einmal, dass ich strlen simulieren muss. Ich bin in C noch nicht so fit und sehe noch nicht wirklich den Sinn diese Sprache zu lernen, da ich es im Berufsleben niemals brauchen werde. Aber ich versuche mir noch das C-Buch von Bradley L. Jones zu besorgen. Das soll zum lernen ganz gut sein.

    Bisher sieht mein geänderter Code so aus. Nur irgendwie habe ich gerade einen Denkfehler, warum mein programm nur eine Zahl einliest:

    #include <stdlib.h>
    #include <string.h>
    #include <stdio.h>
    #define MAX 128
    
    int main(){
    
    
        char *p;
        int i = 0;
        char z[MAX];
    
    
        printf("Gebe maximal 128 Zeichen in einer Zeile ein: ");
    
    
        gets(z);                        /*ganze Zeile einlesen*/
    
        while(*(p+i)!='\0'){            /*Zähle bis zum Ende der Zeichenkette*/
        p = &z[i];                      /*Adresse vom Zeichen ermitteln*/
        p = z + i;                      /*Wert vom Zeichen ermitteln*/
        printf("Test: %c",*p);          /*Ermittelter Wert zu testzwecken ausgeben*/
        i++;                            /*das Array um eins erhöhen*/
        return i;
        }
    
        printf("\nAnzahl:%d\n",i);      /*gib die Anzahl aus*/
    
    }
    
    

  • Mod

    Du wiederholst 3x die gleiche Rechnung, die du nur einmal brauchst: (p+i), p = &z[i], p = z + i. Das sind drei Beispiele für Zeigerarithmetik, die alle ungefähr das gleiche machen und wahrscheinlich so in deinem Lehrbuch stehen. Aber es ist nicht Sinn der Aufgabe, die alle irgendwo anzubringen. Du musst verstehen was das jeweils macht und mit einem Plan an die Aufgabe gehen.

    Bestes Beispiel die Zeilen 20 und 21. Was hast du dir dabei gedacht? Würdest du folgendes für sinnvoll erachten?

    i = 7;
    i = 15;
    

    Das ist quasi, was deine Zeilen 20-21 machen.



  • Das Problem ist allerdings das return i;, das dafür sorgt, dass direkt aus main gesprungen wird und damit das Programm beendet wird.
    printf("\nAnzahl:%d\n",i); wird niemals aufgerufen, wenn die Länge von p größer 0 ist.

    Edit: Ich sehe gerade, dass du gets verwendest, mach das nicht. gets ist mindestens deprecated (imho seit C99, in C2011 ist es komplett rausgeflogen), nimm stattdessen fgets.



  • @Ravensouth

    Dein Code sieht leider nicht so gut aus. Keine Ahnung wo ich da jetzt mit meckern anfangen soll... 🙂

    Versuch doch mal nach bereits existierenden strlen() Implementationen zu googeln. Da findest du durchaus hilfreiche Beispiele, wie man das macht.

    Schau dir beispielsweise das hier an:
    https://en.cppreference.com/w/cpp/string/byte/strlen

    Das verfolgt auch @hustbaer 's erwähnten Ansatz.



  • So ich melde mich nochmal erneut. Ich habe mich nochmal erneut daran versucht und habe das mit der nullten Stelle soweit kapiert. Im Internet hat man kaum etwas dazu gefunden, deshalb kam ich irgendwann auch so auf die Idee: Nur irgendwie denke ich, man hätte es noch sauberer lösen können und mehr die Zeigerarithmetik verwenden können. Hier der Code:

    #include <stdlib.h>
    #include <string.h>
    #include <stdio.h>
    #define MAX 130                         /*1 Byte für Zeichenkette = '\0' | 1 Byte extra, da wir ab i = 0 zählen*/
    
    int main(){
    
    
        int zahl = 0, i;
        char z[MAX];                        /*Array MAX groß*/
    
        printf("Gebe maximal 128 Zeichen in einer Zeile ein: ");
    
        fgets(z, MAX, stdin);                  /*ließt die ganze Zeile ein bis "MAX" Zeichen erreicht sind*/
    
        for(i=0; *(z+i) != 0; i++)             /*Zähle bis zum Ende der Zeichenkette*/
        {
        putchar(*(z+i));                       /*Kontrolle: Eingabe = Ausgabe*/
        zahl++;
        }
        zahl = zahl - 1;                       /*Minderung wegen der Versetzung um ein Byte*/
        printf("Anzahl:%d",zahl);              /*Ausgabe Anzahl*/
    
    return 0;
    }
    
    

  • Mod

    Probierst du deine Programme nicht aus?

    PS:

    1 Byte extra, da wir ab i = 0 zählen

    Ein Array int i[2]; hat zwei Elemente. i[0] und i[1].



  • @SeppJ sagte in Zeichenkette einlesen und mittels Zeigerarithmetik die Anzahl der Zeichen ausgeben?:

    Probierst du deine Programme nicht aus?

    Natürlich probiere ich meine Programme aus. Funktioniert doch. Das ein Array bei 0 anfängt weiß ich 🙂



  • @Ravensouth
    Teste dein Progamm mal mit nem Textfile als Input wo z.B. "test" (ohne folgenden Zeilenumbruch) drinsteht.
    Output:

    Gebe maximal 128 Zeichen in einer Zeile ein: testAnzahl:3
    


  • fgets speichert auch das Newline-Zeichen \n (im Gegensatz zu gets oder scanf("%s") - darum das Dekrementieren.

    Ein Möglichkeit ist mittels dem PP den Format-String für scanf zusammenzusetzen:

    #define STR(X) STRINGIFY(X)
    #define STRINGIFY(X) #X
    

    und dann

    scanf("%" STR(MAX) "s", z);
    

    s.a. Specifying the maximum string length to scanf dynamically in C (like "%*s" in printf)
    sowie der abgeänderte Ideone-Code.


  • Mod

    @Ravensouth sagte in Zeichenkette einlesen und mittels Zeigerarithmetik die Anzahl der Zeichen ausgeben?:

    Das ein Array bei 0 anfängt weiß ich 🙂

    Ja, aber ich habe den Eindruck, du ziehst die falschen Schlüsse.



  • @Th69
    Man kann schon fgets verwenden. Man muss bloss nachher das abschliessenden \n wegmachen wenn man es nicht haben will.



  • Ok das fgets mit /n abschließt wusste ich nicht. Danke für diese Information.



  • @SeppJ sagte in Zeichenkette einlesen und mittels Zeigerarithmetik die Anzahl der Zeichen ausgeben?:

    @Ravensouth sagte in Zeichenkette einlesen und mittels Zeigerarithmetik die Anzahl der Zeichen ausgeben?:

    Das ein Array bei 0 anfängt weiß ich 🙂

    Ja, aber ich habe den Eindruck, du ziehst die falschen Schlüsse.

    Wenn ich int i[2] als Array habe, dann müssten dochi[0],i[1] und i[2] enthalten sein?



  • @Ravensouth
    Nein!
    int i[2];
    hat 2 Elemente ... wie SeppJ oben schon erwähnt hat ...


Anmelden zum Antworten