Teil eines nullterminierten C-Strings eine C++ string zuweisen



  • Hallo,

    Bin in C++ nicht so fit, da ich sonst in Delphi programmiere. Durch suchen habe ich keine Lösung gefunden, deshalb frage ich euch: Wie wird in C++ ein Teil eines nullterminierten C-Strings einem C++ string zugewiesen?

    #include <iostream>
    #include <string>
    using namespace std;
    void main(void)
    {
    // gegeben:
      string s; // Die Zielvariable 
      char *p = "C++ ist kompliziert\0";  // Zeigt auf den Anfang der Zeichenkette
      int len = 8;  // Anzahl der Zeichen die kopiert werden sollen 
    // gesucht:  s == "C++ ist "
    
    }
    

    In Delphi wäre das:

    SetString(s, p, len);
    

    Hoffe in C++ geht das genauso einfach.


  • Mod

    s.assign(p,len); // oder:
    s=string(p,len); // oder gleich bei der Initialisierung:
    string s(p,len);
    


  • Danke camper, Perfekt!



  • Hi BerndD,

    noch zwei kleine Anmerkungen:

    BerndD schrieb:

    ...
      char *p = "C++ ist kompliziert\0";  // Zeigt auf den Anfang der Zeichenkette
    ...
    

    Das '\0' am Ende braucht's IIRC nicht.

    Das "Zurechtmachen (Beschneiden, ...) von std::strings ist viel einfacher als mit CStrings:

    string s = "C++ ist unkompliziert"; 
      string shortStr = s.substr(0, 8);
    ...
    

    Gruß,

    Simon2.



  • Hallo Simon,

    Simon2 schrieb:

    Das '\0' am Ende braucht's IIRC nicht.

    Du meinst weil len das Einlesen sowieso begrenzt? Das war natürlich nur ein Simpel-Beispiel um die Beantwortung zu vereinfachen. Allgemein gesehen denke ich, dass der Nullabschluss nicht weggelassen werden darf.

    ...
      char *p = "C++ ist kompliziert";
      s=string(p, 100);
      ...
    

    Hier würde doch über das Ende drüber weg lesen!?

    Ich habe bereits das nächste Problem und liefere zur Beschreibung wieder ein Simpel-Programm zum Nachvollziehen:

    #include <vector>
    #include <iostream>
    using namespace std;   
    
    typedef vector< vector<int> > int2d;
    
    void append(int2d &v, int value)
    {
      vector <int> i;
      i.push_back(value); 
      v.push_back( i ); 
    }
    
    void main(void)
    {
       int2d v;
       append(v, 42);
       cout << "v[0][0] : " << v[0][0] << endl; // Ausgabe: "v[0][0] : 42"
    }
    

    Dieses Programm funktioniert zwar, ich glaube aber das die drei Zeilen in der Funktion append nicht sehr effizient arbeiten. Ich bekomme es aber nicht besser hin, weil ich nicht weiß, wie ich das ohne Zwischenvariable bewerkstelligen könnte.
    Ist meine Vermutung richtig, dass i angelegt wird, dann bei Übergabe nach v eine Kopie davon erstellt wird und beim Verlassen von append i wieder freigegeben wird? Sicher gibt es da eine bessere Lösung.



  • BerndD schrieb:

    Hallo Simon,
    Du meinst weil len das Einlesen sowieso begrenzt? Das war natürlich nur ein Simpel-Beispiel um die Beantwortung zu vereinfachen. Allgemein gesehen denke ich, dass der Nullabschluss nicht weggelassen werden darf.

    ...
      char *p = "C++ ist kompliziert";
      s=string(p, 100);
      ...
    

    Hier würde doch über das Ende drüber weg lesen!?

    In diesem Fall würde er. Aber nur, weil Du 100 als Länge angibst. Da string auch Nullbytes in Strings verwalten kann, verlässt es sich hier darauf, dass Du die korrekte Länge übergibst. Das hat aber nichts mit der Nullterminierung zu tun.

    Wenn Du in C(++) ein String-Literal a la "TEXT" benutzt, generiert der Compiler automatisch immer einen Bereich der ein Zeichen länger ist und hängt ein Nullbyte an. Wenn Du also "TEXT\0" schreibst, hast Du zwei Nullbytes.

    s = string(p);
    

    Hier sucht string selbst in dem übergebenen Bereich nach dem Nullbyte, rechnet also die Länge selbst aus.



  • LordJaxom hats schon gesagt. In diesem Fall wird automatisch ein 0-Byte rangehangen.

    Dein append könntest du dir so verbessern:

    void appen(int2d &v, int value)
    {
       v.push_back(vector<int>(1,value));
    }
    

    Kann aber auch sein das dein Compiler deinen Code ehe zu sowas optimiert ...



  • Vielen Dank an euch, jetzt habe ich verstanden was Simon meinte.

    KasF schrieb:

    Dein append könntest du dir so verbessern:

    void appen(int2d &v, int value)
    {
       v.push_back(vector<int>(1,value));
    }
    

    Kann aber auch sein das dein Compiler deinen Code ehe zu sowas optimiert ...

    Genau das habe ich gesucht. Um selbst drauf zu kommen hätte ich die Parameterlisten der Konstruktoren gebraucht. In Delphi würde ich einfach im Quelltext nachschauen.

    Vielen Dank für eure Hilfe
    Bernd





  • BerndD schrieb:

    Hallo Simon,

    Simon2 schrieb:

    Das '\0' am Ende braucht's IIRC nicht.

    Du meinst weil len das Einlesen sowieso begrenzt? ...

    Nein, sondern weil "TEST" ein Stringliteral ist, das im Speicher 5 Byte belegt mit dem Inhalt {'T', 'E', 'S', 'T', '\0' }.
    Anders ausgedrückt: Stringliterale sind automatisch mit 0-terminiert (nur einmal, also char text[] = "ABC" "DE"; hat KEIN '\0' hinter dem 'C');

    Gruß,

    Simon2.



  • Habs nicht getestet aber sollte nicht auch einfach

    char* Test = "Mal sehen";
    string s = Test;
    

    funktionieren ?



  • Foxx90 schrieb:

    Habs nicht getestet aber sollte nicht auch einfach

    char* Test = "Mal sehen";
    string s = Test;
    

    funktionieren ?

    ... und den char* braucht's auch nichtmal:

    Simon2 schrieb:

    string s = "C++ ist unkompliziert"; 
      string shortStr = s.substr(0, 8);
    ...
    

    Gruß,

    Simon2.



  • KasF schrieb:

    http://www.cppreference.com/cppvector/vector_constructors.html 😉

    Danke der Link ist hilfreich.

    Also das mit char* auf string habe ich jetzt wirklich begriffen ;).

    Vielleicht Interessiert es euch was ich eigentlich Programmiere – mit Sicherheit gibt es das schon irgendwo und ich mache mir die Mühe umsonst. Naja, lerne dabei natürlich auch was – nicht zuletzt durch eure Hilfe jetzt.

    Für eine DLL, die Sprachunabhängig sein soll habe ich eine Klasse programmiert die ein Zeiger auf einen Speicherbereich und ein Zeiger auf eine ReallocMemory-Funktion übergeben bekommt. Im Speicher befindet sich eine INI-Datei. Über die INI-Datei kann das Hauptprogramm mit der DLL sprachunabhängig Parameter austauschen. Die DLL nutzt also die Speicherverwaltung des aufrufenden Programms. Ist ein guter Kompromiss zwischen Flexibilität und Geschwindigkeit. Habe mich schon oft selbst zu diesem Konzept beglückwünscht, weil sie ziemlich tragfähig in Bezug auf schnelle Programmerweiterungen ist. Und als Pluspunkte kommt noch hinzu, dass ich im selben Format die Daten in eine Datei abspeichern kann.

    Bisher war alles in Delphi geschrieben. Nun möchte ich die DLL aber für C bzw. C++ Programmierer, die unsere Anwendung benutzen wollen/sollen, offenlegen. Daher muss ich die komplette DLL in C++ umschreiben.


Anmelden zum Antworten