1. 程式人生 > >字串切割函式strtok、strtok_s、strtok_r的區別

字串切割函式strtok、strtok_s、strtok_r的區別

strtok函式

標頭檔案#include <string.h>
函式原型char * strtok (char *str, const char * delimiters);
引數str:待分割的字串(c-string);delimiters:分割符字串。
該函式用來將字串分割成一個個片段。引數str指向欲分割的字串,引數delimiters則為分割字串中包含的所有字元。當strtok()在引數s的字串中發現引數delimiters中包涵的分割字元時,則會將該字元改為\0 字元。在第一次呼叫時,strtok()必需給予引數s字串,往後的呼叫則將引數s設定成NULL。每次呼叫成功則返回指向被分割出片段的指標。
需要注意的是

,使用該函式進行字串分割時,會破壞被分解字串的完整,呼叫前和呼叫後的s已經不一樣了。第一次分割之後,原字串str是分割完成之後的第一個字串,剩餘的字串儲存在一個靜態變數中,因此多執行緒同時訪問該靜態變數時,則會出現錯誤。

程式碼舉例

例1:將字串通過’,’分割開,列印子串並判斷原字串(被分割的字串)是否發生改變

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

int main()
{
    char str[]="ab,cd,ef";
    char *ptr;
    printf("before strtok:  str=%s
\n"
,str); printf("begin:\n"); ptr = strtok(str, ","); while(ptr != NULL){ printf("str=%s\n",str); printf("ptr=%s\n",ptr); ptr = strtok(NULL, ","); } return 0; }

輸出結果
before strtok: str=ab,cd,ef
begin:
str=ab
ptr=ab
str=ab
ptr=cd
str=ab
ptr=ef

例2:MSDN例子,字串中含有多個分隔符

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

char string[] = "A string\tof ,,tokens\nand some  more tokens";//被分割的字串
char seps[]   = " ,\t\n";//分隔符集
char *token;//用指標作為標記

void main( void )
{
   printf( "%s\n\nTokens:\n", string );
   /* 建立字串並獲取第一個標記(指向子串的首地址) */
   token = strtok( string, seps );
   while( token != NULL )
   {
      /* 在“string”中有標記*/
      printf( " %s\n", token );
      /* 得到下一個標記*/
      token = strtok( NULL, seps );
   }
}

輸出結果
A string of ,,tokens
and some more tokens

Tokens:
A
string
of
tokens
and
some
more
tokens

結論:strtok在切割字串的過程,實際上就是將被分割的字串的分隔字元替換為‘\0’ 並且返回標記字串的首地址,直到返回NULL結束。

stotok函式的實現原理

函式程式碼

#include<stdio.h>
#include<string.h>
//根據函式原型實現strtok()函式
char* myStrtok_origin(char* str_arr,const char* delimiters,char** temp_str)
{
    //定義一個指標來指向待分解串
    char* b_temp;
    /*
    * 1、判斷引數str_arr是否為空,如果是NULL就以傳遞進來的temp_str作為起始位置;
    * 若不是NULL,則以str為起始位置開始切分。
    */
    if(str_arr == NULL)
    {
        str_arr =*temp_str;
    }
    //2、跳過待分解字串
    //掃描delimiters字元開始的所有分解符
    str_arr += strspn(str_arr, delimiters);//尋找第一個子串,返回子串的長度
    //3、判斷當前待分解的位置是否為'\0',若是則返回NULL,否則繼續
    if(*str_arr =='\0')
    {
        return NULL;
    }
    /*
    * 4、儲存當前的待分解串的指標b_temp,呼叫strpbrk()在b_temp中找分解符,
    * 如果找不到,則將temp_str賦值為待分解字串末尾部'\0'的位置,
    * b_temp沒有發生變化;若找到則將分解符所在位置賦值為'\0',
    * b_temp相當於被截斷了,temp_str指向分解符的下一位置。
    */
    b_temp = str_arr;
    str_arr = strpbrk(str_arr, delimiters);
    if(str_arr == NULL)
    {
        *temp_str = strchr(b_temp,'\0');
    }
    else
    {
        *str_arr ='\0';
        *temp_str = str_arr +1;
    }
    //5、函式最後部分無論找沒找到分解符,都將b_temp返回。
    return b_temp;
}
//使用myStrtok來簡化myStrtok_origin函式
char* myStrtok(char* str_arr,const char* delimiters)
{
    static char* last;//靜態變數
    return myStrtok_origin(str_arr, delimiters,&last);
}
int main(void)
{
    char buf[]="[email protected]@[email protected]@heima";
    //1、使用myStrtok_origin()函式
    char*temp_str = NULL;
    char*str = myStrtok_origin(buf,"@",&temp_str);
    while(str)
    {
        printf("%s ",str);
        str = myStrtok_origin(NULL,"@",&temp_str);
    }
    //2、使用myStrtok()函式
    char*str1 = myStrtok(buf,"@");
    while(str1)
    {
        printf("%s ",str1);
        str1 = myStrtok(NULL,"@");
    }
    return 0;
}

輸出結果:
hello boy this is heima hello

strtok_s函式

strtok_s是Windows下的一個分割字串安全函式,其函式原型
char *strtok_s( char *strToken, const char *strDelimit, char **buf);
數將剩餘的字串儲存在buf變數中,而不是靜態變數中,從而保證了安全性。

程式碼示例

例1:使用strtok_s函式分隔字串

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

int main()
{
    char str[]="ab,cd,ef";

    char *ptr;

    printf("before strtok:  str=%s\n",str);
    printf("begin:\n");

    char *pTmp = NULL;
    ptr = strtok_s(str,",",&pTmp);

    while(ptr != NULL)
    {
        printf("str=%s\n",str);
        printf("ptr=%s\n",ptr);
        ptr = strtok_s(NULL,",",&pTmp);
    }
    return 0;
}

輸出結果
before strtok: str=ab,cd,ef
begin:
str=ab
ptr=ab
str=ab
ptr=cd
str=ab
ptr=ef

strtok_r函式

strtok_s函式是linux下分割字串的安全函式,函式宣告如下:
char *strtok_r(char *str, const char *delim, char **saveptr);
(1)該函式也會破壞帶分解字串的完整性,但是其將剩餘的字串儲存在saveptr變數中,保證了安全性。
(2)在函式strtok中剩餘字串是儲存在一個靜態變數中,因此,多執行緒在使用該靜態變數時引起衝突;而strtok_r則使用使用者傳入的指標為每個使用者saveptr重新申請變數,因而可以保證執行緒安全。
(3)strtok_r函式是strtok函式的可重入版本,也即執行緒安全版本。str為要分解的字串,delim為分隔符字串。char *saveptr引數是一個指向char 的指標變數,用來在strtok_r內部儲存切分時的上下文,以應對連續呼叫分解相同源字串。

程式碼示例

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

int main()
{
    char str[]="ab,cd,ef";
    char *ptr;
    char *p;
    printf("before strtok:  str=%s\n",str);
    printf("begin:\n");
    ptr = strtok_r(str, ",", &p);
    while(ptr != NULL){
        printf("str=%s\n",str);
        printf("ptr=%s\n",ptr);
        ptr = strtok_r(NULL, ",", &p);
    }
    return 0;
}

輸出結果
strtok_r.c

拓展:
可重入函式:
  (1)重入即表示重複進入,首先它意味著這個函式可以被中斷,其次意味著它除了使用自己棧上的變數以外不依賴於任何環境(包括static),這樣的函式就是purecode(純程式碼)可重入,可以允許有該函式的多個副本在執行,由於它們使用的是分離的棧,所以不會互相干擾。如果確實需要訪問全域性變數(包括static),一定要注意實施互斥手段。可重入函式在並行執行環境中非常重要,但是一般要為訪問全域性變數付出一些效能代價。
   (2)指一個可以被多個任務呼叫的函式(過程),任務在呼叫時不必擔心資料是否會出錯。
不可重入函式:
  如果函式介面的程式碼實現中在塊內定義和使用了static儲存型別的變數,這種函式將是不可重入函式。它在實時系統中是不安全函式。
  
參考:http://blog.csdn.net/jiangqin115/article/details/48545895
http://www.cnblogs.com/Bob-tong/p/6610806.html
http://blog.csdn.net/lavorange/article/details/47134121

相關推薦

字串切割函式strtokstrtok_sstrtok_r區別

strtok函式 標頭檔案:#include <string.h> 函式原型:char * strtok (char *str, const char * delimiters); 引數:str:待分割的字串(c-string);delimit

strtokstrtok_sstrtok_r 字串分割函式

1、strtok函式 函式原型:char * strtok (char *str, const char * delimiters); 引數:str,待分割的字串(c-string);delimiters,分割符字串。 該函式用來將字串分割成一個個片段。引數str指

C字串——庫函式系列(strlenstrcatstrcpystrcmp)

一定義: 字串:字串是由零個或者多個字元組成的有限序列; 子串:字串中任意個連續的字元組成的子序列,並規定空串是任意串的子串,字串本身也是子串之一;“abcdefg”,”abc“就是其子串,但是“ade”不屬於子串範圍。 子序列:不要求字元連續,但是其順序與其在主串中相一致;上例中,“abc

JS陣列的slice()方法傳負數和字串操作函式中的slice()substr()substring()

定義和用法 slice() 方法可從已有的陣列中返回選定的元素。 語法 arrayObject.slice(start,end) 引數 描述 start 必需。規定從何處開始選取。如果是負數,那麼它規定從陣列尾部開始算起的位置。也就是說,-1 指最

C語言字串擷取函式strtokstrtok_r

       在看原始碼的時候需要將一段並排的IPs轉化成為一系列的IP,將"10.0.0.1;10.0.0.2;10.0.0.3;10.0.0.4;10.0.0.5"轉換成為單獨的"10.0.0.1

c語言的split字串分割函式strtok的使用

c語言也有類似其他語言的split字串分割函式,就是strtok 標頭檔案:#include <string.h>定義函式:char * strtok(char *s, const char *delim);函式說明:strtok()用來將字串分割成一個個片段。

c,c++中字串處理函式strtok,strstr,strchr,strsub

函式原型:char *strtok(char *s, char *delim); 函式功能:把字串s按照字串delim進行分割,然後返回分割的結果。 函式使用說: 1.strtok函式的實質上的處理是,strtok在s中查詢包含在delim中的字元並用NULL(’/0′)來替換,直到找遍整個字串。這句

strtokstrtok_r 字串分割函式

1.一個應用例項 typedef struct person{ char name[25]; char sex[10]; char age[4]; }Person; 需從字串 char buffer[INFO_MAX_

stof()atoi()atol()strtod()strtol()strtoul() 共6個可以將字串轉換為數字的函式

標頭檔案:#include <stdlib.h> atoi() 函式用來將字串轉換成整數(int),其原型為: int atoi (const char * str); 【函式說明】atoi() 函式會掃描引數 str 字串,跳過前面的空白字元(例如空格,tab縮排等,可以通過 

2018.9.10學習內建函式切片字串拼接等

今日練習: # 題目1:從網路上使用爬蟲程式得到下面字串: # zhangsan-18-175-70-python5;lisi-20-170-80-python5;wangwu-28-165-60-python3;zhaoliu-18-175-70-python5;xi

【c語言】利用指標模式實現字串函式(strlenstrcatstrstrstrcpystrcmpmemcpymemove)

模擬實現strlen int my_strlen(const char *p) { assert(p != NULL); char *s = p; while (*p) { p++; } r

PHP處理字串常用函式

字串操作 一、字串的連線 “. ”可以連線兩個及以上的字元為一個字串 二、字串的操作  1.trim()去除字串首尾空格和特殊字元,並返回處理後字串。  string trim(string str[,string charlist]);  必選引數str要操作的字

Mysql內建函式字串日期數子)

mysql操作函式 數值操作ABS(N):返回絕對值CEIL(N):返回不小於引數的最小整數值CEILING(N):返回不小於引數的最小整數值CONV(N,FROM_BASE,TO_BASE):數字的進位制轉換EXP(N):返回e的n次方FLOOR(N) :返回不大於引數的

JS 進階(9) ECMAScript6 基礎入門:變數函式解構賦值陣列字串面向物件jsonpromise

一、ES6是啥 ECMAScript 和 JavaScrip的關係 簡單的說ECMA 是一個標準,任何語言都可以去實現這個標準,但目前為止只有javascript 實現了。所以也就預設認為ECMAScript就是javascript。 ECMAScript

C語言字串函式總結:模擬實現常用的字串函式(strlenstrcpystrcmp........)

總結:模擬實現常用的字串類函式(strlen、strcpy、strcmp……..) 1. strlen 2. strcpy 3. strcat 4. strstr 5. strchr 6. strcmp 7. memcpy 8. m

nginx切割字串泛域名kong轉發代理

因為業務需要多租戶,因此使用了nginx的正則方便地拿到租戶的編號。 業務請求要轉發到kong。 server { listen 80 default_ser

python中字串:宣告編碼函式格式化

字串的宣告有三種方式:單引號、雙引號和三引號(包括三個單引號或三個雙引號)。例如: ? 1 2 3 4 5 6 7 8 9 10 11 12 >>> str1= 'hello world'  >>> str2= "hello

python常用的幾種字串替換函式stripreplacesub

#!/usr/bin/env python # coding:utf-8 import re ''' 功能:對常見的幾種字串處理函式進行測試使用學習 Author:沂水寒城 ''' def str_test(): str_list=['We are family!!!', '00 11 2

python字串內建函式操作例項(cmpstrenumeratezip等)

#coding=utf8 ''' cmp(str1,str2):根據字串的ASCII碼值進比較,返回一個整數。 如果返回值大於零,str1大於str2; 如果返回值小於零,str1小於str2; 如果返回值等於零,str1等於str2; len(object):返回序列的

C++中讀取字元字串函式

iostream流:cin、cin.get()、cin.getline()       string流:getline() cin:配合輸入操作符">>"使用。而操作符">>"預設會跳過空格、製表符、tab、回車符等分隔符,實際上這