strdup () - C'de ne yapar?


302

strdup()C'deki fonksiyonun amacı nedir ?


44
strdupa () (GNU C kütüphanesinde) de vardır, strdup () işlevine benzer ancak yığına bellek ayırır. Programınızın strdup () durumunda olduğu gibi hafızayı açıkça boşaltmasına gerek yoktur,
strdupa

11
strdupatehlikelidir ve strlençok küçük olduğunu belirlemediğiniz sürece kullanılmamalıdır . Ancak daha sonra yığın üzerinde sabit boyutlu bir dizi kullanabilirsiniz.
R .. GitHub DURDURMA BUZA YARDIMCI OLDU

4
@slacker google translate yardımcı olmuyor ... Lehçe ne demek strdup/ ne strdupademek?
haneefmubarak

14
@haneefmubarak burada
anatolyg

Yanıtlar:


372

Tam olarak nasıl göründüğünü, C ve UNIX'in sözcük atadığı kısaltılmış şekilde kullandığınızı varsayarsak, dizeleri çoğaltır :-)

Aslında ISO C standardının kendisinin bir parçası olmadığını (a) (bir POSIX olayı) unutmayın, etkili bir şekilde aşağıdaki kodla aynı şeyi yapar:

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
}

Diğer bir deyişle:

  1. Eski dizeyi tutacak kadar bellek ayırmaya çalışır (artı dizenin sonunu işaretlemek için '\ 0' karakteri).

  2. Tahsisi başarısız olursa, o setleri errnoiçin ENOMEMve iadeler NULLhemen. Arasında ayarlanması errnoiçin ENOMEMbir şeydir mallocbiz açıkça Biz bir aile odada yapmak gerek kalmaz POSIX'deki yapar strdup. Eğer konum değil POSIX uyumlu, ISO C aslında varlığını zorunlu kılmaz ENOMEMBen buraya dahil değil bu yüzden (b) .

  3. Aksi takdirde, ayırma işe yaradı, böylece eski dizeyi yeni dizgiye (c) kopyalayıp yeni adresi (arayanın bir noktada serbest bırakmaktan sorumlu olduğu) döndürüyoruz.

Bunun kavramsal tanım olduğunu unutmayın. Maaşlarına değer herhangi bir kütüphane yazarı, kullanılan belirli işlemciyi hedefleyen yoğun şekilde optimize edilmiş kod sağlamış olabilir.


(a) Bununla birlikte, strküçük harflerle başlayan işlevler ve küçük harfler gelecekteki talimatlar için standart tarafından ayrılmıştır. Gönderen C11 7.1.3 Reserved identifiers:

Her başlık, ilişkili alt maddesinde listelenen tüm tanımlayıcıları bildirir veya tanımlar ve * isteğe bağlı olarak ilişkili gelecekteki kitaplık yönergeleri alt maddesinde listelenen tanımlayıcıları bildirir veya tanımlar. **

İçin gelecekteki talimatlar string.hşurada bulunabilir C11 7.31.13 String handling <string.h>:

İle başlayan Fonksiyon isimleri str, memveya wcsbir küçük harf içinde bildirimleri eklenebilir <string.h>başlığında.

Bu yüzden, güvende olmak istiyorsanız, muhtemelen başka bir şey demelisiniz.


(b) Değişiklik temel olarak aşağıdakilerle değiştirilecektir if (d == NULL) return NULL;:

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

(c) Bunun strcpyamacını açıkça gösterdiğinden, bunun için kullandığımı unutmayın . Bazı uygulamalarda, memcpyverilerin daha büyük parçalar halinde veya paralel olarak aktarılmasına izin verebileceğinden (zaten uzunluğunu zaten bildiğinizden) kullanmak daha hızlı olabilir. Ya da olmayabilir :-) Optimizasyon mantra # 1: "ölç, tahmin etme".

Her durumda, bu rotaya gitmeye karar verirseniz, şöyle bir şey yaparsınız:

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
Pax'ın örnek uygulamasının ima ettiği gibi, strdup'un (NULL) tanımsız olduğunu ve tahmin edilebilir herhangi bir şekilde davranmayı bekleyebileceğiniz bir şey olmadığını belirtmek gerekir.
açma

2
Ayrıca, malloc () errno ayarlayacağını düşünüyorum, bu yüzden kendiniz ayarlamanız gerekmez. Bence.
Chris Lutz

5
@Alcot, strdupdize kopyası için yığın belleğin ayrılmasını istediğiniz durumlar içindir. Aksi takdirde bunu kendiniz yapmanız gerekir. Zaten varsa sahip yeterince büyük bir tampon (Aksi malloc'ed ya), evet, kullanım strcpy.
paxdiablo

2
@ acgtyrant: standart olarak ISO standardını (gerçek C standardı) kastediyorsanız, hayır, bunun bir parçası değildir. Bu ise POSIX standardının parçası. Bununla birlikte, ISO C'nin resmi bir parçası olmamasına rağmen, bunu sağlayan birçok C uygulaması vardır. Ancak, öyle olmasalar bile, bu cevabın beş astarı fazlasıyla yeterli olmalıdır.
paxdiablo

2
İyi bir nokta, @chux, ISO sadece { EDOM, EILSEQ, ERANGE }gerekli hata kodları gibi zorunlu kılar . Bunun hesabının cevabını güncelledik.
paxdiablo

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

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

Belki kod biraz daha hızlı olan daha strcpy()olarak \0kömür (Zaten birlikteydi tekrar aranacak gerekmez strlen()).


Teşekkürler. Kişisel uygulamamda bunu daha da kötüleştiriyorum. return memcpy(malloc(len), s, len);Ben NULLayırma hatası yerine ayırma çökmesini tercih gibi .
Patrick Schlüter

3
@ tristopia dereferencing çökmek NULLzorunda değil; tanımsız. Kilitlendiğinden emin olmak istiyorsanız, başarısız olduğunda bir emallocçağrı yazın abort.
Dave

Bunu biliyorum, ancak uygulamamın yalnızca Solaris veya Linux'ta (uygulamanın doğası gereği) çalışacağı garanti ediliyor.
Patrick Schlüter

@ tristopia: İşleri en iyi şekilde yapma alışkanlığı içinde olmak güzel. emallocSolaris veya Linux'ta gerekli olmasa bile kullanma alışkanlığına sahip olun, böylece gelecekte diğer platformlarda kod yazarken kullanacaksınız.
ArtOfWarfare

51

Diğer cevapları tekrarlamanın bir anlamı yok, ancak strdup()herhangi bir C standardının parçası olmadığı için C perspektifinden istediği her şeyi yapabileceğini lütfen unutmayın . Ancak POSIX.1-2001 tarafından tanımlanır.


4
strdup()taşınabilir? Hayır, POSIX dışı ortamda kullanılamaz (zaten önemsiz bir şekilde uygulanabilir). Ancak POSIX işlevinin her şeyi yapabileceğini söylemek oldukça bilgiçlik taslayan bir şey. POSIX, C'ler kadar iyi ve daha popüler olan başka bir standarttır .
PP

2
@BlueMoon Bence POSIX hiçbir uygunluk iddia C uygulaması hala strdupbir uzantısı olarak bir işlev sağlayabilir düşünüyorum . Böyle bir uygulamada, bunun strdupPOSIX işleviyle aynı şekilde davrandığının garantisi yoktur . Bu tür uygulamaları bilmiyorum, ancak meşru, kötü niyetli olmayan bir uygulama, char *strdup(char *)tarihi nedenler sağlayabilir ve a const char *.

C standardı ve POSIX arasındaki fark nedir? C standardına göre, C standart kütüphanelerinde mevcut değil mi?
Koray Tugay

@KorayTugay Bunlar farklı standartlardır. Belirli bir C işlevi standardının POSIX standardına uygun olduğunu ve derleyicinizin / kitaplığınızın bu işlev standardına uygun olduğunu bilmediğiniz sürece bunlara ilgisiz davranmanız daha iyi olur.
Matthew,

17

Gönderen strdup adam :

strdup()Fonksiyon ile gösterilen dize kopyası yeni bir dizeye, bir gösterici döneceğiz s1. Döndürülen işaretçi 'e geçirilebilir free(). Yeni dize oluşturulamazsa boş bir işaretçi döndürülür.


4

strdup (), '\ 0' bitiş karakterini içeren karakter dizisi için dinamik bellek ayırma yapar ve yığın belleğinin adresini döndürür:

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
}

Yani, yaptığı şey, bize, bellek ayırmamızı gerektirmeden, argümanı tarafından verilen dize ile aynı olan başka bir dize vermektir. Ama yine de daha sonra serbest bırakmamız gerekiyor.


3

Bir çalıştırarak geçirilen dize bir kopyasını yapar malloc ve strcpy geçirilen dize. Malloc'ed tampon dolayısıyla arayana çalıştırmak için ihtiyaç döndürülür serbest dönüş değeri.


3

strdupve strndupPOSIX uyumlu sistemlerde olduğu gibi tanımlanmıştır:

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

Strdup () işlevi, dize bir kopyasını için yeterli bellek ayırır str, buna kopya ve döner bir işaretçi yok.

İşaretçi daha sonra işleve bir argüman olarak kullanılabilir free.

Yetersiz bellek varsa NULL, döndürülür ve errnoolarak ayarlanır ENOMEM.

Strndup () en fazla fonksiyon kopyalar lendizesini karakterler strhep kopyalanan dizesini sonlandırma boş.


1

Yaptığı en değerli şey, kendinize bellek (konum ve boyut) tahsis etmenize gerek kalmadan, birincisine özdeş başka bir dize vermektir. Ancak, belirtildiği gibi, yine de serbest bırakmanız gerekiyor (ancak bu da bir miktar hesaplaması gerektirmiyor.)


1

İfade:

strcpy(ptr2, ptr1);

eşdeğerdir (bunun işaretçileri değiştirmesi dışında):

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

Buna karşılık:

ptr2 = strdup(ptr1);

şuna eşittir:

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

Bu nedenle, kopyaladığınız dizenin başka bir işlevde kullanılmasını istiyorsanız (yığın bölümünde oluşturulduğu gibi), kullanabilirsiniz strdup, başka strcpyyeterli,


0

Strdup () işlevi, dize çoğaltması için bir kısayoldur, bir parametreyi dize sabiti veya dize değişmezi olarak alır ve dize için yeterli alan ayırır ve ayrılan alana karşılık gelen karakterleri yazar ve son olarak ayrılan adresin adresini döndürür çağıran rutine kadar alan.


1
Argümanı strdupbir dize sabiti olmak zorunda değildir, bir C dizesi, yani boş bir sonlandırılmış dizisi olmalıdır char.
chqrlie
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.