Wie verkette ich Const/Literal-Strings in C?

Lesezeit: 6 Minuten

Benutzeravatar von The.Anti.9
Der.Anti.9

Ich arbeite in C und muss ein paar Dinge verketten.

Momentan habe ich das:

message = strcat("TEXT ", var);

message2 = strcat(strcat("TEXT ", foo), strcat(" TEXT ", bar));

Wenn Sie Erfahrung in C haben, bin ich mir sicher, dass Sie erkennen, dass dies zu einem Segmentierungsfehler führt, wenn Sie versuchen, es auszuführen. Wie kann ich das umgehen?

  • Ich möchte vorschlagen, dass Sie strlcat anstelle von strcat verwenden! gratisoft.us/todd/papers/strlcpy.html

    – activout.se

    21. November 2008 um 13:37 Uhr

  • Ich möchte diesen Vorschlag wiederholen. Strcat verursacht eine Schwachstelle für Pufferüberlauf-Exploits. Jemand kann Ihrem Programm Daten geben, die dazu führen, dass es willkürlichen Code ausführt.

    – Brian

    21. November 2008 um 14:10 Uhr

Benutzeravatar von Brian R. Bondy
Brian R. Bondy

In C sind “Strings” einfach nur einfach char Arrays. Daher können Sie sie nicht direkt mit anderen “Strings” verketten.

Du kannst den … benutzen strcat Funktion, die die Zeichenfolge anhängt, auf die gezeigt wird src bis zum Ende der Zeichenfolge, auf die gezeigt wird dest:

char *strcat(char *dest, const char *src);

Hier ist ein Beispiel von cplusplus.com:

char str[80];
strcpy(str, "these ");
strcat(str, "strings ");
strcat(str, "are ");
strcat(str, "concatenated.");

Für den ersten Parameter müssen Sie den Zielpuffer selbst bereitstellen. Der Zielpuffer muss ein Char-Array-Puffer sein. Z.B: char buffer[1024];

Vergewissere dich dass der erste Parameter genügend Platz hat, um das zu speichern, was Sie hineinkopieren möchten. Falls für Sie verfügbar, ist es sicherer, Funktionen zu verwenden wie: strcpy_s und strcat_s wobei Sie die Größe des Zielpuffers explizit angeben müssen.

Notiz: Ein String-Literal kann nicht als Puffer verwendet werden, da es eine Konstante ist. Daher müssen Sie dem Puffer immer ein Char-Array zuweisen.

Der Rückgabewert von strcat kann einfach ignoriert werden, es gibt lediglich denselben Zeiger zurück, der als erstes Argument übergeben wurde. Es dient der Bequemlichkeit und ermöglicht es Ihnen, die Aufrufe in einer Codezeile zu verketten:

strcat(strcat(str, foo), bar);

Dein Problem könnte also wie folgt gelöst werden:

char *foo = "foo";
char *bar = "bar";
char str[80];
strcpy(str, "TEXT ");
strcat(str, foo);
strcat(str, bar);

  • Würden Sie bitte “Seien Sie sehr vorsichtig, dass …” fett gedruckt? Das kann nicht genug betont werden. Der Missbrauch von strcat, strcpy und sprintf ist das Herzstück instabiler/unsicherer Software.

    – Sockel

    21. November 2008 um 13:33 Uhr

  • Warnung: Wie geschrieben hinterlässt dieser Code ein riesiges, klaffendes Loch in Ihrem Code für Pufferüberlauf-Exploits.

    – Brian

    21. November 2008 um 14:09 Uhr

  • Im obigen Beispiel ist kein Pufferüberlauf-Exploit möglich. Und ja, ich stimme im Allgemeinen zu, dass ich das obige Beispiel nicht für unbestimmte Zeichenfolgenlängen von foo und bar verwenden würde.

    – Brian R. Bondy

    21. November 2008 um 14:14 Uhr

  • Nicht verwenden strcat mehrmals! strcat muss alle vorherigen Bytes überprüfen (Suche nach '\0') Sie haben bereits verkettet. Dies ist eine nutzlose Verarbeitung.

    – Dolmen

    7. September 2010 um 16:13 Uhr

  • An den zweiten @dolmen hat Joel Spolsky geschrieben recht ausführlicher Artikel zum Thema. Sollte Pflichtlektüre sein. 😉

    – peter.slizik

    14. August 2012 um 14:53 Uhr

Benutzeravatar von Alex B
Alex B

Vermeide das Benutzen strcat im C-Code. Der sauberste und vor allem sicherste Weg ist die Anwendung snprintf:

char buf[256];
snprintf(buf, sizeof(buf), "%s%s%s%s", str1, str2, str3, str4);

Einige Kommentatoren haben ein Problem angesprochen, dass die Anzahl der Argumente möglicherweise nicht mit der Formatzeichenfolge übereinstimmt und der Code trotzdem kompiliert wird, aber die meisten Compiler geben bereits eine Warnung aus, wenn dies der Fall ist.

  • Checkers, er sprach über die Klammern um “buf” des Arguments sizeof. Sie sind nicht erforderlich, wenn das Argument ein Ausdruck ist. Aber ich verstehe nicht, warum du downvoted wirst. Ich denke, Ihre Antwort ist die beste von allen, obwohl es c99 ist. (vielleicht sind sie sich deswegen nicht einig! lamers!) +1

    – Johannes Schaub – litb

    21. November 2008 um 13:27 Uhr

  • sizeof() funktioniert hier nur für char buf[…]. NICHT für char * buf = malloc(…). Es gibt nicht viele Unterschiede zwischen Arrays und Zeigern, aber dies ist einer davon!

    – Herr Ree

    21. November 2008 um 13:28 Uhr

  • Außerdem versucht er, eine Verkettung durchzuführen. Verketten mit snprintf() ist ein GROSSES nein nein.

    – Leonardo Herrera

    21. November 2008 um 15:05 Uhr

  • @MrRee: Die Unterschiede zwischen Zeigern und Arrays sind enorm und vollständig! Es liegt an dir verwenden sie, die sich nicht immer unterscheiden. Außerdem sind Zeiger und dynamische Zuordnung wirklich orthogonale Konzepte.

    – Leichtigkeitsrennen im Orbit

    7. Dezember 2011 um 20:11 Uhr


  • Eines meiner Lieblingsprobleme sind Leute wie @unwind, die auf der sinnlosen Unterscheidung zwischen bestehen sizeof(x) und sizeof x. Die Notation in Klammern funktioniert immer und die Notation ohne Klammern funktioniert nur manchmal, verwenden Sie also immer die Notation in Klammern; Es ist eine einfache Regel, die Sie sich merken sollten, und sie ist sicher. Dies führt zu einem religiösen Streit – ich war schon früher an Diskussionen mit denen beteiligt, die Einwände erheben –, aber die Einfachheit von „immer Klammern verwenden“ überwiegt jeden Wert, sie nicht zu verwenden (IMNSHO natürlich). Dies wird zum Ausgleich präsentiert.

    – Jonathan Leffler

    31. März 2014 um 0:22 Uhr

Strings können auch zur Kompilierzeit verkettet werden.

#define SCHEMA "test"
#define TABLE  "data"

const char *table = SCHEMA "." TABLE ; // note no + or . or anything
const char *qry =               // include comments in a string
    " SELECT * "                // get all fields
    " FROM " SCHEMA "." TABLE   /* the table */
    " WHERE x = 1 "             /* the filter */ 
                ;

Benutzeravatar von Mr.Ree
Herr Ree

Leute, benutzt strncpy(), strncat() oder snprintf().

Wenn Sie Ihren Pufferspeicher überschreiten, wird alles andere im Speicher zerstört!

(Und denken Sie daran, Platz für das abschließende Nullzeichen ‘\0’ zu lassen!)

Auch malloc und realloc sind nützlich, wenn Sie nicht im Voraus wissen, wie viele Zeichenfolgen verkettet werden.

#include <stdio.h>
#include <string.h>

void example(const char *header, const char **words, size_t num_words)
{
    size_t message_len = strlen(header) + 1; /* + 1 for terminating NULL */
    char *message = (char*) malloc(message_len);
    strncat(message, header, message_len);

    for(int i = 0; i < num_words; ++i)
    {
       message_len += 1 + strlen(words[i]); /* 1 + for separator ';' */
       message = (char*) realloc(message, message_len);
       strncat(strncat(message, ";", message_len), words[i], message_len);
    }

    puts(message);

    free(message);
}

  • Dies endet in einer Endlosschleife, wenn num_words>INT_MAXvielleicht sollten Sie verwenden size_t zum i

    – 12431234123412341234123

    25. März 2017 um 12:48 Uhr


Der beste Weg, dies ohne eine begrenzte Puffergröße zu tun, ist die Verwendung von asprintf()

char* concat(const char* str1, const char* str2)
{
    char* result;
    asprintf(&result, "%s%s", str1, str2);
    return result;
}

  • Dies endet in einer Endlosschleife, wenn num_words>INT_MAXvielleicht sollten Sie verwenden size_t zum i

    – 12431234123412341234123

    25. März 2017 um 12:48 Uhr


David Rodríguez - Benutzeravatar von dribeas
David Rodríguez – Dribeas

Vergessen Sie nicht, den Ausgabepuffer zu initialisieren. Das erste Argument für strcat muss eine nullterminierte Zeichenfolge mit genügend zusätzlichem Platz für die resultierende Zeichenfolge sein:

char out[1024] = ""; // must be initialized
strcat( out, null_terminated_string ); 
// null_terminated_string has less than 1023 chars

1427700cookie-checkWie verkette ich Const/Literal-Strings in C?

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

Privacy policy