Weisen Sie Speicher zu und speichern Sie die Zeichenfolge in c

Lesezeit: 6 Minuten

Ich habe mich gefragt, warum der folgende Code nicht funktioniert

int main(int argc, char **argv)
{
     char *test = (char*) malloc(12*sizeof(char));
     test = "testingonly";
     free(test);
}

Nachdem ich darüber nachgedacht hatte, war meine Annahme, dass ich zuerst Platz für 12 Zeichen im Speicher zuweise, aber die Zuweisung in der nächsten Zeile ein Zeichenarray auf dem Stapel erstellt und die Speicheradresse davon zum Testen übergeben wird. free() versucht also, Speicherplatz auf dem Stack freizugeben, was nicht erlaubt ist. Ist das korrekt?

Was wäre also der richtige Ansatz, um einen String auf dem Heap zu speichern? Ist das Folgende ein gängiger Weg?

int main(int argc, char **argv)
{
     char *test = (char*) malloc(12*sizeof(char));
     strcpy(test, "testingonly");
     free(test);
}

  • Die erste Lösung zeigt ein klassisches Speicherleck; Sie erhalten einen Zeiger auf einen zugewiesenen Speicher und verlieren dann die einzige Referenz darauf, wenn Sie den Zeiger dem Zeichenfolgenliteral zuweisen test. Danach gibt es für Sie keine legitime Möglichkeit, auf den zugewiesenen Speicher zu verweisen – ein Leck.

    – Jonathan Leffler

    22. Dezember 2011 um 6:44 Uhr

  • Niemals das Ergebnis von malloc in C typisieren, es ist sinnlos und verbirgt nur Fehler und Compiler-Warnungen.

    – Ludin

    22. Dezember 2011 um 7:37 Uhr

  • ja – verwenden strcpy oder strncpy oder memcpy. strncpy ist besser als strcpy, da es hilft, Pufferüberlaufprobleme zu vermeiden, während maximal N Zeichen kopiert werden.

    – Agnius Vasiliauskas

    22. Dezember 2011 um 8:55 Uhr

  • @0x69 strncpy hilft nicht gegen Pufferüberläufe, das ist ein Mythos. Denn strncpy wird zwar n Zeichen in einen Puffer schreiben, aber wenn in diesem Puffer kein Platz mehr ist, wird es keine Null-Terminierung des Strings schreiben. Es wird also dazu führen, dass das Programm genauso abstürzt und brennt wie strcpy. Die Lösung für beide Probleme ist natürlich, zu wissen, was man tut. Es gibt keine Probleme mit der Verwendung von strcpy, solange Sie die Art der Quelle und des Ziels kennen.

    – Ludin

    22. Dezember 2011 um 9:24 Uhr

  • Trotzdem denke ich, dass es besser ist, keine Nullterminierung in den Puffer zu schreiben, als Nullzeichen außerhalb des Puffers zu schreiben (Pufferüberlauf). Im ersten Fall – normalerweise sehen Sie beim Drucken einer solchen Zeichenfolge Datenmüll aus dem Speicher, während im zweiten Fall Ihr Programm auf JEDE unvorhersehbare Weise abstürzen kann. Ich denke also, dass der erste Fehlertyp im Code leichter zu lokalisieren ist als der zweite. Aber ich kann mich irren.

    – Agnius Vasiliauskas

    22. Dezember 2011 um 10:08 Uhr


Benutzer-Avatar
AndersK

char *test = (char*) malloc(12*sizeof(char));

        +-+-+-+-+-+-+-+-+-+-+-+-+
test--->|x|x|x|x|x|x|x|x|x|x|x|x|   (uninitialized memory, heap)
        +-+-+-+-+-+-+-+-+-+-+-+-+

test = "testingonly";

        +-+-+-+-+-+-+-+-+-+-+-+-+
test +  |x|x|x|x|x|x|x|x|x|x|x|x|
     |  +-+-+-+-+-+-+-+-+-+-+-+-+
     |  +-+-+-+-+-+-+-+-+-+-+-+-+
     +->|t|e|s|t|i|n|g|o|n|l|y|0|  
        +-+-+-+-+-+-+-+-+-+-+-+-+

free(test); // error, because test is no longer pointing to allocated space.

Anstatt den Zeiger zu ändern testmüssen Sie die Zeichenfolge kopieren "testingonly" in den zugewiesenen Platz mit zB strcpy oder verwenden strdup. Beachten Sie, dass Funktionen wie malloc und strdup Rückkehr NULL wenn nicht genügend Speicherplatz vorhanden ist und daher überprüft werden sollte.

char *test = (char*) malloc(12*sizeof(char));
strcpy(test, "testingonly");

        +-+-+-+-+-+-+-+-+-+-+-+-+
test--->|t|e|s|t|i|n|g|o|n|l|y|0|
        +-+-+-+-+-+-+-+-+-+-+-+-+

oder

char *test = strdup("testingonly");

        +-+-+-+-+-+-+-+-+-+-+-+-+
test--->|t|e|s|t|i|n|g|o|n|l|y|0|
        +-+-+-+-+-+-+-+-+-+-+-+-+

  • wie wäre es mit test[0] = 0 und dann test = ''desired string''?

    – Cătălina Sirbu

    23. August 2020 um 5:12 Uhr

  • Angenommen, Sie haben zuvor einen Test zugewiesen – dann Ihre erste Aussage test[0] = 0 wird das erste Zeichen auf \0 setzen, aber sobald Sie dies tun test = "desired string", test zeigt auf die neue Zeichenfolge irgendwo im Nur-Lese-Speicher (da es sich um ein Literal handelt). Sobald dieses Literal den Gültigkeitsbereich verlässt, zeigt test nicht mehr auf einen gültigen Speicher.

    – AndersK

    23. August 2020 um 15:15 Uhr


Sie haben Ihre Frage bereits beantwortet. Im Wesentlichen ist strcpy die geeignete Methode zum Kopieren von Zeichenfolgen.

  • Solange Sie wissen, dass der entsprechende Speicher bereits in der Zielzeichenfolge zugewiesen wurde und beide Zeichenfolgen nullterminiert sind.

    – David

    22. Dezember 2011 um 7:55 Uhr

Benutzer-Avatar
Matte

Die erste Version erstellt keine Zeichenfolge auf dem Stapel, aber Sie haben Recht, dass Sie dies nicht dürfen free es nach dem Auftrag. Zeichenfolgenliterale werden normalerweise in konstanten/schreibgeschützten Abschnitten des Speichers gespeichert. Die Zuordnung kopiert nichts, macht nur test zeigen auf diesen Bereich der Erinnerung. Du kannst es nicht befreien. Sie können diese Zeichenfolge auch nicht ändern.

Ihr zweites Stück Code ist korrekt und üblich. Vielleicht möchten Sie auch nachsehen strdup wenn Ihre Implementierung das hat.

  • strncpy ist nicht eine sicherere Version von strcpy. Es kann das Zielarray unterminiert lassen. Es ist sehr selten die richtige Lösung.

    – Keith Thompson

    22. Dezember 2011 um 8:01 Uhr

  • @Keith: richtig, Verweis auf diesen entfernt. strdup ist aber irgendwie nett (vorausgesetzt, Sie wissen, dass Ihre Eingabe 1. eine gültige C-Zeichenfolge und 2. eine akzeptable Größe ist – was auch immer das für Ihre App ist).

    – Matte

    22. Dezember 2011 um 8:31 Uhr

Nun, Sie haben recht. Lassen Sie uns nun den ersten Codeabschnitt untersuchen.

char *test = (char*) malloc(12*sizeof(char));

Der obige Code ist kein Problem.

test = "testingonly";

Hier haben Sie den Zeiger geändert test was zu Speicherlecks führt. Und wenn Sie versuchen, freizugeben, geben Sie nicht den tatsächlich zugewiesenen Zeiger frei, sondern ein “testingonly” -Literal, das auf zeigt. Literal verweist auf einen konstanten Speicher, der in üblichen Szenarien nicht überschrieben werden kann.

Nun zum zweiten Stück Code, das funktioniert gut, da Sie explizit Daten von dem Ort kopiert haben, an dem sich das Literal befindet, um dort zu stapeln, wo Sie sind test zeigt.

Zu deinem zweiten Punkt ja strcpy ist ein üblicher Weg. Andere Möglichkeiten sind ‘memcpy’, wenn Sie Rohbytes kopieren.

HINWEIS: Literale werden nicht auf dem Stack gespeichert. Sie können jedoch den Speicherort, an dem Literale gespeichert werden, nicht ändern.

der Code

#include <stdio.h>
int main(int argc, char **argv)
{
     char *test = (char*) malloc(12*sizeof(char));
     strcpy(test, "testingonly");
     printf("string is: %s\n",test);
     free(test);
     return 0;
}

wird funktionieren

Benutzer-Avatar
ρяσѕρєя K

Dies ist für die Speicherzuweisung:

char *string;
string = (char *) malloc(15);

Dies dient zum Speichern der Daten:

strcpy(str, "kavitajain");
printf("String = %s,  Address = %u\n", str, str);

1362230cookie-checkWeisen Sie Speicher zu und speichern Sie die Zeichenfolge in c

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy