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:
Mencoba mengalokasikan cukup memori untuk menampung string lama (ditambah karakter '\ 0' untuk menandai akhir string).
Jika alokasi gagal, set errno
ke ENOMEM
dan NULL
segera kembali . Pengaturan errno
to ENOMEM
adalah sesuatu yang malloc
dilakukan di POSIX sehingga kita tidak perlu melakukannya secara eksplisit di strdup
. Jika Anda tidak mematuhi POSIX, ISO C tidak benar-benar mengamanatkan keberadaan ENOMEM
jadi saya belum memasukkannya di sini (b) .
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 str
dan 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.h
dapat ditemukan di C11 7.31.13 String handling <string.h>
:
Nama fungsi yang dimulai dengan str
,, mem
atau wcs
dan 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 strcpy
untuk 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
}