Wie funktioniert tolower?



  • int tolower(int ch) {
        return ch|32;
    }
    


  • Die string Klasse baut auf C-Strings (char*) auf, und bildet somit nur eine komfortable Schnittstelle, bei der sich der Benutzer nicht mehr um die riskante Speicherverwaltung (und mehr) kümmern muss. Ein char* ist nichts anderes als ein Zeiger, der auf die erste Speicheradresse einer beliebigen Zeichenkette zeigt. Inkrementiert man jedoch den Zeiger (also erhöht die Speicheradresse um 1) zeigt er auf das zweite Zeichen der Zeichenkette usw.. Das Ende des Strings (Zeichenkette) wird mit einer '\0' markiert.

    char *text = "Das ist ein Beispieltext";
        // Der Inhalt jeder darauffolgenden Speicheradresse,
        // auf die der Zeiger zeigt wird solange ausgegeben,
        // bis eine 0 auftritt, die das Ende markiert.
        std::cout<<text<<std::endl;
    
        // Das ganze kann man jetzt auch manuell machen:
        std::cout<<*text;
        ++text; // Adresse, auf die der Zeiger zeigt, wird um eins erhöht.
        std::cout<<*text;
        // usw.
    

    Weiterführendes: http://www.pronix.de/pronix-745.html
    Und ein Buch wäre eine Anschaffung wert, da dies absolute Grundlagen sind.

    MfG mikey.



  • Brutus schrieb:

    int tolower(int ch) {
        return ch|32;
    }
    
    int tolower(int ch) 
    {
       if (ch >= 'A' && ch <= 'Z')
          return ch|32;
       return ch;
    }
    

    🙂



  • Brutus schrieb:

    int tolower(int ch) {
        return ch|32;
    }
    

    🙂

    tolower dürfte in den meisten Standard-Libraries glaube ich komplexer implementiert sein und auf die Locales zurück greifen.



  • Hallo zusammen,

    wie aber verwendet man tolower oder toupper möglichst unkompliziert auf einer ganzen Zeichenkette? Bis jetzt verwende ich immer folgende Variante. Beispiel:

    #include <iostream>
    #include <string>
    #include <algorithm>
    #include <ctype.h>
    using namespace std;
    
    int f_tolower(int x) {
            return tolower(x);
    }
    
    int main() {
            string s = "KeIN langWEILIGER StAnDarDSPRUCH!";
            transform(s.begin(), s.end(), s.begin(), &f_tolower);
    
            /* transform(s.begin(), s.end(), s.begin(), &tolower)
             * funktioniert leider nicht */
    
            cout << s << endl;
    }
    

    Geht das auch noch einfacher? Gibt es eine derartige Funktion oder gar ein Funktionsobjekt?

    Grüße Martin



  • Was genau funktioniert denn an transform(...,tolower); nicht?



  • CStoll schrieb:

    Was genau funktioniert denn an transform(...,tolower); nicht?

    Ich nehme an (und luck_tux' Nickname bestätigt mich irgendwo dabei), dass er unter Linux arbeitet. Hier sind tolower und toupper irgendwelche Makros o.ä.. Jedenfalls nichts was der g++ in diversen Versionen (ich glaube bis hin zur aktuellen) als Funktionspointer erkennen würde.

    Ich habs unter Linux bisher auch immer wie oben machen müssen. (Allerdings war mein my_tolower immer inline 😉 )



  • lucky_tux schrieb:

    Hallo zusammen,

    wie aber verwendet man tolower oder toupper möglichst unkompliziert auf einer ganzen Zeichenkette? Bis jetzt verwende ich immer folgende Variante. Beispiel:

    #include <iostream>
    #include <string>
    #include <algorithm>
    #include <ctype.h>
    using namespace std;
    
    int f_tolower(int x) {
            return tolower(x);
    }
    
    int main() {
            string s = "KeIN langWEILIGER StAnDarDSPRUCH!";
            transform(s.begin(), s.end(), s.begin(), &f_tolower);
    
            /* transform(s.begin(), s.end(), s.begin(), &tolower)
             * funktioniert leider nicht */
    
            cout << s << endl;
    }
    

    Geht das auch noch einfacher? Gibt es eine derartige Funktion oder gar ein Funktionsobjekt?

    Grüße Martin

    Also eigentlich finde ich das schon ziemlich optimal: Sagt Genau und minimal das aus, was man tut: "Transformiere aus einem string (von begin bis end) in einen anderen mit tolower" .....
    Kürzer und sprechender geht's IMO nicht - höchstens, indem man sich auf komplette strings bezieht, könnte man noch einen Parameter loswerden.

    Unschön finde ich aber auch, dass tolower eine int-Signatur hat ... Besseres fällt mir da im Augenblick auch nicht ein (wundert mich, dass man einen anderen Namen verwenden muss und kein normaler Overload funktikoniert, weiß aber auch nicht, warum).

    Gruß,

    Simon2.



  • Schreibe ich

    transform(s.begin(), s.end(), s.begin(), &tolower);
    

    so lässt sich das Beispiel nicht kompilieren:

    # g++ main.cpp
    main.cpp:10: error: no matching function for call to 'transform(__gnu_cxx::__normal_iterator<char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, __gnu_cxx::__normal_iterator<char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, __gnu_cxx::__normal_iterator<char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, <unresolved overloaded function type>)'

    Ich gehe davon aus, dass Präprozessordirektiven verwendet wurden. Leider habe ich momentan nicht die Möglichkeit das nachzuprüfen. Vlt. wagt ja jemand einen Blick in ctype? ...

    Grüße Martin

    --
    Anmerkung: Da waren Andere schneller... Hab mir wohl ein wenig Zeit beim Tippen gelassen 🙂



  • Jetzt brat mir n Storch und die Beine recht knusprig...

    Kann das Problem (welches ich definitiv auch schon hatte in genau dieser Form) gerade weder mit nem 3.2er noch mit nem 4.1er g++ nachstellen.



  • Hi,

    also ich habe keine Probleme, das nachzustellen (g++ (GCC) 3.4.4 (cygming special) (gdc 0.12, using dmd 0.125)).

    In der ctype finde ich:
    int __cdecl tolower(int);

    Im Standard steht

    ISO/IEC 14882: 2003 (Secon Edition); Kap. 22.1.3.2.2 schrieb:

    template <class charT> charT tolower(charT c, const locale& loc);
    Returns: use_facet<ctype<charT> >(loc).tolower(c) .

    Gruß,

    Simon2.



  • Hallo,

    $ g++-2.95 --version
    2.95.4

    $ g++-2.95 main.cpp

    $ g++-4.1 --version
    g++-4.1 (GCC) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)
    Copyright (C) 2006 Free Software Foundation, Inc.
    This is free software; see the source for copying conditions. There is NO
    warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

    $ g++-4.1 main.cpp
    main.cpp: In function 'int main()':
    main.cpp:10: error: no matching function for call to 'transform(__gnu_cxx::__normal_iterator<char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, __gnu_cxx::__normal_iterator<char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, __gnu_cxx::__normal_iterator<char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, <unresolved overloaded function type>)'

    Mit einem alten Compiler und einer älteren libstdc++ funktioniert alles wunderbar. Meinermeinung nach sollte man jedoch nicht darauf vertrauen, dass die "richtige" Version verwendet wird, sondern möglichst kompatiblen Code schreiben, auch wenn dieser ein wenig komplexer und/oder einen größeren Umfang besitzt.

    Grüße Martin



  • LordJaxom schrieb:

    CStoll schrieb:

    Was genau funktioniert denn an transform(...,tolower); nicht?

    Ich nehme an (und luck_tux' Nickname bestätigt mich irgendwo dabei), dass er unter Linux arbeitet. Hier sind tolower und toupper irgendwelche Makros o.ä.. Jedenfalls nichts was der g++ in diversen Versionen (ich glaube bis hin zur aktuellen) als Funktionspointer erkennen würde.

    Ich habs unter Linux bisher auch immer wie oben machen müssen. (Allerdings war mein my_tolower immer inline 😉 )

    Ich denke ihr beobachtet hier ein anderes Problem: tolower ist, in abhängigkeit der inkludiereten Header, ein überladener Name, was einen Aufruf von transform(..., &tolower) ungültig macht. Ein Cast schafft abhilfe: transform(..., static_cast<int(*)(int)>(tolower)). Korrekt ist das Ergebnis aber nicht, zumindest, wenn char != unsigned char ist. Wie ich hier schon ca. 1 Millionen mal geschrieben habe, muss man bei char != unsigned char die Zeichen erst nach unsigned char casten, bevor man sie an tolower übergibt.

    Sinnvoll wäre also:

    inline int myTolower(int c) {
       return std::tolower(static_cast<unsigned char>(c));
    }
    
    ...
    transform(..., myTolower);
    


  • Äh ich hätt da noch eine Frage zum Thema, wie kann ich die Buchstabenlänge in einem string rausbekommen? Gibts da irgend eine Funktion? Also ich kenne "strlen", aber das geht ja nur bei char oder?
    Ähm und was ist der Unterschied zwischen "ctype.h" und "cctype"?
    Dankeschön schon mal im Voraus.



  • Stromberg schrieb:

    Äh ich hätt da noch eine Frage zum Thema, wie kann ich die Buchstabenlänge in einem string rausbekommen? Gibts da irgend eine Funktion? Also ich kenne "strlen", aber das geht ja nur bei char oder?

    Da gibt's sogar zwei - size() und length().

    Ähm und was ist der Unterschied zwischen "ctype.h" und "cctype"?
    Dankeschön schon mal im Voraus.

    <ctype.h> gehört zu C, <cctype> ist die C++ Entsprechung dazu (und definiert alle Funktionen im Namensraum 'std::').



  • CStoll schrieb:

    Stromberg schrieb:

    Äh ich hätt da noch eine Frage zum Thema, wie kann ich die Buchstabenlänge in einem string rausbekommen? Gibts da irgend eine Funktion? Also ich kenne "strlen", aber das geht ja nur bei char oder?

    Da gibt's sogar zwei - size() und length().

    hat das einen grund?
    sind die wirklich identisch?



  • Ja, ist historisch so entstanden (length() in Anlehnung an die String"länge", size() zur Verwendbarkeit als STL-Container). Und ja, die Methoden sind identisch.


Anmelden zum Antworten