【C语言 | 字符串处理】sscanf 用法(星号*、集合%[]等)详细介绍、使用例子源码
😁博客主页😁:🚀https://blog.csdn.net/wkd_007🚀
🤑博客内容🤑:🍭嵌入式开发、Linux、C语言、C++、数据结构、音视频🍭
⏰发布时间⏰: 2025-06-25
本文未经允许,不得转发!!!
目录
- 🎄一、概述
- 🎄二、sscanf 函数的 str 参数介绍
- 🎄三、sscanf 函数的 format 参数详解
- ✨3.1、format 参数的 %type
- ✨3.2、format 参数带有星号[*]的 %type
- ✨3.3、format 参数带有宽度[width]的 %type
- ✨3.4、format 参数带有[{hh | h | l | L | ll}]的 %type
- ✨3.5、format 参数中的空白字符 ' ' | '\t' | '\n'
- ✨3.6、format 参数中的集合%[]
- 🎄四、例子源码
- 🎄五、总结
🎄一、概述
C语言处理字符串是比较麻烦的,前面有一篇文章介绍了 sscanf 的简单用法,文章链接:sscanf 详细介绍。但最近又遇到一些更复杂的,所以再写一篇博客记录一下笔记。
sscanf 的函数原型如下:
#include <stdio.h>int scanf(const char *format, ...);
int fscanf(FILE *stream, const char *format, ...);
int sscanf(const char *str, const char *format, ...);
// 返回值:成功则返回参数数目,失败则返回-1,错误原因存于errno中。
其实,sscanf 的使用之所以难懂,就是它的 format
参数比较难理解,本文就是从这个参数的一些常见格式入手,加上一些例子去理解。
🎄二、sscanf 函数的 str 参数介绍
sscanf 函数的 str 参数是其第一个参数,这是一个 const char *str
的字符串,是我们要处理的字符串。
关于这个str
参数,我们只需要知道 sscanf是按照 ' '、'\t'、'\n'
这几个分隔符将str
参数划分为多个字符串的,看下面例子:
// str 参数
char first_str[64] = {0,};
char second_str[64] = {0,};
char third_str[64] = {0,};
char fouth_str[64] = {0,};
sscanf("first_str second_str\tthird_str\nfouth_str", "%s%s%s%s", first_str,second_str,third_str,fouth_str);
printf("first_str=[%s],second_str=[%s],third_str=[%s],fouth_str=[%s]\n", first_str,second_str,third_str,fouth_str);// 清空所有字符串
memset(first_str,0,sizeof(first_str));
memset(second_str,0,sizeof(second_str));
memset(third_str,0,sizeof(third_str));
memset(fouth_str,0,sizeof(fouth_str));
printf("first_str=[%s],second_str=[%s],third_str=[%s],fouth_str=[%s]\n", first_str,second_str,third_str,fouth_str);// 只获取第2、第4字符串
sscanf("first_str second_str\tthird_str\nfouth_str", "%*s%s%*s%s", second_str,fouth_str);
printf("first_str=[%s],second_str=[%s],third_str=[%s],fouth_str=[%s]\n", first_str,second_str,third_str,fouth_str);
运行结果:
🎄三、sscanf 函数的 format 参数详解
sscanf 函数的 format 参数是第二个参数,它可以是一个或多个的如下格式:
{% [*] [width] [{hh | h | l | L | ll}] type | ' ' | '\t' | '\n' | 非%符号}
这里可以分成三类去理解:
{% [*] [width] [{hh | h | l | L | ll}] type
:这个都是属于%type
的类型的,其中的[*]、[width]、[{hh | h | l | L | ll}]
都是可选的;' ' | '\t' | '\n'
:这三个都是空白字符,会匹配到第一个参数的空白字符;非%符号
:最后一类是 非%符号 的字符。非符号字符中有一类特殊的,就是集合%[]
,会在3.6节介绍。
✨3.1、format 参数的 %type
这个小节介绍format 参数的 %type
类是怎么匹配字符串的。
这里的type
可以是有对应的取值的,常见的%type
有这些:%%, %d, %u, %f, %x, %c, %s
,分别匹配到百分号(%)、带符号十进制整数、无符号十进制整数、带符号浮点数、无符号的十六进制整数、字符、字符串。
下面看例子:
int int_type_d=0;
unsigned int int_type_u=0;
float float_type_f=0.0;
int int_type_x=0;
char char_type_c=0;
char str_type_s[64]={0,};
sscanf("123 456 3.14 0xff C str 1080863910568919039", "%d %u %f %x %c %s", &int_type_d,&int_type_u,&float_type_f,&int_type_x,&char_type_c,str_type_s);
printf("int_type_d=[%d],int_type_u=[%u],float_type_f=[%f],int_type_x=[%x],char_type_c=[%c],str_type_s=[%s]\n",int_type_d,int_type_u,float_type_f,int_type_x,char_type_c,str_type_s);
运行结果:
✨3.2、format 参数带有星号[*]的 %type
%type
类型在type前面有三个可选的前缀,如果在type
前加上[*]
,表示跳过这个匹配的数据。例如"%*s %s"
表示跳过第一个字符串,读取第二个字符串;
看例子:
// %*type
char str_type1[64] = {0,};
char str_type2[64] = {0,};
sscanf("123 456 3.14 0xff C str 1080863910568919039", "%*d %*u %*f %*x %s %s", str_type1, str_type2);
//sscanf("123 456 3.14 0xff C str 1080863910568919039", "%*s %*s %*s %*s %s %s", str_type1, str_type2);
printf("str_type1=[%s], str_type2=[%s]\n",str_type1, str_type2);
要处理的字符串是"123 456 3.14 0xff C str 1080863910568919039"
,使用的 format 是"%*d %*u %*f %*x %s %s"
,跳过前面4个匹配的字符串,从第5个开始读取。
需要注意,使用的 format 改为"%*s %*s %*s %*s %s %s"
也是一样的结果,因为sscanf会把要处理的字符串按空格分隔成多个子字符串。
运行结果:
✨3.3、format 参数带有宽度[width]的 %type
在type
前加上[width]
,表示匹配的宽度。如果与星号([*]
)一起使用时,星号需要在[width]
前面。例如:
- 处理字符串
"123"
时,只读取12
存放到一个整数里,可以这样写;sscanf("123", "%2d", &i);
- 处理字符串
"3.14"
时,只读取3.1
存放到一个浮点数里,可以这样写;sscanf("3.14", "%3f", &f);
- 处理字符串
"1080863910568919039"
时,想跳过前面11个数字,可以这样写;sscanf("1080863910568919039", "%*11s%s", str);
看了上面例子,你可以知道怎样使用带宽度的format
了,那下面看个复杂的例子,试试能否看懂 😜。
例子:
// %[width]type
int int_width = 0;
float float_width=0.0;
char str_width1[64] = {0,};
char str_width2[64] = {0,};
sscanf("123 456 3.14 0xff C str 1080863910568919039", "%2d%*d %*u %3f%*s %3s%*s %*s %*s %*11s%s", &int_width, &float_width, str_width1, str_width2);
printf("int_width=%d, float_width=%f, str_width1=[%s], str_width2=[%s]\n",int_width,float_width,str_width1, str_width2);
运行结果:
✨3.4、format 参数带有[{hh | h | l | L | ll}]的 %type
在type
前加上[{hh | h | l | L | ll}]
,表示后面对应参数的类型。
hh
:type必须是d, i, o, u, x, X, n
之一,表示其后对应的参数指向一个char
或unsigned char
类型的指针;h
:表示其后对应的参数指向一个short
或unsigned short
类型的指针;l
:表示其后对应的参数指向一个long
或unsigned long
类型的指针;L
:如果type是e、f、g
则其后对应的参数指向一个long double
类型的指针;如果type是d, i, o, u, x
则其后对应的参数指向一个long long
类型的指针;ll
:表示其后对应的参数指向一个long long
类型的指针;
注意:如果没按照[{hh | h | l | L | ll}]
在对应的参数给到对应的类型,编译是会有类似这样的警告,warning: format ‘%hhd’ expects argument of type ‘signed char *’, but argument 3 has type ‘short int *’
例子:
// %[{hh | h | l | L | ll}]type
char char_c = 0;
unsigned char uchar_c = 0;
short short_s = 0;
unsigned short ushort_s = 0;
long long_l = 0;
unsigned long ulong_l = 0;
long long Long_L = 0;
unsigned long long uLong_L = 0;
sscanf("127 255 123 321 456 654 789 987", "%hhd %hhu %hd %hu %ld %lu %Ld %Lu", &char_c, &uchar_c, &short_s, &ushort_s, &long_l, &ulong_l, &Long_L, &uLong_L);
printf("char_c=[%hhd], uchar_c=[%hhu], short_s=%hd ushort_s=%hu long_l=%ld ulong_l=%lu Long_L=%Ld uLong_L=%Lu\n",char_c, uchar_c, short_s, ushort_s, long_l, ulong_l, Long_L, uLong_L);
运行结果:
✨3.5、format 参数中的空白字符 ’ ’ | ‘\t’ | ‘\n’
前面介绍过,如果第一个参数有空白字符(' '、'\t'、'\n'
),sscanf是按照将str
参数划分为多个子字符串;而fromat
参数中的空白字符,无论是连续多少个,都是当成一个空格(' '
)来匹配的。
可以看看下面例子:
// ' ' | '\t' | '\n'
char blank_type[64] = {0,};
sscanf("1 \n2", "1\t%s", blank_type);
printf("blank_type=[%s]\n", blank_type);
sscanf("3 \t\t\t\n\n\n\n\t 4", "3\t\t\n \t\n\t%s", blank_type);
printf("blank_type=[%s]\n", blank_type);
printf("\n");
运行结果:
✨3.6、format 参数中的集合%[]
支持集合操作:
%[]
:只要是中括号内的字符都会匹配,例如:
%[abc ]
:表示只要是a
、b
、c
、空格(
%[a-z1-9\t]
:表示匹配a-z
之间的任意字符,并且也匹配1-9
之间的任意字符,还匹配\t
字符;%[^]
:只要是中括号内的字符都不会匹配
%[^abc ]
:表示只要不是a
、b
、c
、空格(
%[^a-z1-9\t]
:表示不匹配a-z
之间的任意字符,并且也不匹配1-9
之间的任意字符,还匹配\t
字符;
注意:这个集合操作也可以和星号[*
]一起使用,表示跳过匹配到的字符串。
看例子:
// %[]
char str_abc[64] = {0,};
char str_NBA[64] = {0,};
sscanf("aabbcc cba abc NBA", "%[abc ]", str_abc);
printf("str_abc=[%s]\n", str_abc);memset(str_abc, 0, sizeof(str_abc));
sscanf("aabbcc cba abc 13578 246810 NBA", "%[a-z1-9 ]0 %[A-N]", str_abc, str_NBA);
printf("str_abc=[%s], str_NBA=[%s]\n", str_abc, str_NBA);
printf("\n");memset(str_NBA, 0, sizeof(str_NBA));
sscanf("aabbcc cba abc \t13578 246810 NBA", "%*[a-z0-9 \t] %[A-N]", str_NBA);
printf("str_NBA=[%s]\n", str_NBA);
printf("\n");// %[^]
memset(str_NBA, 0, sizeof(str_NBA));
sscanf("NBA 246810 13578 aabbcc cba abc", "%[^abc ]", str_NBA);// 只要不是abc
printf("str_NBA=[%s]\n", str_NBA);memset(str_NBA, 0, sizeof(str_NBA));
sscanf("NBA 246810 13578 aabbcc cba abc", "%[^abc]", str_NBA);// 只要不是abc
printf("str_NBA=[%s]\n", str_NBA);memset(str_NBA, 0, sizeof(str_NBA));
sscanf("NBA 246810 13578 aabbcc cba abc", "%[^a-z0-9\t]", str_NBA);
printf("str_NBA=[%s]\n", str_NBA);
运行结果:
🎄四、例子源码
/*** @file sscanf_sample.c* @author https://blog.csdn.net/wkd_007* @brief * @version 0.1* @date 2025-06-30* * @copyright Copyright (c) 2025* gcc sscanf_sample.c */
#include <stdio.h>
#include <string.h>int main()
{// str 参数char first_str[64] = {0,};char second_str[64] = {0,};char third_str[64] = {0,};char fouth_str[64] = {0,};sscanf("first_str second_str\tthird_str\nfouth_str", "%s%s%s%s", first_str,second_str,third_str,fouth_str);printf("first_str=[%s],second_str=[%s],third_str=[%s],fouth_str=[%s]\n", first_str,second_str,third_str,fouth_str);// 清空所有字符串memset(first_str,0,sizeof(first_str));memset(second_str,0,sizeof(second_str));memset(third_str,0,sizeof(third_str));memset(fouth_str,0,sizeof(fouth_str));printf("first_str=[%s],second_str=[%s],third_str=[%s],fouth_str=[%s]\n", first_str,second_str,third_str,fouth_str);// 只获取第2、第4字符串sscanf("first_str second_str\tthird_str\nfouth_str", "%*s%s%*s%s", second_str,fouth_str);printf("first_str=[%s],second_str=[%s],third_str=[%s],fouth_str=[%s]\n", first_str,second_str,third_str,fouth_str);printf("\n");//--------------------------// %typeint int_type_d=0;unsigned int int_type_u=0;float float_type_f=0.0;int int_type_x=0;char char_type_c=0;char str_type_s[64]={0,};sscanf("123 456 3.14 0xff C str 1080863910568919039", "%d %u %f %x %c %s", &int_type_d,&int_type_u,&float_type_f,&int_type_x,&char_type_c,str_type_s);printf("int_type_d=[%d],int_type_u=[%u],float_type_f=[%f],int_type_x=[%x],char_type_c=[%c],str_type_s=[%s]\n",int_type_d,int_type_u,float_type_f,int_type_x,char_type_c,str_type_s);printf("\n");// %[*]typechar str_type1[64] = {0,};char str_type2[64] = {0,};sscanf("123 456 3.14 0xff C str 1080863910568919039", "%*d %*u %*f %*x %s %s", str_type1, str_type2);// 跳过第2、3、4个字符串//sscanf("123 456 3.14 0xff C str 1080863910568919039", "%*s %*s %*s %*s %s %s", str_type1, str_type2);// 这个也可以printf("str_type1=[%s], str_type2=[%s]\n",str_type1, str_type2);printf("\n");// %[width]typeint int_width = 0;float float_width=0.0;char str_width1[64] = {0,};char str_width2[64] = {0,};// %2d%*d,表示读取123 的 12,跳过3// %3f%*s,表示读取3.14 的 31.2,提过4// %*11s%s,表示跳过 1080863910568919039 前11个字符,再开始匹配sscanf("123 456 3.14 0xff C str 1080863910568919039", "%2d%*d %*u %3f%*s %3s%*s %*s %*s %*11s%s", &int_width, &float_width, str_width1, str_width2);printf("int_width=%d, float_width=%f, str_width1=[%s], str_width2=[%s]\n",int_width,float_width,str_width1, str_width2);printf("\n");// %[{hh | h | l | L | ll}]typechar char_c = 0;unsigned char uchar_c = 0;short short_s = 0;unsigned short ushort_s = 0;long long_l = 0;unsigned long ulong_l = 0;long long Long_L = 0;unsigned long long uLong_L = 0;sscanf("127 255 123 321 456 654 789 987", "%hhd %hhu %hd %hu %ld %lu %Ld %Lu", &char_c, &uchar_c, &short_s, &ushort_s, &long_l, &ulong_l, &Long_L, &uLong_L);printf("char_c=[%hhd], uchar_c=[%hhu], short_s=%hd ushort_s=%hu long_l=%ld ulong_l=%lu Long_L=%Ld uLong_L=%Lu\n",char_c, uchar_c, short_s, ushort_s, long_l, ulong_l, Long_L, uLong_L);printf("\n");// ' ' | '\t' | '\n'char blank_type[64] = {0,};sscanf("1 \n2", "1\t%s", blank_type);// str参数,format参数中的空白字符都当成空格来处理printf("blank_type=[%s]\n", blank_type);sscanf("3 \t\t\t\n\n\n\n\t 4", "3\t\t\n \t\n\t%s", blank_type);printf("blank_type=[%s]\n", blank_type);printf("\n");// %[]char str_abc[64] = {0,};char str_NBA[64] = {0,};sscanf("aabbcc cba abc NBA", "%[abc ]", str_abc);// 从str参数第一个字符开始扫描,只匹配 a,b,c,' ' 4个字符printf("str_abc=[%s]\n", str_abc);memset(str_abc, 0, sizeof(str_abc));sscanf("aabbcc cba abc 13578 246810 NBA", "%[a-z1-9 ]0 %[A-N]", str_abc, str_NBA);printf("str_abc=[%s], str_NBA=[%s]\n", str_abc, str_NBA);memset(str_NBA, 0, sizeof(str_NBA));sscanf("aabbcc cba abc \t13578 246810 NBA", "%*[a-z0-9 \t] %[A-N]", str_NBA);printf("str_NBA=[%s]\n", str_NBA);printf("\n");// %[^]memset(str_NBA, 0, sizeof(str_NBA));sscanf("NBA 246810 13578 aabbcc cba abc", "%[^abc ]", str_NBA);// 从str参数第一个字符开始扫描,直到 a,b,c,' ' 4个字符之一停止printf("str_NBA=[%s]\n", str_NBA);memset(str_NBA, 0, sizeof(str_NBA));sscanf("NBA 246810 13578 aabbcc cba abc", "%[^abc]", str_NBA);// 从str参数第一个字符开始扫描,直到 a,b,c 3个字符之一停止printf("str_NBA=[%s]\n", str_NBA);memset(str_NBA, 0, sizeof(str_NBA));sscanf("NBA 246810 13578 aabbcc cba abc", "%[^a-z0-9\t]", str_NBA);printf("str_NBA=[%s]\n", str_NBA);printf("\n");// 实用例子char buf[64] = {0,};// 1.获取到指定字符为止的字符串memset(buf, 0, sizeof(buf));sscanf("RTSP/1.0 200 OK\r\n", "%[^\r]", buf);printf("buf=[%s]\n", buf);// 2.获取包含指定字符集的字符串,这里获取IP地址memset(buf, 0, sizeof(buf));sscanf("192.168.2.183:8554\r\n", "%[0-9.]", buf);printf("buf=[%s]\n", buf);// 3.从字符串中截取一段字符串,这里截取 // 之后,空格之前 的字符串。memset(buf, 0, sizeof(buf));sscanf("OPTIONS rtsp://192.168.2.183:8554 RTSP/1.0\r\n", "%*s %*[^/]// %[^ ]", buf);printf("buf=[%s]\n", buf);// 4.获取mac地址int mac[6]={0,};sscanf("00:0b:ce:19:09:06", "%2x:%2x:%2x:%2x:%2x:%2x", &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]);printf("%02x:%02x:%02x:%02x:%02x:%02x\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);printf("\n");return 0;
}
运行结果:
🎄五、总结
本文介绍了 sscanf 用法 的详细用法, 结合例子学习,一定有所收益。
如果文章有帮助的话,点赞👍、收藏⭐,支持一波,谢谢 😁😁😁
参考:
C语言函数sscanf()的用法:https://www.cnblogs.com/lyq105/archive/2009/11/28/1612677.html
关于sscanf函数的使用:https://www.jianshu.com/p/67e50d4d4872