https://m.toutiao.com/is/JwmYg8w/
本文接續(xù)《C語言中的匕首 - C風格字符串》。
讓我們展開聊聊C風格字符串的常見操作。
比較兩個字符串,憑借C標準庫里的strcmp函數,這項任務易如反掌。strcmp的函數原型如下。
int strcmp(const char * s1, const char * s2)
從首字符開始,依次比較。
返回值等于0,則兩字符串相等。
返回值大于0, 則字符串s1大于s2。
返回值小于0, 則字符串s1小于s2。
例如,
assert(strcmp('hello', 'Hello') > 0); // 因為字符h大于字符Hassert(strcmp('hello', 'hello ') < 0); assert(strcmp('hello', 'hello') == 0);
最常見的字符串操作之一。例如,從一串字符串中取出前五個字符。
熟悉C++的朋友可能知道C++的std::string類有一個取子字符串的方法: std::string substr(size_t pos = 0, size_t len = std::string::npos)。沒必要羨慕,我們自造一個類似的C函數。請看示例代碼。
#include <string.h>#include <stdio.h>#include <assert.h>// 目的:取指定的子字符串存入目標字符// 返回:指向目標字符串的指針// 目標字符串的分配內存空間必須大于或者等于源頭字符串的分配內存空間// 否則,后果不可預測char* substr(char* dest, // 目標字符串 const char source[], // 源頭字符串 size_t start_index, size_t end_index){ assert(dest != NULL); assert(start_index < end_index); assert(end_index <= strlen(source)); size_t len = end_index - start_index; strncpy(dest, source + start_index, len); dest[len] = '\0'; return dest;}int main(){ char s[] = 'hello, world!'; char dest[strlen(s) + 1]; substr(dest, s, 0, 5); assert(strcmp('hello', dest) == 0); assert(strcmp('ello,', substr(dest, s, 1, 6)) == 0); assert(strcmp('h', substr(dest, s, 0, 1)) == 0); return 0;}
C語言標準庫提供與字符串拷貝相關的庫函數。憑借這些函數,拷貝字符串相當簡單。
char* strcpy(char* source, const char* dest);char* strncopy(char source, const char* dest, size_t len);
#include <assert.h>#inlcude <string.h> int main(){ char s[] = 'hello, world!'; // 使用strcpy函數拷貝字符串 char cp[strlen(s)+1]; strcpy(cp, s); if (cp) assert(strcmp(cp, s) == 0); // 使用strncpy函數拷貝字符串 char cp2[strlen(s)+1]; strncpy(cp2, s, strlen(s)); cp2[strlen(s)] = '\0'; // 這一步不可省略。否則后果嚴重! if (cp2) assert(strcmp(cp2, s) == 0); return 0;}
熟悉C++的朋友或許在想,拷貝一個字符串,用C++多簡單啊,C語言太費事了。而且,你看,C++有很多種辦法拷貝一個字符串。
#include <string>#include <cassert>int main(){ char c_str[] = 'hello'; std::string str {'hello'}; std::string str1 {str}; // 方法1 std::string str2 = str; // 方法2 std::string str3 {str.cbegin(), str.cend()}; // 方法3 std::string str4 {c_str, c_str + strlen(c_str)}; // 方法4 assert(str == str1); assert(str == str2); assert(str == str3); assert(str == str4); return 0;}
這彰顯了C和C++,Java等語言的不同的設計理念和價值觀。
C語言用盡量精簡的語言核心,竭盡全力使經常性開支(overhead costs)為零。例如,拷貝字符串,用庫函數完成,不是發(fā)明一種操作符或者重用某種操作符來完成。這是很多高級C程序員熱愛C的源泉,這也是C語言長盛不衰的原因之一。
C++引入各種語法,盡量使經常性開支(overhead costs)降為零。例如,拷貝用重載操作符“=”等實現。C++由此走上不停擴張語言的道路,越來越龐大。C++程序員和C++編譯器不斷升級學習新內容和避免新舊知識發(fā)生沖突。
類似C++, Java引入各種各樣的語法和其他語言花式,把設計焦點放在安全性和移植性上,而經常性開支不是重點,只要試圖控制在電腦和程序員可以忍受的范圍內就好了。
用C如何拼接字符串?C語言標準庫已有了相關庫函數。
char* strcat(char* dest, const char* src);char* strncat(char* dest, const char* src, size_t n);
例如,我們拼接兩個C風格字符串s1和s2,形成一個新的C風格字符串s3。如何編程?請看。
char s1[] = 'hello,';char s2[] = ' world!';char s3[strlen(s1) + strlen(s2) + 1];s3[0] = '\0'; // 注意!這一步不能省略strcat(s3, s1);strcat(s3, s2);assert(strcmp('hello, world!', s3) == 0);
至此,介紹了C風格字符串的常用操作。從例子代碼看得出,其實操作C風格字符串并不難。C語言的標準庫string.h是C語言程序員的好朋友,內含很多庫函數供調用。用好標準庫中的庫函數一舉兩得,一避免重復造輪子,二獲得良好的代碼可移植性。
然而,有沒有更好地使用C風格字符串的策略呢?能不能取C和C++二者最好的部分,用來處理字符串呢?且看下篇文章詳解。
聯(lián)系客服