C语言深入标准输入输出( 五 )


第二个用途是初始化结构体,可以发现即便数据类型不同,同样的方法也适合初始化结构体,下面是一个例子:
#includestruct Student{char name[20];int age;char sex;};int main(){struct Student s;scanf("%s%c", s.name);scanf("%d%c", &s.age);scanf("%s%c", &s.sex);puts(s.name);printf("%d\n",s.age);printf("%d\n",s.sex);}
当我们输入Tom 20 0,或Tom 20 man,或者Tom, 19,0时都可以正确解析,因为空格、逗号或者其它分隔符均被%c清除,最后一个回车也被%c清除 。
第三个用途是限制输入长度,和()一样,scanf()可以在%前面添加数字来限制读取长度,多于的字符会被抛弃,例如:
#includeint main(){char str[11]="";scanf("s",str);//只取10个字符scanf("%*[^\n]");scanf(“%*c”); //清除多余缓存puts(str);}
str的容量只有10个字符,如果输入超过10个字符就会导致数组溢出,从而导致程序崩溃,这也是被黑客攻击的漏洞之一,这也是为什么一些编译器改用()的原因 。使用scanf()将输入内容限制为10个字符能够堵住这个漏洞,最后不要忘记清除缓存 。现在你已经看到使用正则表达式清除缓存的语句了,马上我们就会讲解正则表达式的用法 。
第四个用途是使用正则表达式匹配内容,scanf()支持简单的正则表达式,当使用正则表达式时scanf()会改变规则,例如读取字符串时不再是遇到空格停止,而是不能满足正则表达式条件时停止 。scanf()中的正则表达式有两种运行方式,匹配和丢弃,我们先看看匹配是怎么运行的 。

C语言深入标准输入输出

文章插图
scanf(“%[a-z]”, str) 表示从左到右匹配小写字母,遇到非法字符立即停止匹配,然后将匹配的结果写入str,未匹配的内容留在缓冲区,举个例子:
#includeint main(){char str[20]="";scanf("%[a-z]",str);puts(str);scanf("%s%c",str);puts(str);}
当输入时,匹配结果为door,scanf()并不支持全局匹配,遇到数字9后停止运行,剩下的字符留在缓存中,最后两句话输出缓冲区中的内容并清除缓存 。现在我们可以改变匹配规则,利用正则表达式输入带空格的字符串了:
scanf(“%[^\n]”, str)
可以匹配除了换行符之外的所有字符,只到读到换行符才会停止,例如:
#includeint main(){char str[20]="";scanf("%[^\n]",str);getchar();puts(str);}
输入一段包含空格的字符串,就可以看到结果 。
正则表达式另外一个运作方式是丢弃字符,在%的后面加上一个号,变成从左到右遇到符合规则的字符会丢弃,遇到不符合规则的字符则停止丢弃,例如:
scanf(“%[0-9]%s”, str)
丢弃所有数字,这里*不用作通配符,而是表示忽略内容,这是和常规正则表达式的区别,当遇到非数字时停止丢弃,然后剩余缓存的内容匹配%s,我们可以编写一段代码测试结果:
#includeint main(){char str[11]="";scanf("%*[0-9]%s%c", str);puts(str);}
输入,得到结果abc,这样就丢弃了数字开头的部分,也可以将正则表达式改为scanf(“%*d%s%c”, str);%d表示丢弃一个整数,注意如果输入导致一开始就丢弃失败会立即退出,不会继续匹配后面的%s 。最后利用丢弃规则编写清空缓存的代码,如下:
scanf("%[^\n]“); scanf(”%*c");
上面代码第一句丢弃除换行符之外所有的字符,第二句话丢弃换行符,也可以换成(),我们用代码来测试下效果:
#includeint main(){scanf("%s");printf("%d\n",stdin->_cnt);scanf("%*[^\n]");scanf("%*c");//getchar();scanf("%c");printf("%d\n",stdin->_cnt);return 0;}