Chính xác thì nó nghe như thế nào, giả sử bạn đã quen với cách viết tắt trong đó C và UNIX gán các từ, nó nhân đôi chuỗi :-)
Hãy nhớ rằng nó thực sự không phải là một phần của tiêu chuẩn ISO C (a) (đó là điều POSIX), nó thực sự hoạt động giống như mã sau:
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
}
Nói cách khác:
Nó cố gắng phân bổ đủ bộ nhớ để giữ chuỗi cũ (cộng với ký tự '\ 0' để đánh dấu kết thúc chuỗi).
Nếu phân bổ thất bại, nó đặt errno
thành ENOMEM
và trả về NULL
ngay lập tức. Thiết của errno
để ENOMEM
là một cái gì đó malloc
làm trong POSIX vì vậy chúng tôi không cần phải làm một cách rõ ràng trong của chúng tôi strdup
. Nếu bạn không tuân thủ POSIX, ISO C thực sự không bắt buộc sự tồn tại của ENOMEM
vì vậy tôi đã không đưa nó vào đây (b) .
Mặt khác, phân bổ hoạt động để chúng tôi sao chép chuỗi cũ sang chuỗi mới (c) và trả lại địa chỉ mới (mà người gọi có trách nhiệm giải phóng tại một số điểm).
Hãy nhớ rằng đó là định nghĩa khái niệm. Bất kỳ nhà văn thư viện nào xứng đáng với mức lương của họ có thể đã cung cấp mã được tối ưu hóa mạnh mẽ nhắm mục tiêu vào bộ xử lý cụ thể đang được sử dụng.
(a) Tuy nhiên, các chức năng bắt đầu bằng str
và một chữ cái viết thường được bảo lưu theo tiêu chuẩn cho các hướng trong tương lai. Từ C11 7.1.3 Reserved identifiers
:
Mỗi tiêu đề khai báo hoặc định nghĩa tất cả các định danh được liệt kê trong mệnh đề phụ được liên kết của nó và * tùy ý khai báo hoặc định nghĩa các định danh được liệt kê trong mệnh đề phụ thư viện hướng tương lai của thư viện. **
Các hướng tương lai cho string.h
có thể được tìm thấy trong C11 7.31.13 String handling <string.h>
:
Tên hàm bắt đầu bằng str
, mem
hoặc wcs
và một chữ cái viết thường có thể được thêm vào các khai báo trong <string.h>
tiêu đề.
Vì vậy, bạn có thể nên gọi nó là một cái gì đó khác nếu bạn muốn được an toàn.
(b) Thay đổi về cơ bản sẽ được thay thế if (d == NULL) return NULL;
bằng:
if (d == NULL) {
errno = ENOMEM;
return NULL;
}
(c) Lưu ý rằng tôi sử dụng strcpy
cho điều đó vì điều đó cho thấy rõ ý định. Trong một số triển khai, có thể nhanh hơn (vì bạn đã biết độ dài) để sử dụng memcpy
, vì chúng có thể cho phép chuyển dữ liệu theo khối lớn hơn hoặc song song. Hoặc có thể không :-) Câu thần chú tối ưu hóa số 1: "đo lường, đừng đoán".
Trong mọi trường hợp, nếu bạn quyết định đi theo con đường đó, bạn sẽ làm một cái gì đó như:
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
}