分割字符串的函数——strtok、sscanf

目录

一、strtok

1、定义

2、函数原型

3、说明

5、strtok_s

6、strtok_r

二、sscanf

1、定义

2、函数原型

3、说明

4、基本使用

5、高级使用

一、strtok

1、定义

分解字符串为一组字符串。s为要分解的字符,delim为分隔符字符(如果传入字符串,则传入的字符串中每个字符均为分割符)。首次调用时,s指向要分解的字符串,之后再次调用要把s设成NULL。在头文件#include中。

2、函数原型

char *strtok(char s[], const char *delim);

3、说明

(1)当strtok()在参数s的字符串中发现参数delim中包含的分割字符时,则会将该字符改为\0 字符。在第一次调用时,strtok()必需给予参数s字符串,往后的调用则将参数s设置成NULL。每次调用成功则返回指向被分割出片段的指针。

(2)从s 开通的一个个被分割的串。当s中的字符查找到末尾时,分会NULL。如果查找不到delim中的字符时,返回当前strtok的字符串的指针。所有delim中还包含的字符都会被滤掉,并将被滤掉的地方设为一处分割点。(结合下图更能理解这段话的意思)

#include 
#include 

int main (int argc, char **argv)
{
    char        input[60]="RPI00001/2021.08.19  18:10/25.0056";
    char       *SN, *time, *temper;
    
    SN = strtok (input, "/");
    if (SN)
        printf ("SN = %s\n", SN);
        
    time = strtok(NULL, "/");
    if (time)
        printf ("time = %s\n", time);

    temper = strtok (NULL, "/");
    if (temper)
        printf ("temper = %s\n", temper);

    return 0;

}

输出结果为:SN = RPI00001  time = 2021.08.19  18:10  temper =  25.0056

 (3)需要注意的是,使用该函数进行字符串分割时,会破坏被分解字符串的完整,调用前和调用后的s已经不一样了。第一次分割之后,原字符串str是分割完成之后的第一个字符串,剩余的字符串存储在一个静态变量中,因此多线程同时访问该静态变量时,则会出现错误。

(4)strtok函数会破坏被分解字符串的完整,调用前和调用后的s已经不一样了。如果要保持原字符串的完整,可以使用strchr和sscanf的组合等。

5、strtok_s函数

strtok_s是windows下的一个分割字符串安全函数,函数声明如下:

char *strtok_s( char *strToken, const char *strDelimit, char **buf); 

这个函数将剩余的字符串存储在buf变量中,而不是静态变量中,从而保证了安全性。

6、strtok_r

strtok_s函数是linux下分割字符串的安全函数,函数声明如下:

char *strtok_r(char *str, const char *delim, char **saveptr);

该函数也会破坏带分解字符串的完整性,但是其将剩余的字符串保存在saveptr变量中,保证了安全性。如下例题:

#include   
#include   
#include   
  
int main(int argc, char **argv)
{  
    char         str[] = "ab/cd/ef";  
    char        *ptr;  
    char        *p;  

    printf ("before strtok_r: str=%s\n",str); 
    printf("begin strtok_r:\n")
 
    //char *strtok_r(char *str, const char *delim, char **saveptr); 注意函数里的第三个参数
    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;  
}

输出结果:
before strtok: str=ab/cd/ef  begin strtok_r: str=ab ptr=ab str=ab ptr=cd str=ab ptr=ef

二、sscanf

1、定义

sscanf通常被用来解析并转换字符串,其格式定义灵活多变,可以实现很强大的字符串解析功能。

2、函数原型

int sscanf(const char *str, const char *format, ...);

3、说明

sscanf函数包含在头文件 #include 中,上述函数 str 代表待解析的字符串,format 表示字符串格式描述,省略号表示其后是一序列数目不定的指针参数,用来存储解析后的数据。

4、基本使用

(1)整形数转换

int   year, month, day,converted;
 
converted = sscanf ("20191103", "%04d%02d%02d", &year, &month, &day);
printf ("converted=%d, year=%d, month=%d, day=%d/n", converted, year, month, day);

输出结果: converted=3, year=2019, month=11, day=03

其中 "%04d%02d%02d" 是用来解析字符串的格式,%表示格式转换的开始,d表示转换为一个整数,04作为d的修饰,表示这是一个长度为4位的位宽,不足4位时以0补齐。

(2)浮点数转换

int         converted;
double      longitude, latitude;

converted = sscanf("113.123456789 31.123456789", "%lf %lf", &longitude, &latitude);
printf("converted=%d, longitude=%.9lf, latitude=%lf/n", converted, longitude, latitude);

输出结果: converted=2, longitude=113.123456789, latitude=31.123457

浮点数的转换和整形数转换两者是差不多一个道理

5、高级使用

(1)数字 + 字符串

char   str[32] = "";

sscanf ("123456abcdedf", "%31[0-9]", str);
printf ("str=%s/n", str);

输出结果: str=123456 

上面的格式中,[0-9]表示这是一个仅包含0-9这几个字符的字符串,前面使用数字31修饰词表示这个字符串缓冲区的最大长度(这也是sscanf最为人诟病的地方,很容易出现缓冲区溢出错误,实际上sscanf是可以避免出现缓冲区溢出的,只要在书写任何字符串解析的格式时,注意加上其缓冲区尺寸的限制)。
 

char   str[32] = "";

sscanf ("123456abcdedf", "%31[0-9a-z]", str);
printf ("str=%s/n", str);

输出结果: str=123456abcdedf

在格式[]中增加了a-z的描述。

(2)使用 ^ 

char    str[32] = "";

sscanf ("123456abcdedf", "%31[^a-z]", str);
printf ("str=%s/n", str);

输出结果: str=123456

在[]中增加表示相反的意思,上面的[a-z]表示一个不包含任何a-z之间的字符串。

(3)使用 *

char      str[32] = "";
int       ret;

ret = sscanf ("123456abcdedf", "%*[0-9]%31[a-z]", str);
printf ("ret=%d, str=%s/n",ret, str);

输出结果: ret=1, str=abcdedf

加上*修饰表示一个被忽略的数据,同时也不需要为它准备空间存放解析结果。如上面的例子中,我们就只使用了str一个参数存放%31[a-z]的解析结果,而sscanf也只返回1,表示只解析了一个数据。

你可能感兴趣的:(C语言,c语言)