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?
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(constchar*src){char*dst = malloc(strlen (src)+1);// Space for length plus nulif(dst == NULL)return NULL;// No memory
strcpy(dst, src);// Copy the charactersreturn dst;// Return the new string}
Mit anderen Worten:
Es wird versucht, genügend Speicher für die alte Zeichenfolge zuzuweisen (plus ein '\ 0'-Zeichen, um das Ende der Zeichenfolge zu markieren).
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) .
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(constchar*src){size_t len = strlen(src)+1;// String plus '\0'char*dst = malloc(len);// Allocate spaceif(dst == NULL)return NULL;// No memory
memcpy (dst, src, len);// Copy the blockreturn dst;// Return the new string}
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(constchar* 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.
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.
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.
strdup () führt eine dynamische Speicherzuweisung für das Zeichenarray einschließlich des Endzeichens '\ 0' durch und gibt die Adresse des Heapspeichers zurück:
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.
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.
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.)
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,
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.
strdupa
ist gefährlich und sollte nicht verwendet werden, es sei denn, Sie haben bereits festgestellt, dass diesstrlen
sehr klein ist. Aber dann könnten Sie einfach ein Array mit fester Größe auf dem Stapel verwenden.strdup
/strdupa
bedeutet auf Polnisch?Antworten:
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:
Mit anderen Worten:
Es wird versucht, genügend Speicher für die alte Zeichenfolge zuzuweisen (plus ein '\ 0'-Zeichen, um das Ende der Zeichenfolge zu markieren).
Wenn die Zuordnung fehlgeschlagen ist, wird sie
errno
auf gesetztENOMEM
und kehrtNULL
sofort zurück. Einstellen vonerrno
zuENOMEM
etwasmalloc
in POSIX tut so brauchen wir nicht explizit , es zu tun in unseremstrdup
. Wenn Sie nicht POSIX-konform sind, schreibt ISO C die Existenz von nicht vor,ENOMEM
daher habe ich dies hier nicht aufgenommen (b) .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
str
und einem Kleinbuchstaben beginnen, sind jedoch durch den Standard für zukünftige Anweisungen reserviert. VonC11 7.1.3 Reserved identifiers
:Die zukünftigen Richtungen für
string.h
finden Sie inC11 7.31.13 String handling <string.h>
: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:(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:
quelle
strdup
ist 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, Verwendungstrcpy
.{ EDOM, EILSEQ, ERANGE }
als erforderliche Fehlercodes. Habe die Antwort aktualisiert, um dies zu berücksichtigen.Vielleicht ist der Code etwas schneller als mit,
strcpy()
da das\0
Zeichen nicht erneut gesucht werden muss (es war bereits mitstrlen()
).quelle
return memcpy(malloc(len), s, len);
da ich lieber den Absturz bei der Zuweisung als denNULL
Fehler bei der Zuweisung bevorzuge .NULL
muss nicht abstürzen; es ist undefiniert. Wenn Sie sicher sein möchten, dass es abstürzt, schreiben Sie eine,emalloc
dieabort
bei einem Fehler fehlschlägt.emalloc
auch 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.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.quelle
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.strdup
Funktion als Erweiterung bietet . Bei einer solchen Implementierung gibt es keine Garantie dafür, dassstrdup
sich dies genauso verhält wie die POSIX-Funktion. Ich kenne keine solchen Implementierungen, aber eine legitime, nicht böswillige Implementierung kannchar *strdup(char *)
aus historischen Gründen vorsehen und Versuche ablehnen, eine zu übergebenconst char *
.Von strdup man :
Die
strdup()
Funktion gibt einen Zeiger auf eine neue Zeichenfolge zurück, die ein Duplikat der Zeichenfolge ist, auf die von zeigts1
. Der zurückgegebene Zeiger kann an übergeben werdenfree()
. Ein Nullzeiger wird zurückgegeben, wenn die neue Zeichenfolge nicht erstellt werden kann.quelle
strdup () führt eine dynamische Speicherzuweisung für das Zeichenarray einschließlich des Endzeichens '\ 0' durch und gibt die Adresse des Heapspeichers zurück:
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.
quelle
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.
quelle
strdup
undstrndup
sind in POSIX-kompatiblen Systemen wie folgt definiert: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,
NULL
wird zurückgegeben und auferrno
gesetztENOMEM
.Die Funktion strndup () kopiert höchstens
len
Zeichen aus der Zeichenfolgestr
, wobei die kopierte Zeichenfolge immer null ist.quelle
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.)
quelle
Die Aussage:
ist äquivalent zu (abgesehen von der Tatsache, dass dies die Zeiger ändert):
Wohingegen:
ist äquivalent zu:
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
, sonststrcpy
ist genug,quelle
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.
quelle
strdup
muss keine Zeichenfolgenkonstante sein, sondern eine C-Zeichenfolge, dh ein nullterminiertes Array vonchar
.