strtok函數原型:strtok(OriginalString,Seps)
參數:
OriginalString代表等待分割的字符串(char*類型)
Seps代表的也是一個字符串(const char*類型),裏面防止什麼符號是分隔符。eg: Seps=" ,!.n" 表示空格,逗號,感嘆號,n都是分割當前字符串的分隔符
運行後產生兩個指針:(詳情見下面程序註釋)
第一個指針pointer_a用來指向函數返回的字符串,這個字符串是被原字符串OriginalString被seps中的字符截斷後的第一個字符串。
第二個指針pointer_b用來指向OriginalString中,匹配截斷字串seps的位置。
注意:
strtok會破壞被分割的字符串。eg: 被分割的是str數組,那麼分割完成後,str指向的只是第一個被分割的所有子串中的第一個子串
strtok函數實例:
//這個代碼寫的繁瑣了一點,主要是爲了理解strtok的運行原理,後面第二份代碼進行了簡化
#include <stdio.h>
#include <string.h> //必須包含此頭文件
int main()
{
char *p;
char str[100]="You are so beautiful a girl.I love you!";
p = strtok(str," ,.!"); // 此時得到的 p指向字符串:"You",第一個符合標準的分隔符會被替換爲
//空指針(NULL),所以此時NULL指針指向後面
//的字符串:"are so beautiful a girl.I love you!"
printf("len:%d str:%s\n",strlen(p),p);
do{
p = strtok(NULL, " ,.!"); // NULL 即爲上面返回的指針,指向
//字符串:"are so beautiful a girl.I love you!"。
if(p){
printf("len:%d str:%s\n",strlen(p),p);
//我爲什麼要寫strlen(p)呢?是爲了表明,我們可以把
//這個p當做一個字符串數組來對待
}
}while(p);
return 0;
}
程序運行結果:
strtok函數中的NULL問題:
上述已經講解,函數運行後會得到兩個參數。以上述程序第一次運行strtok爲例:
函數的返回值pointer_a爲一個指向”You”的指針。此時,對於pointer_b,我更傾向於它指向了剩下的字符串,即"are so beautiful a girl.I love you!"
只要把strtok()的第一個參數設置爲NULL,就可以直接對pointer_b指向的字符串開始進行新一輪的查找匹配了
因此使用方法是:首次調用時,s必須指向要分解的字符串,隨後調用要把s設成NULL。
strtok在s中查找包含在Seps中的字符並用NULL(’\0’)來替換,直到找遍整個字符串。(這樣是不是有種感覺,字符串在內存中的位置並沒有改變,只是把那些分隔符置爲字符串的結束標誌'\0',並且得到了每一個子串的起始位置的指針)
關於如何保存分割後字符串的問題:
上面的程序確實是對其做了分割,但第一時間就打印了。而我們更多的時候是希望可以將其保存下來,應該怎麼做。
首先,我們不知道分割後會產生多少個子串,所以我們需要一個動態容器來添加。(python大法好,split和list是真方便,忍不住吐槽)但C++有vector。
所以我設置了一個 vector<char*> s; 來動態添加保存每一個子串
#include <stdio.h>
#include <string.h> //必須包含此頭文件
#include <vector>
using namespace std;
void split(vector<char*> *s,char *str,const char *c);
using namespace std;
int main()
{
vector<char*> s;
char str[100]="You are so beautiful a girl.I love you!";
split(&s,str," ,.!");
printf("分割後子串的個數:%d\n",s.size());
for(int i=0; i<s.size(); i++){
printf("%s\n",s[i]);
}
return 0;
}
void split(vector<char*> *s,char *str,const char *c)
{
char *p;
p = strtok(str, c);
while(p){
(*s).push_back(p);
p = strtok(NULL, c);
}
}