strcpy vs strdup

74

Ich habe gelesen, dass dies strcpyzum Kopieren einer Zeichenfolge dient, und strdupgebe einen Zeiger auf eine neue Zeichenfolge zurück, um die Zeichenfolge zu duplizieren.

Könnten Sie bitte erklären, welche Fälle Sie bevorzugen strcpyund welche Fälle Sie bevorzugen strdup?

Johan
quelle

Antworten:

106

strcpy(ptr2, ptr1) ist äquivalent zu while(*ptr2++ = *ptr1++)

wo als strdup gleichbedeutend ist mit

ptr2 = malloc(strlen(ptr1)+1);
strcpy(ptr2,ptr1);

( memcpy-Version könnte effizienter sein)

Wenn Sie also möchten, dass die von Ihnen kopierte Zeichenfolge in einer anderen Funktion verwendet wird (wie sie im Heap-Abschnitt erstellt wird), können Sie strdup verwenden, andernfalls reicht strcpy aus.

Abdul Muheedh
quelle
6
Gute Antwort, abgesehen vom letzten Satz, der verwirrend ist. Ich denke, Sie meinen, die Lebensdauer der strdup()ed-Zeichenfolge kann über das Ende der aktuellen Funktion hinausgehen, aber das könnte trotzdem der Fall sein (wenn das Ziel strcpy()ein vom Aufrufer bereitgestellter Puffer, eine globale Variable oder selbst manuell mit malloc()oder zugewiesen ist new). .
j_random_hacker
1
Ja, es stimmt, wenn der vom Aufrufer bereitgestellte Puffer eine globale Variable oder ein dynamischer Zeiger für sich ist, muss strdup nicht verwendet werden. Ich habe gerade auf eines der Anwendungsfallszenarien hingewiesen und danke, dass Sie es abgeschlossen haben.
Abdul Muheedh
9
Ich liebe das wirklich while(*ptr2++ = *ptr1++)! :)
Aloys
1
Wie funktioniert die Exit-Bedingung in der while-Schleife?
sbhatla
3
@sbhatla In C werden Zeichenfolgen durch ein Nullbyte beendet, das als falsch ausgewertet wird, und ein Zuweisungsausdruck wird als zugewiesener Wert ausgewertet.
56

Die Funktionen strcpyund strncpysind Teil der C-Standardbibliothek und arbeiten mit vorhandenem Speicher. Das heißt, Sie müssen den Speicher bereitstellen, in den die Funktionen die Zeichenfolgendaten kopieren, und als Konsequenz müssen Sie über Ihre eigenen Mittel verfügen, um herauszufinden, wie viel Speicher Sie benötigen.

Dies strdupist eine Posix-Funktion, die eine dynamische Speicherzuweisung für Sie durchführt. Es gibt einen Zeiger auf den neu zugewiesenen Speicher zurück, in den die Zeichenfolge kopiert wurde. Aber Sie sind jetzt für diese Erinnerung verantwortlich und müssen sie schließlich free.

Das macht strdupeine der "versteckten malloc" Komfortfunktionen aus, und das ist vermutlich auch der Grund, warum sie nicht Teil der Standardbibliothek ist. Solange Sie die Standardbibliothek verwenden, wissen Sie, dass Sie freefür jedes malloc/ eine aufrufen müssen calloc. Aber Funktionen wie das strdupEinführen eines versteckten malloc, und Sie müssen es genauso behandeln wie ein malloczum Zweck der Speicherverwaltung. (Eine weitere solche versteckten Zuordnungsfunktionen sind GCCs abi::__cxa_demangle().) Vorsicht!

Kerrek SB
quelle
1
Ahh, ich habe mich immer gefragt, warum das nicht in stdlib ist, und jetzt weiß ich es.
Maury Markowitz
14

strdupSpeicher reserviert für den neuen String auf dem Heap, während der Verwendung strcpy(oder dessen sicherer strncpyvarient) ich auf einen String in einen vorher zugewiesenen Speicher kopieren kann entweder den Heap oder den Stapel.

Oren
quelle
1
Warum das nachdrückliche "entweder"? Ist es nicht möglich, strcpyin einen statischen Puffer zu kopieren?
Kerrek SB
Ich habe versucht, den Unterschied in der Verwendung zwischen den beiden Funktionen hervorzuheben, ohne die Antwort mit zu vielen Problemen bei der Speicherverwaltung zu überladen. Aber ja, Sie haben Recht mit statischen Puffern.
Oren
Wenn Sie keine Unordnung wollen, können Sie die Antwort einfach nach "vorab zugewiesenem Speicher"
beenden
kleiner nitpick: strncpy ist nicht sicherer als strcpy, da es nicht garantiert, dass dest null beendet wird. Schlimmer noch, jeder nicht verwendete Speicherplatz im Zielpuffer wird mit Nullterminatoren gefüllt. Diese Funktion war nie für den allgemeinen Gebrauch gedacht. Wenn Sie eine dieser Funktionen verwenden müssen, verwenden Sie am besten strcpy und beenden Sie dest manuell.
JohnF
11

In der akzeptierten Antwort wird die Implementierung von wie strdupfolgt dargestellt:

ptr2 = malloc(strlen(ptr1)+1);
strcpy(ptr2,ptr1);

Dies ist jedoch etwas suboptimal, da beide strlenund strcpydie Länge der Zeichenfolge ermitteln müssen, indem geprüft wird, ob jedes Zeichen a ist \0.

Die Verwendung memcpysollte effizienter sein:

char *strdup(const char *src) {
    size_t len = strlen(src) + 1;
    char *s = malloc(len);
    if (s == NULL)
        return NULL;
    return (char *)memcpy(s, src, len);
}
Heikki Salokanto
quelle
1
Gute Antwort, die die konzeptionelle Verwendung von strcpyImplementierung strdupvon der praktischen Anwendbarkeit auf effiziente Weise trennt .
Michael Gaskill
Da memcpy von der Kenntnis der Stringlänge abhängt, wird strlen in beiden Fällen aufgerufen. memcpy selbst ist äquivalent zu while ( len-- ) { *ptr2++ = *ptr1++ }, das jedes Mal eine Subtraktion, Zuweisung und einen Test für Null durchführt und dann immer noch eine Zuweisung ausführen muss und dann trotzdem zwei Post-Inkremente und deren Zuweisungen. Diese Memcpy-Technik scheint also weniger effizient zu sein. Dies scheinen eher triviale Unterscheidungen und imaginäre Optimierungen zu sein.
0

char *strdup(char *pszSrch);;

strdupweist dem Speicher die Größe der ursprünglichen Zeichenfolge zu. Wenn die Speicherzuordnung erfolgreich ist, wird die ursprüngliche Zeichenfolge in die doppelte Zeichenfolge kopiert.

strdupd Rückkehr NULLbei Ausfall. Wenn der Speicher nicht zugeordnet ist, schlägt fehl Kopie strdupRückkehr NULL.

Bharath Ravindra
quelle