strdup () - apa fungsinya di C?

302

Apa tujuan strdup()fungsi di C?

Keraguan Manoj
sumber
44
ada juga strdupa () (di perpustakaan GNU C), fungsi yang bagus yang mirip dengan strdup (), tetapi mengalokasikan memori pada stack. Program Anda tidak perlu membebaskan memori secara eksplisit seperti halnya dengan strdup (), itu akan dibebaskan secara otomatis ketika Anda keluar dari fungsi tempat strdupa () dipanggil
dmityugov
11
strdupaberbahaya dan tidak boleh digunakan kecuali Anda sudah menentukan bahwa strlenitu sangat kecil. Tapi kemudian Anda bisa menggunakan array ukuran tetap pada stack.
R .. GitHub BERHENTI MEMBANTU ICE
4
@slacker google translate tidak membantu ... Apa artinya strdup/ strdupaartinya dalam bahasa Polandia?
haneefmubarak
14
@haneefmubarak di sini
anatolyg
Inilah perbedaan antara strdup dan strcpy stackoverflow.com/questions/14020380/strcpy-vs-strdup
Siva Prakash

Jawaban:

372

Seperti apa persisnya, dengan asumsi Anda terbiasa dengan cara disingkat di mana C dan UNIX memberikan kata-kata, duplikat string :-)

Ingatlah bahwa itu sebenarnya bukan bagian dari standar ISO C itu sendiri (a) (itu adalah hal POSIX), itu secara efektif melakukan hal yang sama seperti kode berikut:

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
}

Dengan kata lain:

  1. Mencoba mengalokasikan cukup memori untuk menampung string lama (ditambah karakter '\ 0' untuk menandai akhir string).

  2. Jika alokasi gagal, set errnoke ENOMEMdan NULLsegera kembali . Pengaturan errnoto ENOMEMadalah sesuatu yang mallocdilakukan di POSIX sehingga kita tidak perlu melakukannya secara eksplisit di strdup. Jika Anda tidak mematuhi POSIX, ISO C tidak benar-benar mengamanatkan keberadaan ENOMEMjadi saya belum memasukkannya di sini (b) .

  3. Kalau tidak, alokasi berhasil jadi kami menyalin string lama ke string baru (c) dan mengembalikan alamat baru (yang penelepon bertanggung jawab untuk membebaskan di beberapa titik).

Ingatlah bahwa itu adalah definisi konseptual. Penulis perpustakaan mana pun yang sepadan dengan gajinya mungkin telah menyediakan kode yang sangat dioptimalkan yang menargetkan prosesor tertentu yang digunakan.


(a) Namun, fungsi yang dimulai dengan strdan huruf kecil disediakan oleh standar untuk arahan di masa mendatang. Dari C11 7.1.3 Reserved identifiers:

Setiap header menyatakan atau mendefinisikan semua pengidentifikasi yang tercantum dalam sub-klausa yang terkait, dan * secara opsional mendeklarasikan atau mendefinisikan pengidentifikasi yang tercantum dalam sub-klausa arah pustaka arah terkait di masa depan. **

Arahan masa depan untuk string.hdapat ditemukan di C11 7.31.13 String handling <string.h>:

Nama fungsi yang dimulai dengan str,, mematau wcsdan huruf kecil dapat ditambahkan ke deklarasi di <string.h>header.

Jadi Anda mungkin harus menyebutnya sesuatu yang lain jika Anda ingin aman.


(B) Perubahan pada dasarnya akan diganti if (d == NULL) return NULL;dengan:

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

(c) Perhatikan bahwa saya menggunakan strcpyuntuk itu karena itu jelas menunjukkan maksudnya. Dalam beberapa implementasi, mungkin lebih cepat (karena Anda sudah tahu panjangnya) untuk digunakanmemcpy , karena mereka memungkinkan untuk mentransfer data dalam potongan yang lebih besar, atau secara paralel. Atau mungkin tidak :-) Mantra pengoptimalan # 1: "ukur, jangan menebak".

Bagaimanapun, jika Anda memutuskan untuk pergi ke rute itu, Anda akan melakukan sesuatu seperti:

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
}
paxdiablo
sumber
8
Perlu dicatat, bahwa seperti implementasi sampel Pax menyiratkan, strdup (NULL) tidak terdefinisi dan bukan sesuatu yang dapat Anda harapkan untuk berperilaku dengan cara yang dapat diprediksi.
bersantai
2
Juga, saya pikir malloc () akan mengatur errno, jadi Anda tidak harus mengaturnya sendiri. Kupikir.
Chris Lutz
5
@Alcot, strdupuntuk situasi di mana Anda ingin menumpuk memori yang dialokasikan untuk salinan string. Kalau tidak, Anda harus melakukannya sendiri. Jika Anda sudah memiliki buffer yang cukup besar (malloc'ed atau sebaliknya), ya, gunakan strcpy.
paxdiablo
2
@acgtyrant: jika, menurut standar, maksud Anda standar ISO (standar C nyata), tidak, itu bukan bagian dari itu. Ini adalah bagian dari standar POSIX. Namun, ada banyak implementasi C yang menyediakannya, meskipun tidak menjadi bagian resmi dari ISO C. Namun, bahkan jika tidak, lima baris dalam jawaban ini harus lebih dari cukup.
paxdiablo
2
Poin bagus, @chux, mandat ISO hanya { EDOM, EILSEQ, ERANGE }sebagai kode kesalahan yang diperlukan. Telah memperbarui jawaban untuk akun ini.
paxdiablo
86
char * strdup(const char * s)
{
  size_t len = 1+strlen(s);
  char *p = malloc(len);

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

Mungkin kodenya sedikit lebih cepat daripada dengan strcpy()karena \0char tidak perlu dicari lagi (sudah ada dengan strlen()).

Patrick Schlüter
sumber
Terima kasih. Dalam implementasi pribadi saya, saya membuatnya bahkan "lebih buruk". return memcpy(malloc(len), s, len);karena saya lebih suka crash pada alokasi daripada NULLkegagalan alokasi.
Patrick Schlüter
3
@tristopia dereferencing NULLtidak harus macet; itu tidak terdefinisi. Jika Anda ingin memastikannya macet, tulis emallocpanggilan mana yang abortgagal.
Dave
Saya tahu itu, tetapi implementasi saya dijamin hanya berjalan di Solaris atau Linux (berdasarkan sifat aplikasi).
Patrick Schlüter
@tristopia: Ada baiknya kebiasaan melakukan hal-hal dengan cara terbaik. Biasakan menggunakan emallocbahkan jika itu tidak perlu di Solaris atau Linux sehingga Anda akan menggunakannya di masa depan ketika Anda menulis kode pada platform lain.
ArtOfWarfare
51

Tidak ada gunanya mengulangi jawaban lainnya, tetapi harap dicatat bahwa strdup()dapat melakukan apa pun yang diinginkan dari perspektif C, karena itu bukan bagian dari standar C apa pun. Namun demikian didefinisikan oleh POSIX.1-2001.

Chris Young
sumber
4
Apakah strdup()portable? Tidak, tidak tersedia di lingkungan non-POSIX (toh bisa diterapkan secara sepele). Tetapi untuk mengatakan fungsi POSIX dapat melakukan apa saja cukup bagus. POSIX adalah standar lain yang sebagus C dan bahkan lebih populer.
PP
2
@ BlueMoon Saya pikir intinya adalah bahwa implementasi C yang mengklaim tidak ada kesesuaian dengan POSIX mungkin masih menyediakan strdupfungsi sebagai ekstensi. Pada implementasi seperti itu, tidak ada jaminan bahwa strdupberperilaku dengan cara yang sama seperti fungsi POSIX. Saya tidak tahu implementasi semacam itu, tetapi implementasi tidak berbahaya yang sah dapat memberikan char *strdup(char *)alasan historis, dan menolak upaya untuk lulus dalam a const char *.
Apa perbedaan antara standar C dan POSIX? Maksudnya standar C, itu tidak ada di perpustakaan standar C?
Koray Tugay
@ KorayTugay Mereka adalah standar yang berbeda. Lebih baik memperlakukannya sebagai tidak terkait kecuali Anda tahu bahwa standar untuk fungsi C tertentu sesuai dengan standar POSIX, dan bahwa kompiler / pustaka Anda sesuai dengan standar untuk fungsi itu.
Matius Baca
17

Dari strdup man :

The strdup()fungsi akan kembali pointer ke string baru, yang merupakan duplikat dari string ditunjukkan oleh s1. Pointer yang dikembalikan dapat diteruskan ke free(). Pointer null dikembalikan jika string baru tidak dapat dibuat.

VONC
sumber
4

strdup () melakukan alokasi memori dinamis untuk array karakter termasuk karakter akhir '\ 0' dan mengembalikan alamat memori tumpukan:

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
}

Jadi, apa yang dilakukannya adalah memberi kita string lain yang identik dengan string yang diberikan oleh argumennya, tanpa mengharuskan kita mengalokasikan memori. Tapi kita masih harus membebaskannya, nanti.

Karshit
sumber
3

Itu membuat salinan duplikat dari string yang dilewatkan dengan menjalankan malloc dan strcpy dari string yang dilewatkan. Buffer malloc'ed dikembalikan ke pemanggil, maka kebutuhan untuk menjalankan bebas pada nilai kembali.

jussij
sumber
3

strdupdan strndupdidefinisikan dalam sistem yang sesuai dengan POSIX sebagai:

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

Fungsi strdup () mengalokasikan memori yang cukup untuk salinan stringstr , melakukan salinan, dan mengembalikan pointer ke sana.

Pointer selanjutnya dapat digunakan sebagai argumen untuk fungsi free .

Jika memori tidak mencukupi, NULLdikembalikan dan errnodisetel ke ENOMEM .

Fungsi strndup () menyalin paling banyak lenkarakter dari string strselalu null mengakhiri string yang disalin.

Sujay Kumar
sumber
1

Hal paling berharga yang dilakukannya adalah memberi Anda string lain yang identik dengan yang pertama, tanpa mengharuskan Anda mengalokasikan memori (lokasi dan ukuran) sendiri. Tetapi, seperti yang disebutkan, Anda masih perlu membebaskannya (tetapi yang tidak memerlukan perhitungan kuantitas, juga.)

dkretz
sumber
1

Pernyataan:

strcpy(ptr2, ptr1);

setara dengan (selain fakta ini mengubah pointer):

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

Sedangkan:

ptr2 = strdup(ptr1);

setara dengan:

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

Jadi, jika Anda ingin string yang telah Anda salin digunakan di fungsi lain (seperti yang dibuat di bagian heap), Anda bisa menggunakan strdup, kalau strcpytidak cukup,

Md. Al Amin Bhuiyan
sumber
0

Fungsi strdup () adalah singkatan untuk duplikat string, mengambil parameter sebagai konstanta string atau string literal dan mengalokasikan ruang yang cukup untuk string dan menulis karakter yang sesuai dalam ruang yang dialokasikan dan akhirnya mengembalikan alamat yang dialokasikan ruang untuk rutinitas panggilan.

AnkitSablok
sumber
1
Argumen untuk strduptidak perlu berupa string konstan, harus berupa string C, yaitu array null yang dihentikan char.
chqrlie