scanf特殊结束符

scanf读入非空格分隔的字符串和整形的混合类型问题
今天在网上看到一个网友提问这样一个问题:
C语言输入字符串和数字时如何用逗号隔开,
比如输入zhang1,90
要求把zhang1赋给一个字符数组
把90付给一个INT的变量。
刚开始只想到如果用scanf("%s,%d",name,&age);  这种方式肯定会出现问题,输入的数据肯定都会被赋值给字符串,整形数据肯定会是个随机数,因此给网友回答时说不要将字符串写在前面,来避免该问题。
后来网友说肯定能实现,因此在网上查了一些资料,终于将该问题解决,如下:
scanf("%[^,],%d",name,&age);
这是scanf的特殊用法,留在这里,提醒自己很多东西还要不断的去学习。
顺便将网上找到的文章贴在这里,以巩固相关知识。
———————————————————————————————————————————
%[ ] 的用法:%[ ]表示要读入一个字符集合, 如果[ 后面第一个字符是”^”,则表示反意思。
[ ]内的字符串可以是1或更多字符组成。空字符集(%[])是违反规定的,可
导致不可预知的结果。%[^]也是违反规定的。
%[a-z] 读取在 a-z 之间的字符串,如果不在此之前则停止,如
char s[]="hello, my friend” ; // 注意: ,逗号在不 a-z之间
sscanf( s, “%[a-z]”, string ) ; // string=hello
%[^a-z]读取不在 a-z 之间的字符串,如果碰到a-z之间的字符则停止,如
char s[]="HELLOkitty” ; // 注意: ,逗号在不 a-z之间
sscanf( s, “%[^a-z]”, string ) ; // string=HELLO
%*[^=] 前面带* 号表示不保存变量。跳过符合条件的字符串。
char s[]="notepad=1.0.0.1001" ;
char szfilename [32] = "" ;
int i = sscanf( s, "%*[^=]", szfilename ) ; // szfilename=NULL,因为没保存
int i = sscanf( s, "%*[^=]=%s", szfilename ) ; // szfilename=1.0.0.1001
%40c 读取40个字符
The run-time
library does not automatically append a null terminator
to the string, nor does reading 40 characters
automatically terminate the scanf() function. Because the
library uses buffered input, you must press the ENTER key
to terminate the string scan. If you press the ENTER before
the scanf() reads 40 characters, it is displayed normally,
and the library continues to prompt for additional input
until it reads 40 characters
%[^=] 读取字符串直到碰到’=’号,’^’后面可以带更多字符,如:
char s[]="notepad=1.0.0.1001" ;
char szfilename [32] = "" ;
int i = sscanf( s, "%[^=]", szfilename ) ; // szfilename=notepad 
如果参数格式是:%[^=:] ,那么也可以从 notepad:1.0.0.1001读取notepad
使用例子:
char s[]="notepad=1.0.0.1001" ;
char szname [32] = "" ;
char szver [32] = “” ;
sscanf( s, "%[^=]=%s", szname , szver ) ; // szname=notepad, szver=1.0.0.1001
总结:%[]有很大的功能,但是并不是很常用到,主要因为:
1、许多系统的 scanf 函数都有漏洞. (典型的就是 TC 在输入浮点型时有时会出错). 
2、用法复杂, 容易出错. 
3、编译器作语法分析时会很困难, 从而影响目标代码的质量和执行效率.
个人觉得第3点最致命,越复杂的功能往往执行效率越低下。而一些简单的字符串分析我们可以自已处理。
————————————————————————————————————————————————————
一、scanf()函数的一般格式为:scanf("格式字符串",输入项首地址表)
scanf的格式控制的一般形式为:%[*][宽度][F|N][h|l]类型字符 
[]中的控制字符为可选项 
"*"表示该输入项读入后不赋予任何变量,即跳过该输入值。这在减小内存开支上面还是有一点用处的,不需要的字符直接跳过,免得申请没用的变量空间 
"宽度"表示输入读入字符的长度,对于整型表示截取相应宽度的数字赋给后面列表中的相应变量;对于字符型表示读入相应长度的字符后把第一个字符赋给相应的变量,其余的自动舍弃。
例如scanf("%2d%3d",&a, &b);如果输入为12345则将12赋给a,将45赋给b;scanf("%2c%3c",&a, &b);如果输入为12345则将‘1‘赋给a,将‘3‘赋给b 
F 、N、h、l分别表示远指针、近指针、短整和长整型,
对于_int64相应的控制字符为ll或I64 "类型字符"为 d -- 输入十进制整数 、o -- 输入八进制整数 、x -- 输入十六进制整数 、u -- 输入无符号十进制整数 f或e -- 输入实型数(用小数形式或指数形式) 、c -- 输入单个字符 、s -- 输入字符串
二、对于输入字符串还有一些比较有用的控制: 例如经常需要读入一行字符串,而这串字符里面可能有空格、制表符等空白字符,如果直接用%s是不可以的,于是有些人就想到用gets(),当然这也是一种选择,但是懂C的人基本上都知道gets()是一个很危险的函数,而且很难控制,特别是与scanf()交替使用时前者的劣势更是一览无余,所以gets()一般是不推荐用的,其实用%[^\n]就可以很好的解决这个问题了, ^表示"",即读入其后面的字符就结束读入。这样想读入一行字符串直接用scanf("%[^\n]%*c",str);就可以了, %*c的作用是读入\n,否则后面读入的将一直是\n。所有对%s起作用的控制都可以用%[], 比如%[0-9]表示只读入‘0‘到‘9‘之间的字符,%[a-zA-Z]表示只读入字母, ‘-‘是范围连接符,当然也可以直接列出你需要读入的字符,上面读字母之所以用范围连接符是因为要输入52个字符太麻烦了,如果你只需要读"abc"里面的字符就可以用%[abc] (或者%[cab]、%[acb]、%[a-c]、%[c-a].....), 如果想读入某个范围之外的字符串就在前面加一个‘^‘,如:%[^a-z]就表示读入小写字母之外的字符上面
这些用法其实可以有很多推广用法的,比如说你要处理下面的字符串 23 44r f30 88888,3245;34:123. 让你输出里面所有的数字,就可以用下面的代码: 
bool skip(){ scanf("%*[^0-9]"); return true; } 
int main(){
int n; 
while (skip() && scanf("%d", &n)!=EOF) printf("%d\n", n); 
return 0; 
}

 

转载于:https://www.cnblogs.com/huashiyiqike/archive/2013/01/23/2873480.html

你可能感兴趣的:(c/c++)