最近在写一个测试的小程序,由于用到了sscanf函数对字符串进行标准读入,而sscanf在很多方面都与scanf比较相像,于是对scanf进行了一番测试,遇到了一系列基础性的问题,恶补基础的同时也体现了自己的薄弱。

话不多说,直接附上问题吧。

问题描述

#include<stdio.h>
#include<string.h> int main()
{
while(1)
{
char str[256]={0};
int a=0;
char b='\0';
printf("please input the num:\n");
scanf("%[^,],%[^,],%d",str,&b,&a);
printf("input is str: %s b: %c a: %d And str length is %u, the first character is %u\n",str,b,a,strlen(str),str[0]);
//gets(str);
}
return 0;
}

在这段代码里,如果我初始输入"a,a,0",输出正确。但输入",,0"的话,接下来会自动不需要输入然后循环着不断的输出,想问一下这个是什么原因。还有一个是我将代码改成了如下:

#include<stdio.h>
#include<string.h> int main()
{
while(1)
{
char str[256]={0};
int a=0;
char b='\0';
printf("please input the num:\n");
scanf("%*[\n\r\t]%[^,],%[^,],%d",str,&b,&a);
printf("input is str: %s b: %c a: %d And str length is %u, the first character is %u\n",str,b,a,strlen(str),str[0]);
//gets(str);
}
return 0;
}

本来目的是过滤输入的回车,其中%*是过滤满足条件的字符,但是如果直接输入"a,a,0",也会出现不需要输入然后不断地循环输出的现象。

问题解答

scanf里面的任何%都至少要匹配1个字节,所以连续两个逗号是匹配不出任何东西的。注意这里,哪怕是%*...都是只要要匹配一个字符的,匹配不了的就是失败。而死循环的原因,是因为流里面一个字节都没有被接受,所以每次循环面对一摸一样的流。scanf每次都失败。

示例:

 #include<stdio.h>
#include<string.h> int main()
{
while()
{
char str[]={};
int a=-;
char b='\0';
char test[]={};
printf("please input the num:\n");
int ret=scanf("%*[\r\n\t]%[^,],%[^,],%d",str,&b,&a);
printf("input is str: %s b: %c a: %d And str length is %u, the first character is %u.ret is %d \n",str,b,a,strlen(str),str[],ret);
char testgets[];
gets(testgets);
printf("testgets:%s \n",testgets);
}
return ;
}

在%号中若匹配不到任何字节,则scanf失败,标准输入缓冲区中的字段一直保留未被读取。

注:

%跟*则表示过滤掉满足条件的字符,%后可跟正则表达式。

此文所有的实验都是基于下面的程序:
char str[];
for (int i = ; i < ; i++) str[i] = '!';
执行完后str的值为
str = "!!!!!!!!!!"
我们把str的每个字符都初始化为惊叹号,当str的值发生变化时,使用printf打印str的值,对比先前的惊叹号,这样就可以方便的观察str发生了怎样的变化。下面我们做几个小实验,看看使用sscanf和正则表达式格式化输入后,str有什么变化。
实验1:
sscanf( "" , "%s" , str) ; ---------str的值为 "123456\0!!!"
这个实验很简单,把源字符串""拷贝到str的前6个字符,并且把str的第7个字符设为null字符,也就是\
实验2:
sscanf( "" , "%3s" , str) ; ---------str的值为 "123\0!!!!!!"
看到没有,正则表达式的百分号后面多了一个3,这告诉sscanf只拷贝3个字符给str,然后把第4个字符设为null字符。
实验3:
sscanf( "aaaAAA" , "%[a-z]" , str) ; ---------str的值为 "aaa\0!!!!!!"
从这个实验开始我们会使用正则表达式,括号里面的a-z就是一个正则表达式,它可以表示从a到z的任意字符,
在继续讨论之前,我们先来看看百分号表示什么意思,%表示选择 ,%后面的是条件,比如实验1的"%s",s是一个条件,表示任意字符,"%s"的意思是:只要输入的东西是一个字符,就把它拷贝给str。实验2的"%3s"又多了一个条件:只拷贝3个字符。实验3的“%[a-z]”的条件稍微严格一些,输入的东西不但是字符,还得是一个小写字母的字符,所以实验3只拷贝了小写字母"aaa"给str,别忘了加上null字符。
实验4:
sscanf( "AAAaaaBBB" , "%[^a-z]" , str) ; ---------str的值为 "AAA\0!!!!!!"
对于所有字符,只要不是小写字母,都满足"^a-z"正则表达式,符号^表示逻辑非。前3个字符都不是小写字符,所以将其拷贝给str,但最后3个字符也不是小写字母,为什么不拷贝给str呢?这是因为当碰到不满足条件的字符后,sscanf就会停止执行,不再扫描之后的字符。
实验5:
sscanf( "AAAaaaBBB" , "%[A-Z]%[a-z]" , str) ; ---------段错误
这个实验的本意是:先把大写字母拷贝给str,然后把小写字母拷贝给str,但很不幸,程序运行的时候会发生段错误,因为当sscanf扫描到字符a时,违反了条件"%[A-Z]",sscanf就停止执行,不再扫描之后的字符,所以第二个条件也就没有任何意义,这个实验说明:不能使用%号两次或两次以上
实验6: sscanf( "AAAaaaBBB" , "%*[A-Z]%[a-z]" , str) ; ---------str的值为 "aaa\0!!!!!!"
这个实验出现了一个新的符号:%*,与%相反,%*表示过滤 满足条件的字符,在这个实验中,%*[A-Z]过滤了所有大写字母,然后再使用%[a-z]把之后的小写字母拷贝给str。如果只有%*,没有%的话,sscanf不会拷贝任何字符到str,这时sscanf的作用仅仅是过滤字符串。
实验7:
sscanf( "AAAaaaBBB" , "%[a-z]" , str) ; ---------str的值为 "!!!!!!!!!!"
做完前面几个实验后,我们都知道sscanf拷贝完成后,还会在str的后面加上一个null字符,但如果没有一个字符满足条件,sscanf不会在str的后面加null字符,str的值依然是10个惊叹号。这个实验也说明了,如果不使用%*过滤掉前面不需要的字符,你永远别想取得中间的字符。
实验8:
sscanf( "AAAaaaBC=" , "%*[A-Z]%*[a-z]%[^a-z=]" , str) ; ---------str的值为 "BC\0!!!!!!!"
这是一个综合实验,但这个实验的目的不是帮我们复习前面所学的知识,而是展示两个值得注意的地方:
注意1:%只能使用一次,但%*可以使用多次,比如在这个实验里面,先用%*[A-Z]过滤大写字母,然后用%*[a-z]过滤小写字母。
注意2:^后面可以带多个条件,且这些条件都受^的作用,比如^a-z=表示^a-z且^=(既不是小写字母,也不是等于号)。
实验9:
int k;
sscanf( "AAA123BBB456" , "%*[^0-9]%i" , &k) ; ---------k的值为123
首先,%*[^-]过滤前面非数字的字符,然后用%i把数字字符转换成int型的整数,拷贝到变量k,注意参数必须使用k的地址。
实验10:
sscanf("123334abcd123", "%[0-9]*", str);
执行完后str的内容是字符串""。[-]*是一个非常简单的正则表达式,意思是匹配数字任意次。

最新文章

  1. 黄聪:C#带cookie模拟登录百度
  2. sublime配置java编译环境
  3. sql存在一个表而不在另一个表中的数据
  4. VC++从入门到精通视频教程网址
  5. ImageView 缩放
  6. fseek/ftell/rewind/fgetpos/fsetpos函数使用-linux
  7. sed 一些用法
  8. JSON.parse()和JSON.stringify()&amp;&amp;traditional(ajax请求)的作用
  9. Extjs中grid前端分页使用PagingMemoryProxy【二】
  10. [转载]Tortoise SVN使用方法,简易图解
  11. 前端入门20-JavaScript进阶之异步回调的执行时机
  12. bzoj1977次小生成树(重要)
  13. InnoDB中锁的算法(3)
  14. echarts仪表盘
  15. 【!Important】Java线程死锁查看分析方法
  16. tips:Java的Random类和Random函数
  17. MySQL学习笔记:delete
  18. 微信小程序+PHP:动态显示项目倒计时(格式:4天7小时58分钟39秒)
  19. 第二百七十七节,MySQL数据库-数据表、以及列的增删改查
  20. TI IPNC Web网页之进阶修改

热门文章

  1. SQL Server Connection Pooling (ADO.NET)
  2. Windows 命令行切换目录
  3. JAVA编程思想读书笔记(一)--面向对象
  4. viewpager切换耗时控制
  5. 2017年浙江中医药大学大学生程序设计竞赛(重现赛)D - CC的神奇背包
  6. Struts2 MVC基础介绍
  7. 为什么我喜欢Java
  8. PHP定义字符串
  9. HDU 6071 Lazy Running(最短路)
  10. 零配置文件搭建SpringMvc