istnieje także strdupa () (w bibliotece GNU C), przyjemna funkcja podobna do strdup (), ale przydziela pamięć na stosie. Twój program nie musi jawnie zwalniać pamięci, tak jak w przypadku strdup (), zostanie ona zwolniona automatycznie po wyjściu z funkcji, w której wywołano strdupa ()
dmityugov 31.10.08
11
strdupajest niebezpieczny i nie należy go używać, chyba że już ustaliłeś, że strlenjest bardzo mały. Ale wtedy możesz po prostu użyć tablicy o stałym rozmiarze na stosie.
R .. GitHub ZATRZYMAJ LÓD
4
@slacker google translate nie jest pomocny ... Co oznacza strdup/ strdupaznaczy po polsku?
Dokładnie tak, jak to brzmi, zakładając, że przyzwyczaiłeś się do skróconego sposobu, w jaki C i UNIX przypisują słowa, powiela ciągi :-)
Pamiętając, że tak naprawdę nie jest częścią samego standardu ISO C (a) (jest to kwestia POSIX), skutecznie robi to samo, co następujący kod:
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}
Innymi słowy:
Próbuje przydzielić wystarczającą ilość pamięci, aby pomieścić stary ciąg (plus znak „\ 0”, aby zaznaczyć koniec łańcucha).
Jeśli przydział nie powiodła się, to ustawia errnosię ENOMEMi powraca NULLnatychmiast. Ustawienie od errnocelu ENOMEMjest coś mallocnie w POSIX, więc nie trzeba jawnie robić w naszym strdup. Jeśli jesteś nie POSIX zgodne, ISO C faktycznie nie wprowadzały istnienie ENOMEMwięc nie obejmowały że tutaj (b) .
W przeciwnym razie przydział zadziałał, więc kopiujemy stary ciąg do nowego ciągu (c) i zwracamy nowy adres (który w pewnym momencie odpowiedzialny jest za zwolnienie).
Pamiętaj, że to jest definicja koncepcyjna. Każdy pisarz biblioteki warty swojej pensji mógł dostarczyć wysoce zoptymalizowany kod skierowany do konkretnego używanego procesora.
(a) Jednak funkcje rozpoczynające się strod małej litery są rezerwowane przez standard dla przyszłych kierunków. Od C11 7.1.3 Reserved identifiers:
Każdy nagłówek deklaruje lub definiuje wszystkie identyfikatory wymienione w powiązanej podpunkcie, a * opcjonalnie deklaruje lub definiuje identyfikatory wymienione w powiązanej przyszłej podpunkcie kierunków bibliotek. **
Przyszłe kierunki dla string.hmożna znaleźć w C11 7.31.13 String handling <string.h>:
Nazwy funkcji rozpoczynające się od str, memlub wcsmałą literą mogą być dodawane do deklaracji w <string.h>nagłówku.
Prawdopodobnie powinieneś to nazwać czymś innym, jeśli chcesz być bezpieczny.
(b) Zmiana polegałaby zasadniczo na if (d == NULL) return NULL;:
if(d == NULL){
errno = ENOMEM;return NULL;}
(c) Zauważ, że używam strcpydo tego, ponieważ wyraźnie pokazuje to zamiar. W niektórych implementacjach użycie może być szybsze (ponieważ znasz już długość) memcpy, ponieważ mogą one umożliwiać przesyłanie danych w większych porcjach lub równolegle. A może nie :-) Mantra optymalizacji nr 1: „mierz, nie zgaduj”.
W każdym razie, jeśli zdecydujesz się wybrać tę trasę, zrobiłbyś coś takiego:
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}
Warto zauważyć, że jak sugeruje przykładowa implementacja Pax, strdup (NULL) jest niezdefiniowany i nie jest czymś, czego można się spodziewać w jakikolwiek przewidywalny sposób.
odpręż się
2
Myślę też, że malloc () ustawiłoby errno, więc nie powinieneś ustawiać go sam. Myślę.
Chris Lutz
5
@Alcot, strdupjest w tych sytuacjach, w których chcesz przydzielić pamięć sterty dla kopii ciągu. W przeciwnym razie musisz to zrobić sam. Jeśli już masz wystarczająco duży bufor (malloc'ed lub w inny sposób), tak, użycie strcpy.
paxdiablo
2
@acgtyrant: jeśli przez standard rozumiesz standard ISO (prawdziwy standard C), nie, nie jest on częścią tego. Jest to część standardu POSIX. Istnieje jednak wiele implementacji języka C, które ją zapewniają, mimo że nie są one oficjalną częścią ISO C. Jednak nawet jeśli nie, pięciowarstwowa odpowiedź w tej odpowiedzi powinna być więcej niż wystarczająca.
paxdiablo
2
Dobra uwaga, @chux, ISO nakazuje tylko { EDOM, EILSEQ, ERANGE }wymagane kody błędów. Zaktualizowałem odpowiedź na to konto.
paxdiablo
86
char* strdup(constchar* s){size_t len =1+strlen(s);char*p = malloc(len);return p ? memcpy(p, s, len): NULL;}
Może kod jest nieco szybszy niż z, strcpy()ponieważ \0znak nie musi być ponownie przeszukiwany (już był z strlen()).
Dzięki. W mojej osobistej realizacji robię to jeszcze „gorszym”. return memcpy(malloc(len), s, len);ponieważ wolę awarię przydziału niż NULLbłąd przydziału.
Patrick Schlüter,
3
Dereferencing @tristopia NULLnie musi się zawieszać; jest niezdefiniowany. Jeśli chcesz mieć pewność, że się zawiesi, napisz, emallocktóry wywołuje abortawarię.
Dave
Wiem o tym, ale moja implementacja gwarantuje, że będzie działała tylko w systemie Solaris lub Linux (z samej natury aplikacji).
Patrick Schlüter,
@tristopia: Dobrze jest mieć nawyk robienia rzeczy w najlepszy sposób. Nabierz nawyku używania, emallocnawet jeśli nie jest to konieczne w systemie Solaris lub Linux, dzięki czemu będziesz go używać w przyszłości, gdy będziesz pisać kod na innych platformach.
ArtOfWarfare
51
Nie ma sensu powtarzać innych odpowiedzi, ale pamiętaj, że strdup()może zrobić wszystko, co chce z perspektywy C, ponieważ nie jest częścią żadnego standardu C. Jest jednak zdefiniowany w POSIX.1-2001.
Jest strdup()przenośny? Nie, niedostępne w środowisku innym niż POSIX (w każdym razie możliwe do wdrożenia). Ale powiedzenie, że funkcja POSIX może zrobić wszystko, jest dość pedantyczne. POSIX to kolejny standard równie dobry jak C i jeszcze bardziej popularny.
PP
2
@BlueMoon Myślę, że chodzi o to, że implementacja języka C, która twierdzi, że nie jest zgodna z POSIX, może nadal zapewniać strdupfunkcję rozszerzenia. W przypadku takiej implementacji nie ma gwarancji, że strdupzachowuje się tak samo jak funkcja POSIX. Nie znam takich implementacji, ale zgodna z prawem nie-złośliwa implementacja może zapewnić char *strdup(char *)z przyczyn historycznych i odrzucić próby przekazania const char *.
Jaka jest różnica między standardem C a POSIX? Przez standard C rozumiesz, że nie istnieje w standardowych bibliotekach C?
Koray Tugay
@KorayTugay Są to różne standardy. Lepiej traktować je jako niepowiązane, chyba że wiesz, że standard dla określonej funkcji C jest zgodny ze standardem POSIX i że twój kompilator / biblioteka jest zgodny ze standardem dla tej funkcji.
strdup()Funkcja zwraca wskaźnik do nowego łańcucha, który stanowi kopię łańcucha wskazywanego przez s1. Zwrócony wskaźnik można przekazać do free(). Wskaźnik zerowy jest zwracany, jeśli nie można utworzyć nowego ciągu.
Tak więc daje nam kolejny ciąg identyczny z ciągiem podanym przez jego argument, bez konieczności przydzielania pamięci. Ale nadal musimy go uwolnić później.
Tworzy zduplikowaną kopię ciągu przekazanego przez uruchomienie malloc i przekazanie ciągu strcpy ciągu. Malloc'ed bufor jest zwracany do wywołującego, stąd potrzeba zwolnienia wartości zwracanej.
Najcenniejszą rzeczą jest to, że daje ci kolejny ciąg identyczny z pierwszym, bez konieczności samodzielnego przydzielania pamięci (lokalizacji i rozmiaru). Ale, jak wspomniano, nadal musisz go zwolnić (ale to również nie wymaga obliczenia ilości).
Jeśli więc chcesz, aby ciąg, który skopiowałeś, był używany w innej funkcji (ponieważ jest tworzony w sekcji sterty), możesz użyć strdup, w przeciwnym razie strcpywystarczy,
Funkcja strdup () jest skrótem dla duplikatu ciągu, przyjmuje parametr jako stałą ciągu lub literał ciągu i przydziela wystarczającą ilość miejsca na ciąg i zapisuje odpowiednie znaki w przydzielonym miejscu, a na koniec zwraca adres przydzielonego miejsca miejsce na rutynę wywoływania.
strdupa
jest niebezpieczny i nie należy go używać, chyba że już ustaliłeś, żestrlen
jest bardzo mały. Ale wtedy możesz po prostu użyć tablicy o stałym rozmiarze na stosie.strdup
/strdupa
znaczy po polsku?Odpowiedzi:
Dokładnie tak, jak to brzmi, zakładając, że przyzwyczaiłeś się do skróconego sposobu, w jaki C i UNIX przypisują słowa, powiela ciągi :-)
Pamiętając, że tak naprawdę nie jest częścią samego standardu ISO C (a) (jest to kwestia POSIX), skutecznie robi to samo, co następujący kod:
Innymi słowy:
Próbuje przydzielić wystarczającą ilość pamięci, aby pomieścić stary ciąg (plus znak „\ 0”, aby zaznaczyć koniec łańcucha).
Jeśli przydział nie powiodła się, to ustawia
errno
sięENOMEM
i powracaNULL
natychmiast. Ustawienie oderrno
celuENOMEM
jest cośmalloc
nie w POSIX, więc nie trzeba jawnie robić w naszymstrdup
. Jeśli jesteś nie POSIX zgodne, ISO C faktycznie nie wprowadzały istnienieENOMEM
więc nie obejmowały że tutaj (b) .W przeciwnym razie przydział zadziałał, więc kopiujemy stary ciąg do nowego ciągu (c) i zwracamy nowy adres (który w pewnym momencie odpowiedzialny jest za zwolnienie).
Pamiętaj, że to jest definicja koncepcyjna. Każdy pisarz biblioteki warty swojej pensji mógł dostarczyć wysoce zoptymalizowany kod skierowany do konkretnego używanego procesora.
(a) Jednak funkcje rozpoczynające się
str
od małej litery są rezerwowane przez standard dla przyszłych kierunków. OdC11 7.1.3 Reserved identifiers
:Przyszłe kierunki dla
string.h
można znaleźć wC11 7.31.13 String handling <string.h>
:Prawdopodobnie powinieneś to nazwać czymś innym, jeśli chcesz być bezpieczny.
(b) Zmiana polegałaby zasadniczo na
if (d == NULL) return NULL;
:(c) Zauważ, że używam
strcpy
do tego, ponieważ wyraźnie pokazuje to zamiar. W niektórych implementacjach użycie może być szybsze (ponieważ znasz już długość)memcpy
, ponieważ mogą one umożliwiać przesyłanie danych w większych porcjach lub równolegle. A może nie :-) Mantra optymalizacji nr 1: „mierz, nie zgaduj”.W każdym razie, jeśli zdecydujesz się wybrać tę trasę, zrobiłbyś coś takiego:
źródło
strdup
jest w tych sytuacjach, w których chcesz przydzielić pamięć sterty dla kopii ciągu. W przeciwnym razie musisz to zrobić sam. Jeśli już masz wystarczająco duży bufor (malloc'ed lub w inny sposób), tak, użyciestrcpy
.{ EDOM, EILSEQ, ERANGE }
wymagane kody błędów. Zaktualizowałem odpowiedź na to konto.Może kod jest nieco szybszy niż z,
strcpy()
ponieważ\0
znak nie musi być ponownie przeszukiwany (już był zstrlen()
).źródło
return memcpy(malloc(len), s, len);
ponieważ wolę awarię przydziału niżNULL
błąd przydziału.NULL
nie musi się zawieszać; jest niezdefiniowany. Jeśli chcesz mieć pewność, że się zawiesi, napisz,emalloc
który wywołujeabort
awarię.emalloc
nawet jeśli nie jest to konieczne w systemie Solaris lub Linux, dzięki czemu będziesz go używać w przyszłości, gdy będziesz pisać kod na innych platformach.Nie ma sensu powtarzać innych odpowiedzi, ale pamiętaj, że
strdup()
może zrobić wszystko, co chce z perspektywy C, ponieważ nie jest częścią żadnego standardu C. Jest jednak zdefiniowany w POSIX.1-2001.źródło
strdup()
przenośny? Nie, niedostępne w środowisku innym niż POSIX (w każdym razie możliwe do wdrożenia). Ale powiedzenie, że funkcja POSIX może zrobić wszystko, jest dość pedantyczne. POSIX to kolejny standard równie dobry jak C i jeszcze bardziej popularny.strdup
funkcję rozszerzenia. W przypadku takiej implementacji nie ma gwarancji, żestrdup
zachowuje się tak samo jak funkcja POSIX. Nie znam takich implementacji, ale zgodna z prawem nie-złośliwa implementacja może zapewnićchar *strdup(char *)
z przyczyn historycznych i odrzucić próby przekazaniaconst char *
.Od strdup man :
strdup()
Funkcja zwraca wskaźnik do nowego łańcucha, który stanowi kopię łańcucha wskazywanego przezs1
. Zwrócony wskaźnik można przekazać dofree()
. Wskaźnik zerowy jest zwracany, jeśli nie można utworzyć nowego ciągu.źródło
Funkcja strdup () wykonuje dynamiczny przydział pamięci dla tablicy znaków, w tym znaku końcowego „\ 0”, i zwraca adres pamięci sterty:
Tak więc daje nam kolejny ciąg identyczny z ciągiem podanym przez jego argument, bez konieczności przydzielania pamięci. Ale nadal musimy go uwolnić później.
źródło
Tworzy zduplikowaną kopię ciągu przekazanego przez uruchomienie malloc i przekazanie ciągu strcpy ciągu. Malloc'ed bufor jest zwracany do wywołującego, stąd potrzeba zwolnienia wartości zwracanej.
źródło
strdup
istrndup
są zdefiniowane w systemach zgodnych z POSIX jako:Funkcja strdup () przydziela wystarczającą ilość pamięci na kopię ciągu
str
, wykonuje kopię i zwraca do niej wskaźnik.Wskaźnik może następnie zostać użyty jako argument funkcji
free
.Jeśli dostępna jest niewystarczająca ilość pamięci,
NULL
jest zwracana ierrno
ustawiana naENOMEM
.Funkcja strndup () kopiuje co najwyżej
len
znaki z ciągu,str
zawsze kończąc kopiowany ciąg.źródło
Najcenniejszą rzeczą jest to, że daje ci kolejny ciąg identyczny z pierwszym, bez konieczności samodzielnego przydzielania pamięci (lokalizacji i rozmiaru). Ale, jak wspomniano, nadal musisz go zwolnić (ale to również nie wymaga obliczenia ilości).
źródło
Twierdzenie:
jest równoważne (poza tym, że zmienia to wskaźniki):
Natomiast:
jest równa:
Jeśli więc chcesz, aby ciąg, który skopiowałeś, był używany w innej funkcji (ponieważ jest tworzony w sekcji sterty), możesz użyć
strdup
, w przeciwnym raziestrcpy
wystarczy,źródło
Funkcja strdup () jest skrótem dla duplikatu ciągu, przyjmuje parametr jako stałą ciągu lub literał ciągu i przydziela wystarczającą ilość miejsca na ciąg i zapisuje odpowiednie znaki w przydzielonym miejscu, a na koniec zwraca adres przydzielonego miejsca miejsce na rutynę wywoływania.
źródło
strdup
nie musi być ciągiem ciągłym, musi być ciągiem C, tzn. Tablicą zakończoną zeremchar
.