寫這篇部落客要是為了疏理一下C/C++标準庫自帶字元串操作函數 ,為迎接9月的“細細诶夫“考試的孩子們(包括我自己咯)整理思路,在處理字元串問題時更加得心應手。
閑話少說,開始進入正體。C/C++中對字元串的操作函數有不少,集中分布在C string.h、stdlib.h,C++ string頭檔案中,當然不排除将其視為容器也可使用algorithm的算法(這個以後再讨論),主要涉及的字元串的複制、移動、連接配接、比較、搜尋、到其他數值類型的互相轉換、以及其他操作,接下來按功能進行分别解析各函數用法以及應用。此外,還将讨論一下其他有用的工具性函數。
C篇:
<string.h> / <cstring>
一.複制
1.(沒什麼卵用系列) void* memcpy(void* destination,const void* source, size_t num)
void* memmove(void* destination, const void* source, size_t num)
這兩個函數屬于對記憶體塊進行操作函數,操作對象是記憶體,是以無視\0l字元的終止限定,從source指針指向的記憶體往後數num bytes,将其copy/move到destination,copy與move均不會導緻destination記憶體的自動配置設定,是以需要程式員自己預先配置設定足夠的記憶體,使用memcpy需要注意source與destination不能有重疊,即存在共有部分,而memmove則允許存在重疊部分,是以比memcpy更安全。
2.(有點用)char* strcpy(char* destination, const char* source)
char* strncpy(char* destination, const char* source, isize_tnum)
與上面兩個mem氏函數不同,str氏的操作對象是字元數組/c風格字元串,是以會受到\0限定,這也可以從參數與傳回值類型為char*而不是void*中看出,于是存在不指定num的情況和指定num的情況,指定num主要對于有特定需求(截取前num位元組)進行複制操作,同樣,這兩個函數也不會對記憶體執行配置設定操作,是以需要程式員自己管理記憶體,防止溢出。
二.連接配接(有點用)
char* strcat(char* destination, const char* source)
char* strncat(char* destination, const char* source, size_t num)
這兩個函數功能為将source的(帶有n則是前num個)字元連接配接到destination尾部,同樣需要程式員保證不會溢出,同時,通過以上我們也能知道c函數庫的命名的套路:操作對象+操作,如果隻對前n個位元組/字元操作,需要在中間加上n,參數為目标字元數組+源字元數組+num,傳回值為目标字元數組。
三.比較(有用)
int strcmp(const void* ptr1, const void* ptr2)
int strncmp(const* char* ptr1, const char* ptr2, size_t num)
這兩個函數功能為将ptr字元數組與ptr2字元數組按字典順序進行比較,ptr1 > ptr2傳回1,ptr1 == ptr2傳回0,ptr1 < ptr2傳回-1。(n的作用同上)
四.搜尋(有用)
1. char* strchr(char* str, int character)
char* strrchar(char* str, int character)
在str中搜尋character字元出現的第一個/最後一個,如果搜尋到,傳回一個指針指向這個字元,如果不存在,傳回NULL。
char* strstr(char* str1, char* str2)
在str1中搜尋字串str2,如果搜尋到,傳回一個指針指向這個字元,如果不存在,傳回NULLl。
2.size_t strspn(const char* str1, const char* str2) (特定情況有用)
size_t strcspn(const char* str1, const char* str2)
中間不帶有c的函數(即strspn)功能為從str1第一個字元從前往後查找在str2中出現過的字元,直到遇到不屬于str2的字元,傳回之前在str2出現過的字元的個數。
中間帶有c的函數(即strcspn)功能“相反”,從str1第一個字元從前往後查找未在str2中出現的字元,直到遇到屬于str2的字元,傳回之前在str2中未出現的字元的個數。
char* strpbrk(const char* str1, const* str2)
在str1中查找第一次出現的屬于str2的字元,并傳回一個指針指向這個字元,如果不存在,傳回NULL。
3.char* strtok(char* str, const char* delimiters) (有用+)
字元串分割函數,這個函數使用起來相比之前略複雜,第一次調用的第一個參數是需要分割的字元串,第二個為分割的标志字元串,而以後每一次調用第一個參數需要調整為NULL,第二個參數不變,傳回值為指向分割後的字串的指針,在每一次查找到後,将找到的标志指派為NULL(\0)。回顧整個流程,相當于将字元串中的标志字元串全部用\0替代,在每一次調用時傳回每個字串的首位址。
五.長度(最常用)
size_t strlen(const char* str)
傳回字元串的長度,以\0作為終止符。
<stdlib.h>/<cstdlib>
一.字元串轉換函數
首先說一下命名的套路:a和str都代表字元串,to代表轉換,數值資料類型的前面的字母代表其他數值資料類型,如i代表int,l代表long,f代表float,
d代表double,然後是沒什麼多用的ul,代表usigned long,其中當後面的為f,i,l時,a代表字元串,為d,l時str代表字元串。
atox的參數為字元數組,傳回值為到第一個不為數字之前的字元字串轉換成為的數字,例如"12306str",将傳回12306,"123 06"将傳回123,而“str12306”将傳回0,超出int範圍将引發為定義的行為。
那麼就會有人想,如果我需要擷取譬如"12306str12580"這樣的字元串中的每一個數值字串的值呢,strtox可以做到。strtox提供了第二個參數,char** endptr,每次調用函數後,*endptr将會指向轉換後的數值的後一個字元,譬如說第一次調用strtol("12306str12580“, &endPtr, 10)後,endptr将會指向's',第二次調用後将會指向't',第三次指向'r',第四次指向最後\0,對于非小數類型,還提供了第三個參數,表示進制數,如16,則可以将"0xf"轉換為15,如2,則可以将"110"轉換為6。
二.算法
隻有兩個,快速排序函數和二分搜尋函數,由于使用起來較為繁瑣,一般會被STL中的sort和find函數代替。
void qsort(void* base, size_t num, size_t size, int (*comptr)(const void*, const void*) )
void* bsearch(const void* key,const void* base, size_t num, size_t size,int (*comptr)(const void*, const void* ) )
由于函數本身不知道傳進去的資料類型,是以需要指定數組元素size大小,函數也不知道數組長度,需要指定數組大小,提供比較器則是指定比較的規則,注意bsearch傳回的是void*,是以在使用時要注意進行顯示的轉換。
三.數學運算
1.絕對值
abs和labs,取絕對值,分别對應int型和long型
2.整除
div和ldiv,傳回值是結構體div_t、ldiv_t,
typedef struct { typedef struct {
int quot; long quot;
int rem; long rem;
} div_t; } ldiv_t;
quot代表整除的結果,rem代表餘數。
<math.h>/<cmath>
1.絕對值函數
abs與fabs,二者之間并沒有什麼明顯的差別,主要對浮點數進行操作,傳回值為float、double,與stdlib中的相混合可能會讓人比較糾結,但是一個強制類型轉換就可以解除選擇困難症的問題,部落客一般用fabs。
2.舍入
ceil,floor,round:ceil為向上取整,floor為向下取整,round傳回距離參數最近的整數。
3.乘方/開方
pow,sqrt:常用函數,不多解釋了。
C++篇:
<string>
終于到了c++的舞台了,被c中繁瑣的函數糾纏的欲生欲死?系加加是你的福音。
首先,談到string頭檔案就有必要談談string類本身了。
string類本身可以視為一種STL容器類,它擁有iterator,也擁有begin(),end(),push_back(),pop_back(),insert(),erase()等基本函數,是以可以某種意義上可以将string當作vector<char>來使用,algorithm中的算法也可以完美的應用在string類上。這些都是後話了,現在主要讨論string作為string所具有的獨特函數:
1.構造函數:
default (1)
string(); //預設構造函數,沒什麼可說的
copy (2)
string (const string& str); //通過另外一個string的複制構造函數,也沒有什麼好說的
substring (3)
string (const string& str, size_t pos, size_t len = npos); //通過另外一個string的某一部分,某種意義上相當于取字串
from c-string (4)
string (const char* s); //通過c風格字元串,是c-string到string的途徑
from sequence (5)
string (const char* s, size_t n); //通過c風格的字串建立
fill (6)
string (size_t n, char c); //用n個相同的字元建立
range (7)
template <class InputIterator> //通過疊代器建立
string (InputIterator first, InputIterator last);
2.析構函數
pass~
3.擷取大小
size()方法和length()方法,并無什麼差別,可能是為了與傳統的length和STL的size相容而特意弄出兩個來。
4.連接配接
+=重載或者append()方法
5.複制
=運算符重載
6.替換
replcae()方法,前兩個參數為位置 + 長度,這個格式在之前的c函數中也頻繁出現,後面的參數為字元串的各種表示方法以及取字串添加的數字。
7.擷取字元
[]運算符重載,或者at方法
8.查找
find()方法,參數是要查找的字元串/字元 + 查找起始位置,要查找的字元串為c-string還可以加上一個數字指明c-string的長度。
r_find()為反向查找。
*注意,這裡如果沒有找到傳回的是string::nopos。
9.比較
compare()方法,按照字典順序比較
10.截取字串
substr()方法,參數為起始位置+長度。
11.轉化為c-string
c_str()方法。
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
寫到這裡部落客有必要說以下,剛才發現string中其他函數全是c++11的,為了突顯針對“系系诶夫”的主題,部落客決定去除部落格c++11的内容,以免産生誤導作用,但
值得一提的是,c/c++/java等各個語言都在與時俱進,都在發展,而考試卻僅僅停留在98标準,實在讓人感到費解,新标準中加入了對原有标準的補充與修複,是值
的去學習的,也希望“系系诶夫”有一天能發揮預期的作用。寫了兩三個小時,後面的有些簡略,以後有空完善,如果有錯誤敬請指出。
休息會去了==下個部落格見。