Funktion welche Zeichenstring zählt



  • Servus Gemeinde,

    bin sehr neu hier und brauche eure Hilfe, da ich mehr als feststecke.

    Bin in der Fachoberschule 12. Klasse und wir haben gerade mit Zeigern(Pointern) angefangen.
    Nun haben wir erstmals eine Hausaufgabe, die ich so gar nicht verstehe. Die restlichen konnte ich mit Schwitzen noch selbst nachrecherchieren und dann selbst lösen.
    Nun zur Aufgabe:

    Schreibe eine Definition der Funktion int stringlen(char*pa), die den Zeiger pa auf einen String übergeben bekommt, die darin enthaltenen Zeichen zählt (ohne '\0') und deren Anzahl zurückgibt,
    ( Beispiel : Der Aufruf ' stringlen ( "Hallo" ) liefert den Wert 5 zurück)

    soviel dazu.

    Mein Problem nun : char liest ja lediglich den ersten Buchstaben eines Wortes ein. Also habe ich ein Array erstellt und lese es mit einer For-Schleife ein. Das funktioniert aber auch nicht.
    Ich brauche unbedingt mal einen Denkanstoß, da wir fast noch nie mit char-Variablen gearbeitet haben.
    Bitte werft nicht mit Steinen auf mich 😃 , bin wirklich noch blutiger Anfänger und versuche mein Bestes zu geben

    Danke schonmal im Voraus!

    Gruß Chippo



  • Hallo,

    weisst du, was ein Zeiger ist und wie man ihn benutzen kann?

    Du schreibst, dass du etwas geschrieben hast, das aber nicht funktioniert. "funktioniert nicht" ist eine ganz miese Fehlerbeschreibung. Am besten ist es, deinen Code zu posten, zu erklaeren, was du erwartest und in wie fern das Ergebnis davon abweicht. Dann kann man erkennen, welche Gedanken du dir gemacht hast und wo es beim Verstaendnis hakt.

    Poste doch einfach mal, was du bisher hast, auch wenn es dir nicht relevant vorkommen mag.



  • #include <iostream>
    
    using namespace std;
    
    int stringlen(char *pa);
    
    int main(void)
    {
    	char eingabe[15];
    	int i;
    
    	for (i = 0; i < 15; i++)
    	cin >> eingabe[i];
    	cout << eingabe; *****
    
    }
    int stringlen(char *pa)
    
    {
    
    }
    

    ****Hier ist schon mein Problem, da ich eigentlich will, dass die Schleife aufhört sobald das Wort eingegeben wurde und nicht, sobald 15 Zeichen eingegeben wurden. Und vor der Eingabe zu fragen, wie viele Buchstaben man eingeben will wäre ja auch sinnlos.

    Zeiger weiß ich wie es funktioniert. 👍

    Gruß



  • Zuallererst: benutze geschwungene Klammern auch fuer Schleifen und Abfragen (if), die nur eine Anweisung enthalten:

    for(int i = 0; i < 15; ++i)
    {
        // ... so sollte das aussehen
    }
    

    Deine Frage zum char-array hat ja mit der eigentlichen Fragestellung nichts zu tun, ich komme gleich darauf zurueck.
    Du koenntest das aktuelle gelesene Zeichen ueberpruefen und wenn es ein bestimmtes Zeichen (z.B. ';') ist, die Schleife abbrechen. Generell ist deine Art, Zeichen zu lesen, nicht so knuelle. Das Problem ist, dass du ein char-array verwendest. Ich schaetze mal, ihr habt das halt so im Unterricht gemacht und von std::string habt ihr noch nie gehoert.
    Das laesst einen hin-und hergerissen, dir zu zeigen, wie man es mit einem char-array (halbwegs) sauber machen kann oder dich auf std::string zu verweisen. 😕
    Eigentlich bin ich davon ueberzeugt, dass es besser ist, es erst zu lernen wie man es richtig macht, um spaeter, wenn man mehr kann, die andere Variante kennenlernt.
    Ich zeige einfach mal beides.

    Die schoene Variante: std::string verwenden.

    #include <string> // string ist aus der standardbibliothek
    #include <iostream>
    
    using namespace std;
    
    int main()
    {
        cout << "Wie ist dein Name?\n";
        string antwort;
        cin >> antwort;
    
        cout <<  "Hallo " << antwort << '\n';
    }
    

    Bam. Einfacher gehts nicht. Beachte allerdings, dass die Eingabe nur bis zum ersten Whitespace (z.B. Leerzeichen oder Tabulator) liesst. Probiers aus!

    Die komplizierte Variante: char-arrays

    #include <iostream>
    
    using namespace std;
    
    int main()
    {
        char arr[15] = { 0 }; // das initialisiert alle Zellen mit 0
    
        // variante 1: die unsichere, niemals benutzen!
        cin >> arr; // liesst bis zum ersten Whitespace, aber was ist, wenn das Wort mehr als 14 Zeichen hat?
    
        // variante 2: mit get
        // liess solange Zeichen, bis ein gewuenschtes Endzeichen gelesen wurde oder der stream zu ende ist (eof)
        char ch;
        unsigned int i = 0;
        while(cin.get(ch))
        {
            arr[i++] = ch;
        }
    
        // variante 3: mit getline
        cin.getline(arr, 15);
    }
    

    Wie du siehst, ist das bis auf das erste Beispiel mit mehr Aufwand als mit der Verwendung von std::string verbunden. Die erste Variante ist aber so schlecht, dass sie einfach schon falsch ist.
    Die Benutzung von char* ist sehr fehleranfaellig und hat ein paar sehr spezielle Details, mit denen du dich nicht rumschlagen willst.

    Naja, auf zur eigentlichen Frage:
    Du sagst, du weisst wie ein Zeiger funktioniert. Weisst du auch, wie ein C-string funktioniert? Darum gehts hier. Ein c-string ist ein Zeiger auf den Anfang einer Zeichenkette im Speicher, also ein char*.
    Das wichtigste, was man beachten muss, ist dass ein c-string immer mit einer 0 abgeschlossen wird (die Zahl, nicht das Zeichen!).
    Wenn du also einen c-string mit dem Inhalt "Hallo" hast, sind fuer diesen String insgesamt 6(!) chars reserviert, das letzte enthaelt 0 (auch als '\0' geschrieben).

    Nimm einfach dieses Beispiel und teste damit deine Funktion:

    #include <iostream>
    
    using namespace std;
    
    int stringlen(char* pa)
    {
        // hier code einfuegen
    }
    
    int main() // void in leeren parameterlisten ist nicht noetig
    {
        const char* string = "Hallo Welt!";
    
        int length = stringlen(string);
        cout << "The length of the string '" << string << "' is " << length << '\n';
    }
    


  • Wo in der Aufgabenstellung kommt eine Eingabe vor?



  • Ich flippe gleich aus. Ich weiß nicht wie man die Zeichen zählt.
    Mir ist klar das Bei " Hallo " im Speicher [H][A][L][L][O][\0] belegt ist. Ich weiß auch, dass ich mit einer Schleife zählen muss, aber ich komme nicht auf den Wert, der die Schleife eingrenzt.

    *pa zeigt ja im Moment auf das "H", wenn ich das richtig verstanden habe. Und das "H" ist pa[0] ?



  • chippo schrieb:

    *pa zeigt ja im Moment auf das "H", wenn ich das richtig verstanden habe. Und das "H" ist pa[0] ?

    Ja, kann man so sagen auch wenn es verwirrt klingt...

    chippo schrieb:

    Ich weiß auch, dass ich mit einer Schleife zählen muss, aber ich komme nicht auf den Wert, der die Schleife eingrenzt.

    Vergiss einfach mal für ein moment die normale Schleife von 0 bis X, du weißt ja noch garnicht wie weit du zählen musst. Statt also bis zu einem festen Wert zu zählen zählst du von 0 an bis du pa[i] == '\0' erreicht hast.



  • #include <iostream>
    #include <string>
    
    using namespace std;
    
    int stringlen(char* pa)
    {
    	int i, summe;
    
    	for (i = 0; pa[i] == '\0'; i++)
    	{
    		summe = summe + i;
    	}
    
    	return summe-1 ;
    
    }
    
    int main()
    {
    	char* string = " Hallo ";
    
    	int length = stringlen(string);
    	cout << "The length of the string '" << string << "' is " << length << '\n';
    }
    

    So sieht es jetzt aus. Ich gehe jetzt schlafen, bevor ich noch meinen PC zeige, was eine Wasserkühlung mit dem Kärcher ist. Ohman wie ich es hasse, was nicht zu verstehen 👎
    Gute Nacht!



  • Nicht ganz, aber nah dran.

    #1: summe = summe + i macht keinen sinn, wenn dann wäre das + 1 für jedes Zeichen.
    #2: du hast bereits i was für dich zählt
    #3: Deine Bedingung ist falschrum. Du willst weiterzählen solange das Zeichen nicht '\0' ist

    Nach den 3 kleinen Verbesserungen sieht der Code dann so aus:

    int stringlen(char* pa) 
    { 
        int i;
        for (i = 0; pa[i] != '\0'; i++) {}
        //Leerer Schleifenbody. i wird bereits durch die Schleife erhöht und
        //das Zeichen wird durch die Bedingung geprüft
    
        return i;
    }
    


  • #1,5: summe ist nicht initialisiert. Du hast summe keinen Anfangswert gegeben.

    Und das sollte² dein Compiler als Warnung anmeckern. Und die musst du auch beachten.
    ²Wenn er das nuicht macht, musst du die Einstellungen für die Warnungen verändern.



  • Es funktioniert nun. Ich habe einfach viel zu viel an die normale Schleife mit Stoppwert x gedacht. Jetzt macht das alles auch Sinn 😃

    Vielen Dank an die fleißigen Helfer! 👍



  • Damit auch eine schöne Implementierung dasteht:

    #include <cstddef>
    
    std::size_t strlen( char const * str )
    {
    	char const * p = str;
    	while( *p++ );
    	return p - str - 1;
    }
    


  • Swordfish schrieb:

    Damit auch eine schöne Implementierung dasteht:

    könnte die überlaufen? Ist es garantiert, dass das letzte byte im addressraum nicht belegt werden kann?


  • Mod

    otze schrieb:

    Swordfish schrieb:

    Damit auch eine schöne Implementierung dasteht:

    könnte die überlaufen? Ist es garantiert, dass das letzte byte im addressraum nicht belegt werden kann?

    Da dachte ich auch sofort dran, aber ich meine, dass es erlaubt ist, um Eins hinter das Ende eines Arrays zu zählen. Ich habe aber gerade keine Lust, das im Standard nachzuschlagen und warte stattdessen auf einen Kommentar von den Leuten, die den Standard auswendig können.



  • SeppJ schrieb:

    otze schrieb:

    [
    könnte die überlaufen? Ist es garantiert, dass das letzte byte im addressraum nicht belegt werden kann?

    Da dachte ich auch sofort dran, aber ich meine, dass es erlaubt ist, um Eins hinter das Ende eines Arrays zu zählen. Ich habe aber gerade keine Lust, das im Standard nachzuschlagen und warte stattdessen auf einen Kommentar von den Leuten, die den Standard auswendig können.

    Es ist garantiert.

    §5.7/5 schrieb:

    [...]Moreover, if the expression P points to the last element of an array object, the expression (P)+1 points one past the last element of the array object, and if the expression Q points one past the last element of an array object, the expression (Q)-1 points to the last element of the array object. If both the pointer operand and the result point to elements of the same array object, or one past the last element of the array object, the evaluation shall not produce an overflow; otherwise, the behavior is undefined.



  • SeppJ schrieb:

    otze schrieb:

    Swordfish schrieb:

    Damit auch eine schöne Implementierung dasteht:

    könnte die überlaufen? Ist es garantiert, dass das letzte byte im addressraum nicht belegt werden kann?

    Da dachte ich auch sofort dran [...]

    Zählen darf ich, wohin ich will. Nur dereferenzieren nicht.

    // und unsigneds dürfen auch überlaufen soviel sie wollen. Wenn mir dagegen der Benutzer einen String gibt, der nicht Nullterminiert ist, ist er selber schuld.



  • Swordfish schrieb:

    SeppJ schrieb:

    otze schrieb:

    Swordfish schrieb:

    Damit auch eine schöne Implementierung dasteht:

    könnte die überlaufen? Ist es garantiert, dass das letzte byte im addressraum nicht belegt werden kann?

    Da dachte ich auch sofort dran [...]

    Zählen darf ich, wohin ich will. Nur dereferenzieren nich

    Nein, Pointerarithmetik ist nur innerhalb arraygrenzen erlaubt.



  • Swordfish schrieb:

    Zählen darf ich, wohin ich will. Nur dereferenzieren nicht.

    problem ist nur, wenn durch einen Überlauf p=0 ist. Dann gibt p - str - 1 nicht das richtige.

    //edit doch, klar. überlauf ist ja definiert.



  • otze schrieb:

    Swordfish schrieb:

    Zählen darf ich, wohin ich will. Nur dereferenzieren nicht.

    problem ist nur, wenn durch einen Überlauf p=0 ist. Dann gibt p - str - 1 nicht das richtige.

    //edit doch, klar. überlauf ist ja definiert.

    Üherlauf für Pointer ist nicht definiert, da er nie auftreten kann! Es ist legal, bis eins hinters Ende eines Arrays zu zählen, egal wo das Array ist.
    Weitere Pointerarithmetik ist dann UB.



  • Nathan schrieb:

    Üherlauf für Pointer ist nicht definiert, da er nie auftreten kann! Es ist legal, bis eins hinters Ende eines Arrays zu zählen, egal wo das Array ist.
    Weitere Pointerarithmetik ist dann UB.

    Ist mir bekannt, ich war in der lage deinen post zu lesen bevor ich geantwortet hatte. Das war auf Swordfish bezogen.


Anmelden zum Antworten