跳轉到內容

C 程式設計/string.h/函式參考

來自華夏公益教科書,開放的書籍,開放的世界


#include <string.h>
void *memset(void *s, int c, size_t n);

memset()c 複製到 s 指向的物件的前 n 個位元組中。

返回值

[編輯 | 編輯原始碼]

該函式返回指標 s。當發生錯誤時,沒有定義的返回值。

在計算中,C 程式語言提供了一個名為 strcat 的庫函式,允許將一個記憶體塊附加到另一個記憶體塊。這兩個記憶體塊都需要以 null 結尾。因為在 C 中,字串不是一等公民資料型別,而是作為記憶體中的 ASCII 位元組塊實現的,strcat將有效地將一個字串附加到另一個字串,給定指向兩個已分配記憶體塊的指標。名稱strcat是“字串連線”的縮寫。strcat可以在string.h標頭檔案中找到。

例如

char str1[14] = "Hello,";    /* The array has enough space for 'Hello,' plus " world!" plus a null terminator */
strcat(str1, " world!");
puts(str1);                 /* prints "Hello, world!" to stdout followed by a newline */

以下是可能實現的strcat:

char *
strcat(char *dest, const char *src)
{
    size_t i,j;
    for (i = 0; dest[i] != '\0'; i++)
        ;
    for (j = 0; src[j] != '\0'; j++)
        dest[i+j] = src[j];
    dest[i+j] = '\0';
    return dest;
}

它也可以用其他字串庫函式來定義

char *
strcat(char *dest, const char *src)
{
    strcpy(dest + strlen(dest), src);
    return dest;
}

邊界錯誤

[編輯 | 編輯原始碼]

strcat可能是危險的,因為如果要附加的字串太長,無法放入目標緩衝區,它將覆蓋相鄰的記憶體,從而引發未定義的行為。通常程式在這種情況下只會導致段錯誤,但熟練的攻擊者可以使用這種緩衝區溢位攻擊來侵入系統(參見計算機安全)。

邊界檢查變體

[編輯 | 編輯原始碼]

為了防止緩衝區溢位,已經使用了多種替代strcat的方法。它們都接受一個額外的引數,該引數對目標緩衝區的長度進行編碼,並且不會寫入該緩衝區末尾。如果提供了錯誤的長度,它們都可能導致緩衝區溢位。

char* strncat(char* dst, const char* src, size_t n);

最常見的邊界變體,strncat,只附加指定數量的位元組,加上一個 NULL 位元組。這允許每個連線的字串使用不超過其在緩衝區中的“份額”,也許是用來製作表格的。它不適合更常見的需求,即獲得適合緩衝區的連線字串的字首。為此,要傳遞的計數的正確值是bufferSize-strlen(buffer)-1。常見的錯誤是傳遞bufferSize, bufferSize-1bufferSize-strlen(buffer),這些都會導致緩衝區溢位。

size_t strlcat(char* dst, const char* src, size_t size);

strlcat函式由 OpenBSD 開發人員 Todd C. Miller 和 Theo de Raadt 建立,通常被認為是strncat的更安全、更有用的版本。它接受緩衝區的實際長度作為引數,並返回所需的位元組數,允許呼叫者根據需要重新分配緩衝區。它已被移植到許多作業系統,但被 glibc 維護者明確拒絕,他們認為 C 程式設計師需要跟蹤字串長度,並且“使用此函式只會導致其他錯誤”。[1]

errno_t strcat_s(char* dst, rsize_t size, const char* src);

strcat_s 函式在 ISO/IEC TR 24731 中提出標準化。[2][3] 受 Microsoft C 執行時庫支援。[4] 以及其他一些 C 庫。如果源字串不適合,它會返回非零值,並將緩衝區設定為空字串(如果原始字串未儲存在其他位置或呼叫者忽略返回值,則這是一個災難性的結果)。它還被一些庫明確不支援,包括 GLibc 庫。[5] Microsoft 編譯器發出的警告訊息,建議程式設計師將strcatstrncat更改為此函式,據一些人推測是微軟試圖將開發者鎖定在其平臺上。[6][7]

[編輯 | 編輯原始碼]

C 和 C++ 的函式名稱 strchr()

語法
include <string.h>
char *strchr(const char *s, int c);

描述
strchr() 函式在 s 指向的字串中查詢 c 的第一個出現,轉換為 char。終止 null 字元被認為是字串的一部分。

引數
s 指向要搜尋的字串。

c 是要在字串 s 中搜索的字元。

返回值
strchr() 函式返回指向 s 內找到的字元 c 的第一個出現的指標。如果字串中沒有出現字元 c,strchr() 返回一個空指標。

在 POSIX 和 C 程式語言中,strcmp 是 C 標準庫中的一個函式(在 string.h 中宣告),用於比較兩個 C 字串。

根據 ISO/IEC 9899:1999,7.21.4.2 的原型

int strcmp(const char *s1, const char *s2);

當字串相等時,strcmp 返回 0;當 s1 小於 s2 時,返回負整數;當 s1 大於 s2 時,返回正整數,根據字典序。

strcmp 的一個變體名為 strncmp,它只比較字串到一定偏移量。

另一個變體 strcasecmp 符合 POSIX.1-2001,工作方式類似於 strcmp,但區分大小寫。一些系統反而用名為 stricmpstrcmpi 的函式提供此功能。為了區分大小寫地比較兩個字串的子集,各種系統可能會提供 strncasecmpstrnicmpstrncmpi

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main (int argc, char **argv)
{
    int v;

    if (argc < 3)
    {
        fprintf (stderr, "Compares two strings\nUsage: %s string1 string2\n",argv[0]);
        return EXIT_FAILURE;
    }

    v = strcmp (argv[1], argv[2]);

    if (v < 0)
        printf ("'%s' is less than '%s'.\n", argv[1], argv[2]);
    else if (v == 0)
        printf ("'%s' equals '%s'.\n", argv[1], argv[2]);
    else if (v > 0)
        printf ("'%s' is greater than '%s'.\n", argv[1], argv[2]);

    return 0;
}

上面的程式碼是一個工作示例,它列印第一個引數是否小於、等於或大於第二個引數。

可能的實現是(P.J. Plauger,The Standard C Library,1992)

int strcmp (const char * s1, const char * s2)
{
    for(; *s1 == *s2; ++s1, ++s2)
        if(*s1 == 0)
            return 0;
    return *(unsigned char *)s1 < *(unsigned char *)s2 ? -1 : 1;
}

但是,大多數現實世界的實現將具有各種最佳化技巧來減少函式的執行時間。你會注意到,strcmp 不僅返回 -1、0 和 +1,還會返回其他負值或正值,這是由於最佳化掉了由 ?: 運算子引入的分支。

return *(const unsigned char *)s1 - *(const unsigned char *)s2;
[編輯 | 編輯原始碼]

C 程式語言提供了一個名為 strcpy 的庫函式,在 string.h 標頭檔案中定義,它允許將以 null 結尾的記憶體塊從一個位置複製到另一個位置。由於 C 中的字串不是一等資料型別,而是作為記憶體中的連續位元組塊來實現,strcpy將有效地複製給定指向兩個已分配記憶體塊的指標的字串。

函式的原型是:[8]

char *strcpy(char *destination, const char *source);

引數順序模仿賦值:目標“=”源。返回值是 目標

用法和實現

[編輯 | 編輯原始碼]

例如

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的記憶體地址str2str1中,但不是實際的字串。兩者都將引用相同的記憶體塊,以前由

strcpy指向的分配塊將丟失。對 str2[0] 的賦值也會修改 str1,或者會導致訪問衝突(因為現代編譯器通常將字串常量放在只讀記憶體中)。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 結尾的字串。函式的名稱具有誤導性,因為strncatsnprintf 的邊界版本,分別是strcatsprintf.

假設結果是以 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 程式設計師需要跟蹤字串長度,並且“使用此函式只會導致其他錯誤”。[1]

errno_t strcpy_s(char* dst, rsize_t size, const char* src);

strcpy_s 函式在 ISO/IEC TR 24731 中被提議用於標準化。[9][10] 它受 Microsoft C 執行時庫[11] 和其他一些 C 庫的支援。如果源字串不適合,它將返回非零值,並將緩衝區設定為空字串(而不是字首!)。它也明確不受一些庫的支援,包括 GNU C 庫。[12] 一些人推測,Microsoft 編譯器發出的建議程式設計師將strcpystrncpy更改為該函式的訊息是 Microsoft 試圖將開發人員鎖定在其平臺上。[13][14]

[編輯 | 編輯原始碼]

strcspn 是來自 C 標準庫(標頭檔案 string.h)的函式。

它在字串中搜索特定的一組字元。

strcspn() 函式計算字串 1 的初始段的長度,該段不包含字串 2 中的任何字元。

返回值

[edit | edit source]

該函式返回字串 1 中第一個與字串 2 中的任何字元匹配的字元的索引。

語法

[edit | edit source]
#include <string.h>

size_t strcspn( const char *str1, const char *str2 );

示例

[edit | edit source]
#include <stdio.h>
#include <string.h>

int main(){
  char s[20] = "wikireader007", t[11] = "0123456789";
  printf("The first decimal digit of s is at position: %d.\n", '''strcspn'''(s, t));

  return 0;
}

輸出:

s 的第一個十進位制數字位於位置:10

[edit | edit source]

strerror

[edit | edit source]

字串錯誤函式 strerror 是一個 C/C++ 函式,它將錯誤程式碼(通常儲存在全域性變數 errno 中)轉換為人類可讀的錯誤訊息。

歷史

[edit | edit source]

strerror 函式在 IEEE Std 1003.1(也稱為 POSIX 1)中定義。

可重入性

[edit | edit source]

strerror 函式不可重入。有關該函式的可重入版本,請參見 strerror r。

用法

[edit | edit source]

包含

[edit | edit source]
#include <string.h>

宣告

[edit | edit source]
char* strerror(int errnum);

語義

[edit | edit source]

該函式生成並報告一個 C 樣式字串,其中包含從與 errnum 傳遞的錯誤程式碼派生的錯誤訊息。

參考

[edit | edit source]
  1. strerror by OpenGroup
[edit | edit source]

strlen

[edit | edit source]

在 C 標準庫中,strlen 是一個字串函式,它確定 C 字串的長度。

示例用法

[edit | edit source]
#include <stdio.h>
#include <string.h>
 
int main()
{
    char *string = "Hello World";
    printf("%lu\n", (unsigned long)strlen(string));
    return 0;
}

此程式將列印值 11,它是字串 "Hello World" 的長度。字元字串儲存在稱為char的資料型別的陣列中。字串的結尾透過搜尋陣列中的第一個空字元來找到。

重要的是要注意,此長度 *不* 包含 C 字串的結束字元所需的尾隨空位元組的陣列條目。因此,如果您需要複製 C 字串,則需要分配 strlen() + 1 的空間。

實施

[edit | edit source]

FreeBSD 6.2 實現strlen如下所示:[15]

size_t strlen(const char * str)
{
    const char *s;
    for (s = str; *s; ++s) {}
    return(s - str);
}

可以在 C 中編寫更快的版本,這些版本檢查完整的機器字而不是逐位元組地檢查。Hacker's Delight 給出了一個演算法,該演算法利用按位運算來檢測這些位元組中的任何一個是否為空 ('\0')。當前的 FreeBSD 實現就是這樣做的。 [16]

現代 C 編譯器通常提供strlen的快速內聯版本,這些版本使用匯編編寫,使用按位運算技術或某些 CISC 處理器提供的特殊指令。此外,strlen引用的字串常量的長度通常最佳化為常數整數。

[edit | edit source]

strrchr

[edit | edit source]

strrchrstring.h 中的函式。[17] 它主要用於從末尾開始搜尋字串中字元的最後一次出現。它返回指向字串中字元最後一次出現的指標。結束空字元被認為是 C 字串的一部分。因此,它也可以被定位以檢索指向字串末尾的指標。

語法

[edit | edit source]

在 C 中,此函式被宣告為

char *strrchr ( const char *, int );

str 是一個 C 字串。character 是要定位的字元。它作為其 int 提升傳遞,但它在內部被轉換回 char。

返回值

[edit | edit source]

指向 str 中 character 最後一次出現的指標。如果未找到該值,該函式將返回一個 空指標

示例

[edit | edit source]
#include <stdio.h>
#include <string.h>

int main(void)
{
    const char *str = "This is a sample string";
    char *pch = strrchr(str, 's');
    printf("Last occurrence of 's' found at %d\n", pch - str + 1);
    return 0;
}

輸出:'s' 的最後一次出現位於 18。

另請參閱

[edit | edit source]

strchr

[edit | edit source]

strspn

[edit | edit source]

strspn() 函式用於找出子字串的長度或由一個字串指向的字串(例如 s1)的最大初始段的長度,該初始段包含來自另一個由另一個字串(例如 s2)指向的字串的所有字元,而 strscpn() 用於發現包含不在拒絕列表中的所有元素的初始段的長度。

size_t strspn(const char *s, const char *accept);

size_t strcspn(const char *s, const char *reject);

s1 - 指向要搜尋的以空字元結尾的字串。

s2 - 指向以空字元結尾的字元集。

strstr是 C 標準庫字串函式,定義在string.h. strstr()具有以下函式簽名:char * strstr(const char *haystack, const char *needle);它返回指向第一個索引處的字元的指標,該索引處needlehaystack中,如果不存在,則返回 NULL。[18]

strcasestr()是一個與strstr()非常相似的函式,它忽略了needlehaystack. strcasestr()是一個非標準函式,而strstr()符合 C89 和 C99。[18]

#include <stdio.h>
#include <string.h>

int main(void) 
{
	/* Define a pointer of type char, a string and the substring to be found*/
	char *cptr;
	char str[] = "Wikipedia, be bold";
	char substr[] = "edia, b";

	/* Find memory address where substr "edia, b" is found in str */
	cptr = strstr(str, substr);

	/* Print out the character at this memory address, i.e. 'e' */
	printf("%c\n", *cptr);

	/* Print out "edia, be bold" */
	printf("%s\n", cptr);
	
	return 0;
}

cptr現在是指向第六個字母(e)的指標,位於 "wikipedia" 中。

[編輯 | 編輯原始碼]

strtok 是 C 庫函式之一。strtok() 函式的語法如下:語法

#include <string.h>
char *strtok( char *str1, const char *str2 );

描述:strtok() 函式返回 str1 中下一個“標記”的指標,其中 str2 包含確定標記的分隔符。如果找不到標記,則 strtok() 返回 NULL。為了將字串轉換為標記,第一次呼叫 strtok() 應使 str1 指向要標記化的字串。所有此後的呼叫都應使 str1 為 NULL。

strxfrm 是 C 標準庫字串函式,在 string.h 中宣告。它根據當前區域設定轉換字串。

此函式的原型為

  size_t strxfrm(char *str1 , const char *str2 , size_t num);

是接收 num 個字元的轉換字串的字串。如果 num 等於零,則 str1 僅包含空字元。

是要轉換的字串。

是要複製到 str1 中的最大字元數。

strxfrm() 函式根據當前區域設定轉換 str2。為此,使用定義在 locale.h 中的 LC_COLLATE 類別。轉換後,轉換後的字串的前 num 個字元被複制到 str1 中。strxfrm() 函式執行轉換,以使對兩個字串的 strcmp 結果與對兩個原始字串的 strcoll 結果相同。

返回值

[編輯 | 編輯原始碼]

strxfrm() 函式返回轉換後的字串的長度,不包括終止空字元。

示例用法

[編輯 | 編輯原始碼]
#include <stdio.h>
#include <string.h>
 
int main(void)
{
    char str2[] = "Hello World";
    char str1[];
    printf("The length of str2 = %d\n",strxfrm(str1, str2, 4));
    printf("The content of str1 = %s\n", str1[]);
    printf("The content of str2 = %s\n", str2[]);
    return 0;
}

str2 的長度 = 11
str1 的內容 = Hell
str2 的內容 = Hello World

[編輯 | 編輯原始碼]
  1. a b libc-alpha 郵件列表,選自 2000 年 8 月 8 日的主題:536061
  2. ISO/IEC. ISO/IEC WDTR 24731 安全 C 庫函式規範. 國際標準化組織. Retrieved 2008-04-23.
  3. Plakosh, Daniel. "strcpy_s() 和 strcat_s()". Pearson Education, Inc. 檢索於 2006-08-12.
  4. 微軟. "CRT 中的安全增強功能". MSDN. 檢索於 2008-09-16.
  5. "Re: 實施“C 庫擴充套件”(ISO/IEC WG14 N1172)".
  6. Danny Kalev. "他們又在搞什麼鬼". InformIT.
  7. "安全增強型 CRT,比標準庫更安全?".
  8. ISO/IEC 9899:1999 規範, 第 326 頁,第 7.21.2.3 節
  9. ISO/IEC. ISO/IEC WDTR 24731 安全 C 庫函式規範. 國際標準化組織. 檢索於 2008-04-23.
  10. Plakosh, Daniel. "strcpy_s() 和 strcat_s()". Pearson Education, Inc. 檢索於 2006-08-12.
  11. 微軟. "CRT 中的安全增強功能". MSDN. 檢索於 2008-09-16.
  12. "Re: 實施“C 庫擴充套件”(ISO/IEC WG14 N1172)".
  13. Danny Kalev. "他們又在搞什麼鬼". InformIT.
  14. "安全增強型 CRT,比標準庫更安全?".
  15. "strlen.c 修訂版 1.4". FreeBSD. 2002-03-21. 檢索於 2009-03-04.
  16. "/stable/10/lib/libc/string/strlen.c 的內容". FreeBSD. 2013-10-10.
  17. ISO/IEC 9899:1999 規範 (PDF). 第 343 頁,第 7.12.4.3 節.
  18. a b strcasestr(3)
華夏公益教科書