char an char* anhängen



  • Hey,
    ich möchte ein zeichen an eine Zeichenkette anhängen, bzw an einen LPSTR.

    Ein LPSTR ist ja char* mit \0 am ende als terminator.

    strcat( ) funktioniert leider nicht bei zeichen, sondern nur bei zeichenketten.

    kann man einfach

    LPSTR a = "hall";
    LPSTR b = "hallo1234";
    
    int pos=0;
    while(a[pos] != '\0'){
       pos++;
    }
    
    a[pos] = b[4];
    a[pos+1] = '\0';
    

    bei der variante bin ich mir aber unsicher, weil es kann doch sein, wenn ich was an den speicherbereichhänge, dass ich was anderes überschreibe oder?

    gibt es eine andere möglichkeit ein zeichen, z.b. string[zeichenindex], an ein string zu hängen?



  • Zeile 4-7 deines Codes kannst du durch strlen abkürzen.

    In a solltest du gar nichts ändern, da dies ein Zeiger auf einen Konstanten String ist, also einen Speicherbereich, an dem nichts mehr geändert werden sollte.
    Stattdessen solltest du einen neuen Speicherbereich reservieren, der groß genug ist, um den Inhalt aus a + das neue Zeichen speichern zu können. Anschließend kopiert du a dort rein und fügst dein Zeichen und das Terminierungszeichen hinzu.



  • LPSTR a = "hall";
    //bzw.
    char *a = "hall";
    

    Das sollte gar nicht erst kompilieren. "hall" ist nämlich nicht beschreibbar und a zeigt nur auf "hall".

    LPCSTR a = "hall";
    //bzw.
    const char *a = "hall";
    

    Jetzt ist es korrekt, aber an nicht beschreibbare Strings kannst du natürlich nichts anhängen.

    char a[] = "hall";
    

    Jetzt ist a ein beschreibbares Array mit Inhalt "hall", hat aber nur 5 Bytes Speicher (4 für hall + 1 für \0). Daher wird beim Anhängen irgendwas kaputt gehen, möglicherweise was wichtiges.

    char a[6] = "hall";
    

    Jetzt haben wir ein Byte extra und können sowas machen:

    a[4] = 'o';
    a[5] = '\0';
    //a enthält jetzt "hallo"
    

    Zeichen angehängt.

    Möglicherweise willst du auch Kopien von Strings.

    const char *a = "hall";
    char *b = malloc(strlen(a) + 1 + 1); //eins extra für '\0' und eins extra fürs drangehängte
    strcpy(b, a);
    b[strlen(a)] = 'o';
    b[strlen(a) + 1] = '\0';
    //vergiss nicht irgendwann
    free(b);
    //zu machen
    

    Speicher verwalten ist anstrengend. Vielleicht willst du auch C++ verwenden.

    string s = "hall";
    s += 'o';
    s += " welt!";
    


  • In C++: std::string::push_back.
    In C: Ein zwei char großes Array erstellen, an Index 0 kommt das Zeichen, an Index 2 das Nullbyte und dann strcat verwenden.
    Oder tricksen:

    strncat(str, &c, 1);
    

    (ungetestet)
    Trotzdem wächst der String nicht magisch!

    Zu deinem Einsatz:
    Sollte noch nicht einmal kompilieren.
    LPSTR ist ein Typedef für char*, das kann man nicht auf ein konstantes (!) Stringliteral zeigen lassen.
    Außerdem greifts du auf Speicher zu, der dir nicht gehört.
    (In C wachsen Strings nicht, nur wenn du auf ein neues Zeichen zugreifts (in C++ so direkt zwar auch nicht, aber...)).

    Edit: So spät!?



  • wenn ich meine variante ausführe, bekomm ich immer ne zugriffsverletzung. wahrscheinlich wie ich vermutet habe, weil ich außerhalb des speicherbereichs schreiben will.

    da habe ich die frage, ob ich nicht einfach neuen speicherplatz reservieren kann mit der größe vom string + 1byte?

    LPSTR a = "hall";
    
    LPSTR b = (LPSTR) malloc(sizeof(a)+1);
    
    strcpy(b, a, 10);
    strcat(b, 'o');
    
    a=b;
    

    Was passiert dann mit dem Speicher vorauf a gezeigt hat? Wird der dann automatisch gefreed?

    Wird b beim Programmende automatisch gefreed oder bleibt b im ram bis systemneustart?

    Edit: hehe, da haben alle gleichzeitig geschrieben und auf einige fragen auf diesen post schon beantwortet 🙂 Danke für die reichlichen antworten.

    Die Sache ist, dass ich ne funktion wie strcat schreiben möchte, die ein einzelnes zeichen an ein LPSTR anhängt. quasi

    strcat( LPSTR dest, char zeichen );
    


  • Wie du schon festgestellt hast erwartet strcat einen String und kein char und tut deshalb Blödsinn.
    Folgendes ginge:

    LPSTR a = "hall";
    
    LPSTR b = (LPSTR) malloc(strlen(a)+2); //sizeof a tut nicht was du willst, siehe unten
    
    strcpy(b, a); //, 10); wieso 10?
    strcat(b, "o"); //hier war vorher die Speicherverletzung
    
    a=b; //a und b zeigen auf dieselbe Zeichenkette, aber in dieser Zeile passiert nichts mit Zeichenketten oder Speicher
    

    Zum sizeof a: a ist ein Pointer auf einen String. sizeof a gibt dir die Größe des Pointers, nicht des Strings. Mach entweder ein Array draus wie ich oben beschrieben habe oder benutze strlen + 1 fürs '\0'-Byte

    In C passiert praktisch nichts automatisch was CPU oder Speicher kostet. Speicher frei geben passiert nicht automatisch.
    Der Speicher, auf den a zeigt kann aber eh nicht freigegeben werden, weil er nicht mit malloc angefordert wurde. Ansonsten wäre er verloren, nennt sich dann Speicherleck.



  • hey, ich habe mein problem jetzt fast so gelöst

    void con( LPSTR dest, char item ){
    
    	LPSTR temp = (LPSTR) malloc(strlen(dest)+2);
    
    	strcpy(temp, dest);
    	temp[strlen(dest)] = item;
    	temp[strlen(dest)+1] = '\0';
    
    	strcpy(dest , temp);   // zugriffsverletzung (weiß auch warum)
    	free(temp);
    }
    
    int main() {
    
    	LPSTR b="hall";
    	con(b, 'o');
    
    	printf("%s\n", b);
    
    	getch();
    	return 0;
    }
    

    ich möchte halt, dass sich mein b in main() ändert, so als wenn man strcat() benutzt. meine idee war es vorher, den pointer von a aus der funktion auf den neuen speicherbereich umzubiegen und den alten speicherbereich zu löschen ( was ja beim ersten funktionsaufruf nicht geht, weil die erste variable nicht durch malloc erzeugt wurde).

    Edit: und ich möchte natürlich auch kein speicherleck, was ziemlich unpraktisch wäre. Es denke es wäre wirklich wesentlich einfacher die <string> header zu benutzen, aber das prinzip so zu verstehen, kann natürlich nie schaden



  • Variante 1:
    Du schreibst einfach in den Speicher, ob du darfst oder nicht. Vorteil: Es ist einfach und strcat machts genauso. Nachteil: Der Aufrufende muss einen String mit genug beschreibbarem Speicher übergeben (wie bei strcat) sonst stürzt das Programm ab.

    void con(char *s, char c){
    	size_t l = strlen(s);
    	s[l] = c;
    	s[l+1] = '\0';
    }
    

    Sowas wie con("Hall", 'o') funktioniert nicht, aber strcat("Hall", "o") funktioniert ja auch nicht.

    Variante 2:
    Du erzeugst einen neuen String. Vorteil: Man kann Stringliterale benutzen. Nachteil: Der Aufrufende muss den Speicher frei geben.

    char *con(const char *s, char c){
    	size_t l = strlen(s);
    	char *b = malloc(l + 2);
    	strcpy(b, s);
    	b[l] = c;
    	b[l+1] = '\0';
    	return b;
    }
    

    Damit funktioniert dann char *s = con("Hall", 'o').

    Noch eine kleine Sache zur Sprechweise:
    "Ich möchte dass sich mein b in main ändert" geht nicht. In C werden Parameter immer als Wert übergeben, b kann also niemals durch eine Funktion, der b übergeben wird (tatsächlich wird nicht b sondern der Wert von b übergeben), geändert werden.
    Was du meinst ist, dass b auf Speicher zeigt und con den Speicher ändert, auf den b zeigt. b bleibt dabei unberührt.

    Wenn man das aber möchte, kann man durchaus b ändern.

    void con(char **s, char c){
    	size_t l = strlen(*s);
    	char *b = malloc(l + 2);
    	strcpy(b, *s);
    	b[l] = c;
    	b[l+1] = '\0';
    	//hier könnte man über ein free(*s) nachdenken
    	*s = b;
    }
    

    Jetzt kannst du einen Zeiger auf b übergeben, wodurch tatsächlich b überschrieben werden kann.
    Benutzung:

    int main() {
    
        LPSTR b="hall";
        con(&b, 'o'); //das & braucht man, um die Adresse von b zu kriegen
    
        printf("%s\n", b);
    
        getch();
        return 0;
    }
    

Anmelden zum Antworten