本文為程序設計基礎,本文為1.8.2 字符串常量第三點:字符串函數。
1.字符串函數
標準C提供了一個操作字符串的接口string.h,其中的很多函數是有特殊用途的,下面將詳細介紹通過string.h導出的最重要的函數原型。
strlen()函數用于統(tǒng)計字符串的長度,其函數原型如下:
size_t strlen(const char *s);
//前置條件:s是一個以null結尾的字符串
//后置條件:返回值為s中的字符個數(不包括null字符)
下面的函數可以縮短字符串的長度,其中用到了strlen()。即:
1 void fit(char *string, unsigned int size)
2 {
3 if(strlen(string) > size)
4 strlen[size] = '\0';
5 }
由于該函數要改變字符串,因此函數在聲明形參string時沒有使用const限定符。當然,也可以調用strlen(s)確定字符串s的長度,或用if語句比較兩個字符串是否相等。即:
if(strcmp(s1, s2) == 0) …
用于拼接字符串的strcat()函數接受兩個字符串作為參數,其函數原型如下:
char *strcat(char *s1, char const *s2);
//前置條件:s2是一個以null結尾的字符串,s1數組的末尾還有足夠的空間容納s2的一個副本
//后置條件:s2被連接到s1中,且返回值是一個指針,該指針指向s1數組的第一個字符
該函數將第2個字符串的備份附加在第1個字符串末尾,s2字符串的第1個字符將覆蓋s1字符串末尾的空字符,并將拼接后的新字符串作為第1個字符串返回,第2個字符串不變。strcat()函數的類型是char *(即指向char的指針),strcat()函數返回第1個參數,即拼接第2個字符串后的第1個字符串的地址。
由于strcat()函數無法檢查第1個數組是否能夠容納第2個字符串,如果分配給第1個數組的空間不夠大,那么多出來的字符溢出到相鄰存儲單元時就會出問題,當然也可以用strlen()查看第1個數組的長度。注意,要給拼接后的字符串長度加1才夠空間存放末尾的空字符。或者用strncat(),該函數的第3個參數指定了添加的最大字符數,其函數原型如下:
char *strncat(char *s1, char const *s2, size_t n);
該函數將s2字符串中的n個字符拷貝到s1字符串末尾,s2字符串中的第1個字符將覆蓋s1字符串末尾的空字符。不會拷貝s2字符串中的空字符和其后的字符,并在拷貝字符的末尾添加一個空字符,該函數返回s1。
strcmp()函數要比較的是字符串的內容,不是字符串的地址,其函數原型如下:
int strcmp(char const *s1, char const *s2);
//前置條件:s1和s2都是以null結尾的字符串
//后置條件:返回值為0,表示s1=s2;
// 返回值小于0,表示s1在詞典順序上位于s2之前;
// 返回值大于0,表示s1在詞典順序上位于s2之后
如果s1字符串在機器排序序列中位于s2字符串的后面,該函數返回一個正數;如果兩個字符串相等,則返回0;如果s1字符串在機器排序序列中位于s2字符串的前面,則返回一個負數。strcmp()函數比較的是字符串("hello")不是字符('q'),所以其參數應該是字符串。由于char的類型實際上是整數類型,因此可以使用關系運算符比較字符。如果兩個字符串開始的幾個字符都相同會怎樣?strcmp()會依次比較每個字符,直到發(fā)現(xiàn)第1對不同的字符為止,然后返回相應的值。比如,"apples"和"apple"只有最后一對字符不一樣("apples"的s和"apple"的空字符),由于空字符在ASCII中排第1,字符s一定在它后面,所以strcmp()返回一個正數。
最后一個例子,strcmp()比較所有的字符,不只是字母。與其說該函數按字母順序進行比較,還不如說是按機器排序序列進行比較,即根據字符的數值(ASCII值)進行比較,在ASCII中,大寫字母在小寫字母前面,因此strcmp("Z", "a")返回的是負值。
在大多數情況下,strcmp()返回的具體值并不重要,只在意該值是0還是非0,即比較兩個值是否相等,或按字母排序字符串,此時需要知道比較的結果是正、負或0。假設word是存儲在char類型數組中的字符串,ch是char類型的變量。即:
if(strcmp(word, "hello") == 0) puts("bye")
if(ch == 'q' ) puts("bye")
盡管如此,不要使用ch或'q'作為strcmp()的參數。
strcmp()比較兩個字符串中的字符,直到發(fā)現(xiàn)不同的字符為止,這一過程可能會持續(xù)到字符串的末尾。而strcmp()在比較兩個字符串時,可以比較字符不同的地方,也可以只比較第3個參數指定的字符數。其函數原型如下:
int strncmp(char const *s1, char const *s2, size_t n);
strcpy()函數有兩個屬性,第一,strcpy()的返回值類型為char *,該函數返回的是第1個參數的值,即一個字符的地址。第二,第1個參數不必指向數組的開始,這個屬性可用于拷貝數組的一部分。注意,strcpy()將源字符串中的空字符也拷貝在內。
如果pts1和pts2都是指向字符串的指針,那么下面語句拷貝的是字符串的地址,而不是字符串本身。即:
pts2 = pts1;
如果希望拷貝整個字符串,可以使用strcpy()函數。其函數原型如下:
char *strcpy(char *s1, char const *s2);
//前置條件:s2是一個以null結尾的字符串,s1數組有足夠的空間容納s2的一個副本
//后置條件:s2被復制到s1,且返回值是一個指針,該指針指向s1數組的第一個字符
該函數將s2指向的字符串(包括空字符)拷貝至s1指向的位置,返回s1。即strcpy()接受2個字符串指針作為參數,可以將指向源字符串的第2個指針聲明為指針、數組名或字符串常量,而指向源字符串副本的第1個指針應指向一個數據對象,比如,數組,且對象要有足夠的空間存儲字符串的副本,通常將拷貝出來的字符串稱為目標字符串。注意,聲明數組將分配存儲數據的空間,而聲明指針只分配存儲一個地址的空間。
strcpy()和strcat()都有同樣的問題,它們不能檢查目標空間是否能容納源字符串的副本,因此拷貝字符串使用strncpy()更安全,該函數的第3個參數指明可拷貝的最大字符數。其函數原型如下:
char *strncpy(char *s1, char const *s2, size_t n);
該函數將s2指向的字符串拷貝至s1指向的位置,拷貝的字符不超過n,其返回值為s1。該函數不會拷貝空字符后面的字符,如果源字符串中的字符數少于n,則目標字符串就以拷貝的空字符結尾。如果源字符串有n個或超過n個字符,就不拷貝空字符,所以拷貝的副本中不一定有空字符。基于此,一般會將n設置比目標數組大小少1,然后將數組最后一個元素設置為空字符。
這樣做的目的將確保存儲的是一個字符串,如果目標空間能夠容納源字符串的副本,那么從源字符串拷貝的空字符便是該副本的結尾;如果目標空間裝不下副本,則將副本最后一個元素設置為空字符。
盡管C語言允許將字符串作為一個字符數組或一個指向字符的指針,但是從更抽象的角度理解字符串將會更有意義。如果你想訪問字符串中的單個字符,則需要注意它的表現(xiàn)形式。如果將字符串當作一個整體來看待的話,那么就可以忽略其表現(xiàn)的細節(jié),而寫出更容易理解的程序。比如:
typedef char *striing;
其目的是強調字符串是一個在概念上完全不同的類型,雖然string與char *類型完全相同,但它們傳遞的信息卻是不同的。如果將一個變量定義為char *類型,其底層的表示方法是指針;如果將一個變量定義為string類型,就會將該字符串作為整體看待。這樣一來,在聲明函數的形參時,無論是將字符串作為數組、指針或抽象數據類型,它們都是可以互換的,其聲明方法如下:
int strlen(string cStr);
int strlen(char cStr[]);
int strlen(char *cStr);
雖然標準C提供的string.h接口提供了一系列的字符串操作函數,它允許在函數調用時將字符串作為一個整體對待,但這些函數同樣要求我們了解底層的表示,即函數將分配內存的任務留給了用戶,特別是檢測緩沖區(qū)溢出的條件。當使用這個接口時,用戶要為每個字符串的存儲負責。這種分配方式不僅增加了程序員的負擔,也間接使得編碼中的錯誤增多了。
使用gets()函數從標準輸入讀入字符串容易導致緩沖區(qū)溢出,而誤用strcpy()和strcat()同樣如此。因為使用某些函數可能造成攻擊者用格式化字符串攻擊的方法訪問內存,甚至能夠注入代碼,所以C11版本加入了strcat_s()和strcpy_s()函數,如果發(fā)生緩沖區(qū)溢出,它們會返回錯誤。printf()、fprintf()和snprintf()這些函數都接受格式化字符串作為參數,避免這類攻擊的一種簡單方法是不要將用戶提供的格式化字符串傳給這些函數。
-
字符串
+關注
關注
1文章
579瀏覽量
20528 -
C語言編程
+關注
關注
6文章
90瀏覽量
21108 -
數據結構
+關注
關注
3文章
573瀏覽量
40136 -
程序設計
+關注
關注
3文章
261瀏覽量
30396 -
周立功
+關注
關注
38文章
130瀏覽量
37645
原文標題:周立功:字符真正價值在于形成字符序列——字符串函數
文章出處:【微信號:ZLG_zhiyuan,微信公眾號:ZLG致遠電子】歡迎添加關注!文章轉載請注明出處。
發(fā)布評論請先 登錄
相關推薦
評論