C 程式設計/string.h/strcpy
C 程式語言提供了一個名為strcpy的庫函式,該函式在 string.h 標頭檔案中定義,允許將以 null 結尾的記憶體塊從一個位置複製到另一個位置。由於 C 中的字串不是一等資料型別,而是作為記憶體中連續的位元組塊實現的,strcpy將有效地複製給定兩個指向已分配記憶體塊的指標的字串。
該函式的原型為:[1]
char *strcpy(char *destination, const char *source);
引數順序模仿賦值:目標“=”源。返回值為destination。
例如
char *str1 = "abcdefghijklmnop";
char *str2 = malloc(100); /* must be large enough to hold the string! */
strcpy(str2, str1); /* str2 is now "abcdefghijklmnop" */
str2[0] = 'A'; /* str2 is now "Abcdefghijklmnop" */
/* str1 is still "abcdefghijklmnop" */
在第二行,分配記憶體以儲存字串的副本,然後將字串從一個記憶體塊複製到另一個記憶體塊,然後修改該副本的第一個字母。
雖然簡單的賦值str2 = str1可能看起來做同樣的事情,但它只複製了str1的記憶體地址到str2中,而不是實際的字串。兩者str1和str2將引用相同的記憶體塊,並且以前由str2指向的已分配塊將丟失。對 str2[0] 的賦值要麼也會修改 str1,要麼會導致訪問衝突(因為現代編譯器通常將字串常量放在只讀記憶體中)。
該strcpy函式透過迭代字串的各個字元並將它們逐個複製來執行復制。的顯式實現為strcpy是
char *strcpy(char *dest, const char *src)
{
unsigned i;
for (i=0; src[i] != '\0'; ++i)
dest[i] = src[i];
//Ensure trailing null byte is copied
dest[i]= '\0';
return dest;
}
一個常見的緊湊實現是
char *strcpy(char *dest, const char *src)
{
char *save = dest;
while(*dest++ = *src++);
return save;
}
C 庫提供的現代版本通常一次複製的位元組數遠不止一個,依靠位數學來檢測較大的字在寫入之前是否包含空位元組。通常,呼叫會編譯成專門用於執行的內聯機器指令strcpy.
strcpy將適用於所有常見的 Unicode 字串位元組編碼,包括 UTF-8。只要空位元組從未被其使用,就無需實際知道編碼。
如果 Unicode 以大於一個位元組的單位編碼,例如 UTF-16,則需要不同的函式,因為空位元組將出現在較大的程式碼單元的一部分中。C99 定義了函式wcscpy(),它將複製wchar_t大小的物件並在第一個值為零的物件處停止。這不像看起來那麼有用,因為不同的計算機平臺在多大程度上存在分歧wchar_t是(有些使用 16 位,有些使用 32 位)。
strcpy可能很危險,因為如果要複製的字串太長而無法放入目標緩衝區,它將覆蓋相鄰的記憶體,從而呼叫未定義的行為。通常,程式在這種情況下只會導致分段錯誤,但熟練的攻擊者可以使用緩衝區溢位來侵入系統。為了防止緩衝區溢位,已經使用了幾個替代方案strcpy。它們都帶有一個額外的引數,即目標緩衝區的長度,並且不會寫入該緩衝區末尾之外。如果提供了不正確的長度,它們仍然可能導致緩衝區溢位。
char* strncpy(char* dst, const char* src, size_t size);
strncpy寫入完全給定的位元組數,如果字串太長,則僅複製字串的開頭,或者在副本的末尾新增零以填充緩衝區。它被引入 C 庫是為了處理結構(如目錄條目)中的固定長度名稱欄位。儘管它的名稱如此,但它不是的受限版本strcpy;它不能保證結果是以 null 結尾的字串。函式的名稱具有誤導性,因為strncat和snprintf 分別是的受限版本strcat和sprintf.
假設結果是以 null 結尾的字串會導致兩個問題。如果源字串太長,則結果不是以 null 結尾的,這使得緩衝區末尾之後的資料看起來像是字串的一部分。並且如果源字串比緩衝區短得多,則會浪費大量時間用 null 位元組填充緩衝區的其餘部分。
標準 C 庫中始終附加一個 null 位元組的另一種方法是使用 strncat,並將最初為空的字串作為目標。
size_t strlcpy(char* dst, const char* src, size_t size);
該strlcpy函式由 OpenBSD 開發人員 Todd C. Miller 和 Theo de Raadt 建立,通常被認為是更安全的版本strncpy。它始終新增一個 null 位元組,並返回所需的位元組數,允許呼叫者在可能的情況下重新分配緩衝區。它已被移植到許多作業系統,但值得注意的是,glibc 維護者 Ulrich Drepper 拒絕了它,他建議 C 程式設計師需要跟蹤字串長度,並且“使用此函式只會導致其他錯誤”。[2]
errno_t strcpy_s(char* dst, rsize_t size, const char* src);
strcpy_s 函式,在 ISO/IEC TR 24731 中提議進行標準化,[3][4] 受 Microsoft C 執行時庫[5] 和一些其他 C 庫的支援。如果源字串不適合,則返回非零值,並將緩衝區設定為空字串(而不是字首!)。它也明確地不受某些庫(包括 GNU C 庫)的支援。[6] Microsoft 編譯器生成的警告訊息建議程式設計師更改strcpy和strncpy為該函式,據一些人推測,這是微軟試圖將開發人員鎖定在其平臺上的一種嘗試。[7][8]
- ↑ ISO/IEC 9899:1999 規範,第 326 頁,第 7.21.2.3 節
- ↑ libc-alpha 郵件列表,選自 2000 年 8 月 8 日的主題:53、60、61
- ↑ ISO/IEC. ISO/IEC WDTR 24731 安全 C 庫函式規範. 國際標準化組織. 檢索於 2008-04-23.
- ↑ Plakosh,Daniel。 “strcpy_s() 和 strcat_s()”。Pearson Education, Inc。檢索於 2006-08-12.
- ↑ Microsoft。 “CRT 中的安全增強功能”。MSDN。檢索於 2008-09-16.
- ↑ “關於實現“C 庫擴充套件”(ISO/IEC WG14 N1172)”.
- ↑ Danny Kalev。 “他們又來了”。InformIT。
- ↑ “安全增強 CRT,比標準庫更安全?”.
std::strcpy的 C++ 參考- :複製字串 – OpenBSD 庫函式手冊