strdup () - was macht es in C?


302

Was ist der Zweck der strdup()Funktion in C?


44
Es gibt auch strdupa () (in der GNU C-Bibliothek), eine nette Funktion, die strdup () ähnelt, aber Speicher auf dem Stapel zuweist. Ihr Programm muss den Speicher nicht explizit freigeben, wie im Fall von strdup (). Er wird automatisch freigegeben, wenn Sie die Funktion beenden, in der strdupa () aufgerufen wurde
dmityugov

11
strdupaist gefährlich und sollte nicht verwendet werden, es sei denn, Sie haben bereits festgestellt, dass dies strlensehr klein ist. Aber dann könnten Sie einfach ein Array mit fester Größe auf dem Stapel verwenden.
R .. GitHub STOP HELPING ICE

4
@slacker google translate ist nicht hilfreich ... Was bedeutet strdup/ strdupabedeutet auf Polnisch?
Haneefmubarak

14
@ Haneefmubarak hier
Anatolyg

Hier ist der Unterschied zwischen strdup und strcpy stackoverflow.com/questions/14020380/strcpy-vs-strdup
Siva Prakash

Antworten:


372

Genau wie es sich anhört, vorausgesetzt, Sie sind an die abgekürzte Art und Weise gewöhnt, in der C und UNIX Wörter zuweisen, werden Zeichenfolgen dupliziert :-)

Wenn man bedenkt, dass es eigentlich nicht Teil des ISO C-Standards selbst ist (a) (es ist eine POSIX-Sache), macht es effektiv dasselbe wie der folgende Code:

char *strdup(const char *src) {
    char *dst = malloc(strlen (src) + 1);  // Space for length plus nul
    if (dst == NULL) return NULL;          // No memory
    strcpy(dst, src);                      // Copy the characters
    return dst;                            // Return the new string
}

Mit anderen Worten:

  1. Es wird versucht, genügend Speicher für die alte Zeichenfolge zuzuweisen (plus ein '\ 0'-Zeichen, um das Ende der Zeichenfolge zu markieren).

  2. Wenn die Zuordnung fehlgeschlagen ist, wird sie errnoauf gesetzt ENOMEMund kehrt NULLsofort zurück. Einstellen von errnozu ENOMEMetwas mallocin POSIX tut so brauchen wir nicht explizit , es zu tun in unserem strdup. Wenn Sie nicht POSIX-konform sind, schreibt ISO C die Existenz von nicht vor, ENOMEMdaher habe ich dies hier nicht aufgenommen (b) .

  3. Andernfalls hat die Zuordnung funktioniert, sodass wir die alte Zeichenfolge in die neue Zeichenfolge (c) kopieren und die neue Adresse zurückgeben (für deren Freigabe der Anrufer irgendwann verantwortlich ist).

Denken Sie daran, dass dies die konzeptionelle Definition ist. Jeder Bibliotheksschreiber, der sein Gehalt wert ist, hat möglicherweise stark optimierten Code für den jeweiligen verwendeten Prozessor bereitgestellt.


(a) Funktionen, die mit strund einem Kleinbuchstaben beginnen, sind jedoch durch den Standard für zukünftige Anweisungen reserviert. Von C11 7.1.3 Reserved identifiers:

Jeder Header deklariert oder definiert alle in der zugehörigen Unterklausel aufgeführten Bezeichner und * deklariert oder definiert optional die in der zugehörigen Unterklausel für zukünftige Bibliotheksrichtungen aufgeführten Bezeichner. **

Die zukünftigen Richtungen für string.hfinden Sie in C11 7.31.13 String handling <string.h>:

Funktionsnamen, die mit str, memoder wcsund einem Kleinbuchstaben beginnen , können zu den Deklarationen in der <string.h>Kopfzeile hinzugefügt werden .

Sie sollten es also wahrscheinlich etwas anderes nennen, wenn Sie sicher sein möchten.


(b) Die Änderung würde im Wesentlichen ersetzt if (d == NULL) return NULL;durch:

if (d == NULL) {
    errno = ENOMEM;
    return NULL;
}

(c) Beachten Sie, dass ich dafür verwende strcpy, da dies die Absicht klar zeigt. In einigen Implementierungen ist die Verwendung möglicherweise schneller (da Sie die Länge bereits kennen) memcpy, da sie möglicherweise die Übertragung der Daten in größeren Blöcken oder parallel ermöglicht. Oder vielleicht auch nicht :-) Optimierungsmantra # 1: "messen, nicht raten".

Sollten Sie sich auf jeden Fall für diesen Weg entscheiden, würden Sie Folgendes tun:

char *strdup(const char *src) {
    size_t len = strlen(src) + 1;       // String plus '\0'
    char *dst = malloc(len);            // Allocate space
    if (dst == NULL) return NULL;       // No memory
    memcpy (dst, src, len);             // Copy the block
    return dst;                         // Return the new string
}

8
Es ist erwähnenswert, dass strdup (NULL), wie die Beispielimplementierung von Pax impliziert, undefiniert ist und nicht etwas ist, von dem Sie erwarten können, dass es sich auf vorhersehbare Weise verhält.
Entspannen Sie sich

2
Ich denke auch, dass malloc () errno setzen würde, also sollten Sie es nicht selbst setzen müssen. Meiner Ansicht nach.
Chris Lutz

5
@Alcot strdupist für Situationen gedacht, in denen Heapspeicher für die Zeichenfolgenkopie zugewiesen werden soll. Sonst musst du es selbst machen. Wenn Sie bereits haben einen großen genug Puffer (malloc'ed oder auf andere Weise), ja, Verwendung strcpy.
Paxdiablo

2
@acgtyrant: Wenn Sie standardmäßig den ISO-Standard (den echten C-Standard) meinen, nein, ist er nicht Teil davon. Es ist Teil des POSIX-Standards. Es gibt jedoch viele C- Implementierungen , die dies ermöglichen, obwohl sie kein offizieller Bestandteil von ISO C sind. Selbst wenn dies nicht der Fall wäre, sollte der Fünfzeiler in dieser Antwort mehr als ausreichend sein.
Paxdiablo

2
Guter Punkt, @chux, ISO-Mandate nur { EDOM, EILSEQ, ERANGE }als erforderliche Fehlercodes. Habe die Antwort aktualisiert, um dies zu berücksichtigen.
Paxdiablo

86
char * strdup(const char * s)
{
  size_t len = 1+strlen(s);
  char *p = malloc(len);

  return p ? memcpy(p, s, len) : NULL;
}

Vielleicht ist der Code etwas schneller als mit, strcpy()da das \0Zeichen nicht erneut gesucht werden muss (es war bereits mit strlen()).


Vielen Dank. In meiner persönlichen Umsetzung mache ich es noch "schlimmer". return memcpy(malloc(len), s, len);da ich lieber den Absturz bei der Zuweisung als den NULLFehler bei der Zuweisung bevorzuge .
Patrick Schlüter

3
@tristopia Dereferenzierung NULLmuss nicht abstürzen; es ist undefiniert. Wenn Sie sicher sein möchten, dass es abstürzt, schreiben Sie eine, emallocdie abortbei einem Fehler fehlschlägt.
Dave

Ich weiß das, aber meine Implementierung läuft garantiert nur unter Solaris oder Linux (aufgrund der Natur der App).
Patrick Schlüter

@tristopia: Es ist gut, die Gewohnheit zu haben, Dinge am besten zu machen. Gewöhnen Sie sich an, es emallocauch dann zu verwenden , wenn es unter Solaris oder Linux nicht erforderlich ist, damit Sie es in Zukunft verwenden können, wenn Sie Code auf anderen Plattformen schreiben.
ArtOfWarfare

51

Es macht keinen Sinn, die anderen Antworten zu wiederholen, aber bitte beachten Sie, dass strdup()dies aus C-Sicht alles tun kann, was es will, da es nicht Teil eines C-Standards ist. Es ist jedoch durch POSIX.1-2001 definiert.


4
Ist strdup()tragbar? Nein, in einer Nicht-POSIX-Umgebung nicht verfügbar (ohnehin trivial implementierbar). Zu sagen, dass eine POSIX-Funktion alles kann, ist ziemlich umständlich. POSIX ist ein weiterer Standard , der so gut wie C und noch beliebter ist.
PP

2
@BlueMoon Ich denke, der Punkt ist, dass eine C-Implementierung, die keine Konformität mit POSIX beansprucht, möglicherweise noch eine strdupFunktion als Erweiterung bietet . Bei einer solchen Implementierung gibt es keine Garantie dafür, dass strdupsich dies genauso verhält wie die POSIX-Funktion. Ich kenne keine solchen Implementierungen, aber eine legitime, nicht böswillige Implementierung kann char *strdup(char *)aus historischen Gründen vorsehen und Versuche ablehnen, eine zu übergeben const char *.

Was ist der Unterschied zwischen C-Standard und POSIX? Mit C-Standard meinen Sie, dass es in C-Standardbibliotheken nicht existiert?
Koray Tugay

@KorayTugay Sie sind verschiedene Standards. Behandeln Sie sie besser als nicht verwandt, es sei denn, Sie wissen, dass der Standard für eine bestimmte C-Funktion dem POSIX-Standard entspricht und dass Ihr Compiler / Ihre Bibliothek dem Standard für diese Funktion entspricht.
Matthew Read

17

Von strdup man :

Die strdup()Funktion gibt einen Zeiger auf eine neue Zeichenfolge zurück, die ein Duplikat der Zeichenfolge ist, auf die von zeigt s1. Der zurückgegebene Zeiger kann an übergeben werden free(). Ein Nullzeiger wird zurückgegeben, wenn die neue Zeichenfolge nicht erstellt werden kann.


4

strdup () führt eine dynamische Speicherzuweisung für das Zeichenarray einschließlich des Endzeichens '\ 0' durch und gibt die Adresse des Heapspeichers zurück:

char *strdup (const char *s)
{
    char *p = malloc (strlen (s) + 1);   // allocate memory
    if (p != NULL)
        strcpy (p,s);                    // copy string
    return p;                            // return the memory
}

Sie geben uns also eine weitere Zeichenfolge, die mit der durch das Argument angegebenen Zeichenfolge identisch ist, ohne dass wir Speicher zuweisen müssen. Aber wir müssen es später noch befreien.


3

Es macht eine Kopie des Strings übergeben durch einen laufenden malloc und strcpy der Zeichenfolge übergeben. Der malloc'ed Puffer an den Aufrufer zurückgegeben wird, daher die Notwendigkeit zu laufen frei auf dem Rückgabewert.


3

strdupund strndupsind in POSIX-kompatiblen Systemen wie folgt definiert:

char *strdup(const char *str);
char *strndup(const char *str, size_t len);

Die Funktion strdup () reserviert ausreichend Speicher für eine Kopie der Zeichenfolge str, führt die Kopie durch und gibt einen Zeiger darauf zurück.

Der Zeiger kann anschließend als Argument für die Funktion verwendet werden free.

Wenn nicht genügend Speicher verfügbar ist, NULLwird zurückgegeben und auf errnogesetzt ENOMEM.

Die Funktion strndup () kopiert höchstens lenZeichen aus der Zeichenfolge str, wobei die kopierte Zeichenfolge immer null ist.


1

Das Wertvollste ist, dass Sie eine andere Zeichenfolge erhalten, die mit der ersten identisch ist, ohne dass Sie selbst Speicher (Speicherort und Größe) zuweisen müssen. Wie bereits erwähnt, müssen Sie es dennoch freigeben (dies erfordert jedoch auch keine Mengenberechnung.)


1

Die Aussage:

strcpy(ptr2, ptr1);

ist äquivalent zu (abgesehen von der Tatsache, dass dies die Zeiger ändert):

while(*ptr2++ = *ptr1++);

Wohingegen:

ptr2 = strdup(ptr1);

ist äquivalent zu:

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

Also, wenn Sie die Zeichenfolge wollen , die Sie kopiert haben , in einer anderen Funktion verwendet werden (wie es in Haufen Abschnitt erstellt wird), können Sie verwenden strdup, sonst strcpyist genug,


0

Die Funktion strdup () ist eine Abkürzung für String-Duplikat. Sie nimmt einen Parameter als String-Konstante oder als String-Literal auf, weist gerade genug Platz für den String zu und schreibt die entsprechenden Zeichen in den zugewiesenen Platz und gibt schließlich die Adresse des zugewiesenen Strings zurück Platz für die aufrufende Routine.


1
Das Argument to strdupmuss keine Zeichenfolgenkonstante sein, sondern eine C-Zeichenfolge, dh ein nullterminiertes Array von char.
Chqrlie
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.