C++ Stringoperationen im Vergleich zu C Stringoperationen, C++Anfänger



  • CStoll schrieb:

    OK, dann setze ich mal deinen Code um:

    string buffer,p,p1...;  //char buffer[1024],*p,*p1,*p2,*p3...usw;
    int pos,apos;
    
    buffer = String;        //strcpy(buffer,String);
    
    //Zahl am Anfang
    pos = buffer.find(" "); //p=strtok(buffer," ");
    if(pos==string::npos)   //if(p==NULL)
      throw("Fehler beim zerhacken des Strings");
    else
      p=buffer.substr(0,pos);
    
    //Name
    apos=pos+1;pos=buffer.find(",",apos);
                            //p1=strtok(NULL,",");
    if(apos==string::npos)
      throw("Fehler beim zerhacken des Strings");
    else
      p1=buffer.substr(apos,pos-apos);
    
    ...
    

    Denn nur das erste Zeichen finden bringt mir nichts,

    Das nette an find() und Kollegen ist, daß du auch eine Startposition angeben kannst - auf diese Weise suchst du beim nächsten Durchlauf hinter der letzten gefundenen Position weiter.

    Bei diesem Beispiel hier..da könnte ich doch das else weglassen, da er nach dem throw eh rausspringt, oder?

    Mondmann



  • Ja, könntest du eigentlich.



  • Ok.
    UND wie kann ich das jetzt darstellbar machen?
    Ich meine wenn ich in einem Messagebox:

    MessageBox(NULL,p_buf, "Erster Teilstring", MB_OK);
    

    ausgebem will, meckert der, daß er std:string nicht in LPCSTR umwandeln kann. Muss ich das machen?
    Generell?



  • std::string hat auch eine Methode c_str(), mit der du auf das unterliegende char-Array zugreifen kannst:

    MessageBox(NULL,p_buf.c_str(), "Erster Teilstring", MB_OK);
    

    PS: Im Zuge der UNICODE-Euphorie wäre vielleicht ein "typedef std::basic_string<TCHAR> tstring;" angebracht 😉



  • hmmmm...ich muss als immer wenn ich den String ausgeben will ihn mit c_st() konvertieren???(ich muss ihn ja immer ausgeben)
    Kommt mir jetzt etwas umständlich vor....



  • Hallo

    Du must gar nichts konvertieren, c_str() gibt nur einen Pointer auf das interne char-Array zurück.
    Und das must du auch nur dann machen, wenn du einen C-String brauchst. Bei den Standard-Streams aus der STL brauchst du das zum Beispiel nicht, diese verstehen direkt std::string.

    bis bald
    akari



  • ok alles klar. Mir fehlt einfach nur noch C++ Grundkenntnisse, es gibt ja genügend tutorials im Internet.

    Der größte Vorteil erschließt sich mir dadaurch, da0 ich mich nicht um den Speicher kümmern muss. Ansonsten wird es nicht umbedingt schneller sein..eher langsamer. Das werde ich dann bei weitaus größeren dieser meiner "operationen" schnell merken.

    Vielen Dank, Mondmann



  • Mondmann schrieb:

    ...Ansonsten wird es nicht umbedingt schneller sein...

    Ich denke, dass man auch nicht der Performance wegen von C auf C++ wechselt. Schließlich kommt man mit C-Code (den man glücklicherweise ja ebenso in C++ nutzen kann) nahezu beliebig tief auf die technische Ebene runter, auf denen man "optimal optimieren" ( 😉 ) kann.

    Es hat sich aber einfach in der Praxis heruasgestellt, dass viel an Ärger und Kosten gar nicht durch das eine oder andere % Performanceabstrich verursacht werden, sondern durch Dinge wie "Strukturierung". .... wie sonst hätte sich Java etablieren können 😉 ?

    Wie gesagt: Wo immer das letzte Quentchen an Performance wirklich wichtig ist (und man nicht durch 100 Euro Prozessorkauf 50 Tage Tun-/Testing sparen kann), kann man in C++ immer noch dieselben "Spezialitäten" machen wie unter C.

    Gruß,

    Simon2.



  • Womit ich ein weiteres Problem hätte.

    Die Funktion(nicht von mir) die den Stream an den Webbrowser schickt,ist ne C-Funktion.
    Da ich aber jetzt lauter string-Objekte habe müsste ich viel in der Gegend herum konvertieren.ich schätze damit ist alles hinfällig.

    Hier die definition:

    BOOL (WINAPI * WriteClient)  ( HCONN      ConnID,
                                       LPVOID     Buffer,
                                       LPDWORD    lpdwBytes,
                                       DWORD      dwReserved );
    

    es geht um die mittleren beiden Argumente.

    bisher hatte ich ebenen ein großes C-Array das den komplette HTML COde enthielt.
    JEtzt habe ich ein string objekt.

    Mit buffer.c_str() lässt er sich nicht abspeisen.
    Das 3. Argument hatte infach nur die Länge des C-Strings. (strlen)

    So sieht das aus:

    pECB_SEND->WriteClient(pECB_SEND->ConnID, buffer, &bufsiz, dwReserved);
    

    Das erste und letzte Argument lasst mal mein Bier sein:-)

    DWORD buflen_str;
    std::string main1=main
    
    buflen_str=header.length()+footer.length()+menue.length()+top.length()+main1.length();
    
    //bisher
    //	char* buffer=(char*)calloc(buflen,sizeof(char*));
    //	if(buffer==NULL){throw("Fehler beim SEND Fehlernummer 347");}
    
    //jetzt
    std::string buffer;
    
    //bisher 	if(!(_snprintf_s(buffer,buflen,_TRUNCATE,"%s%s%s%s%s",header,top,menue,main, footer)))
    	//	throw("Fehler beim erzeugen des Strings (genehmigung/372)");
    
    //jetzt
    buffer=header+top+menue+main+footer;	
    
    pECB2->WriteClient(pECB2->ConnID, buffer, &buflen_str, dwReserved);
    

    Fehlermeldungen:

    Fehler 10 error C2664: 'BOOL (HCONN,LPVOID,LPDWORD,DWORD)': Konvertierung des Parameters 2 von 'std::string' in 'LPVOID' nicht möglich

    Da es ja ein LP ist, kriege ich es hin, wenn ich &buffer angebe. Nur ist dann nichts mehr drin.
    Wenn ich zuvor kontrolliere, ist der Buffer randvoll mit dem korrekten HTML Code.

    Wie kriege ich das hin?



  • Mit &buffer kommst du nur an ein paar Kontrollstrukturen der Klasse. An die tatsächlichen Textdaten kommst du per buffer.c_str().



  • Na ja - natürlich ist das schneller, einen festen Puffer auf den Stack anzulegen. Und noch schneller ist es, wenn ich darauf verzichte, die Puffergrösse zu überprüfen. Das Ergebnis sind zahlreiche Sicherheitslücken durch Pufferüberläufe.

    Wenn ich in C genau das implementiere, was ich in C++ habe, ist C nicht schneller. Nur umständlicher.

    Man denke nur an dieses einfache Beispiel mit Strings. Statt eines festen Puffers müsste ich zunächst mit malloc so viel Speicher reservieren, wie ich benötige, prüfen, ob die Allokation erfolgreich war und dann mit strcpy meine Daten hinein kopieren. Wenn ich die Funktion verlasse, muß ich dann mit free den Speicher wieder frei geben.

    In der Praxis macht man sich mit C nicht die Mühe es so richtig zu machen. C++ macht es uns halt einfach es richtig zu machen. Das Ergebnis sind Programme, die langsamer sind, weil sie richtig sind.

    Tntnet



  • CStoll schrieb:

    Mit &buffer kommst du nur an ein paar Kontrollstrukturen der Klasse. An die tatsächlichen Textdaten kommst du per buffer.c_str().

    Wie gesagt,das funktioniert leider nicht.
    Wenn ich das mit buffer.c_str() mache kommt Fehlermeldung:

    Fehler 10 error C2664: 'BOOL (HCONN,LPVOID,LPDWORD,DWORD)': Konvertierung des Parameters 2 von '*const char ' in 'LPVOID' nicht möglich.

    Ich denke auch, daß es so gehen müsste, tuts aber leider nicht...

    Woran könnte das liegen?



  • An dem verd... const. Wenn du dir ganz sicher bist, daß WriteClient() die übergebenen Daten nicht verändern wird, darfst du das ausnahmsweise casten als "(LPVOID) buffer.c_str()" (aber da mußt du genau wissen, was du machst - der Compiler kontrolliert nämlich jetzt nicht mehr).

    (Anmerkung: Wenn WriteClient() tatsächlich in den String schreiben will, kommst du um ein char-Array nicht herum)



  • Mondmann schrieb:

    ...
    Fehler 10 error C2664: 'BOOL (HCONN,LPVOID,LPDWORD,DWORD)': Konvertierung des Parameters 2 von '*const char ' in 'LPVOID' nicht möglich.

    Ich denke auch, daß es so gehen müsste, tuts aber leider nicht...

    Woran könnte das liegen?

    Ist auch klar: Wie schon gesagt, liefert Dir c_str() einen const char*, in den nicht geschrieben werden darf.
    Wenn Du einen "beschreibbaren" char-Buffer brauchst, musst Du ihn anlegen.
    z.B.

    ...
        std::string myS("Meine Zeichenkette");
    
        // StringDaten -> char[]
        char* myBuf = new char[myS.size() + 1];
        strcpy(myBuf, myS.c_str());
    
        callMyCAPI(myBuf);
    
        // char[]-Daten -> String
        myS = std::string(myBuf);
        delete[] myBuf;
        ...
    

    oder so ähnlich.

    Das Ganze wird klarer, wenn man "Kapselung" ernst nimmt: std::string kapselt die Daten und bietet gesicherte Zugriffe (damit man nicht mehr schreibt, als "geht". Da Du in C mit einem Pointer beliebig viel schreiben kannst, bietet std::string nicht an).
    Wie die Klasse die Daten intern ablegt, ist nicht festgelegt.

    Wenn Du nun die Daten in einem bestimmten Format vorliegen haben mußt (wie hier: Als aneinanderfolgende bytes im Speicher ab einer bestimmten Adresse), mußt Du eine entsprechende Umformung machen. Dafür bietet std::string Dir entsprechende Methoden an (c_str() oder operator[]()), die natürlich dafür sorgen, dass die interne Konsistenz der Daten gewährleistet bleibt.

    Gruß,

    Simon2.



  • Das mit dem casten wollte ich eben vermeiden und es funktioniert auch nicht, es fehlt die Hälfte...
    Also kann ich das Ganze mit dem schönen, einfachen C++ Handling vergessen und muss es lassen wie es ist?(mit dem lästigen mallos, free,strtok..)

    *heul*



  • Mondmann schrieb:

    ...
    Also kann ich das Ganze mit dem schönen, einfachen C++ Handling vergessen und muss es lassen wie es ist?(mit dem lästigen mallos, free,strtok..)...

    Wieso das ?
    Du brauchst nur "eine C-compatible Zwischenschicht" für die C-API-Funktionen (z.B. über "meinen" Mechanismus). Alle eigene Fachlichkeit kannst Du dann mit strings machen.

    Gruß,

    Simon2.



  • Mondmann schrieb:

    Das mit dem casten wollte ich eben vermeiden und es funktioniert auch nicht, es fehlt die Hälfte...

    Vielleicht solltest du die Länge erst berechnen, nachdem du den String zusammengesetzt hast:

    buffer=header+top+menue+main+footer;
    buflen_str = buffer.length();
    


  • Ok es klappt.
    Mit der "zwischenschicht" funktionierts einfandfrei.

    Denke, langsam schnalle ich die Sache, zumal ich mich das erstemal mit der Materie auseinandersetze.

    Vielern, herzlichen Dank für Eure große Hilfe.
    Jetzt habe ich erst mal was zu tun....

    Grüße Mondmann



  • hm..nochmal ne blöde Frage.
    Was könnte ich denn für sprintf schreiben in C++?

    sprintf(buff,"%s %i","Fehlernummer, 100);

    Mondmann



  • std::ostringstream s;
    s << "Fehlernummer " << 100;
    std::string msg = s.str();
    

    Tntnet


Anmelden zum Antworten