常に無力だけのオリジナルを見つけるために、高度な使用方法のscanfの発見まで、限られた入力の問題のいくつかを解決する上でとてもシンプルにすることができます。
記事がで再現:https://blog.csdn.net/C1664510416/article/details/80869470
前のセクションでは、我々は、様々なデータを読み取るためのscanf()を使用する方法について、基本的にscanf関数を排除し、またバッファを説明する、コントロール文字に使用することができるのscanf()のフォーマットを要約示しました( )これらの奇妙な行動で、これまでのところ、多くの初心者は、()、彼らが完全にscanf関数をマスターしていると思います。
あなたが入力したい場合は実際には、これは基本的な使用法のちょうどのscanf()があり、すべてのCプログラマが言語を習得する必要があり、より多くのクールな、より個人的な、より多くのセキュリティ、あなたものscanf()の高度な使用方法を学ぶ必要があります、これは偉大な神と流域の新人です。
さて、クローサー家庭に、私たちは三つの側面のscanf()の高度な使用方法を説明します。
1)読み取り長を指定します
あなたはそれでのprintf()の最小出力幅を指定することができます覚えていますか?中間フォーマット制御文字が数字が続き、例えば、%10d
位置の出力の整数表現は、少なくとも10個の文字によって占められます。
- 10未満の整数幅場合、左側のスペースで埋め。
- 幅は整数10、出力10、もはや機能の整数自体の幅を超えた場合。
実際には、scanfの()は同様の使用は、デジタル中間形式の制御コードを追加し、データを読み取るための最大の長さを表すことができ、例えばしている:%2d
2の整数を表し、最大読み取り、%10s
最大文字列表現の読み取り長さは10である、または10文字まで読みました。
次の例を考えてみます。
#include <stdio.h>
int main(){
int n;
float f;
char str[23];
scanf("%2d", &n);
scanf("%*[^\n]"); scanf("%*c"); //清空缓冲区
scanf("%5f", &f);
scanf("%*[^\n]"); scanf("%*c"); //清空缓冲区
scanf("%22s", str);
printf("n=%d, f=%g, str=%s\n", n, f, str);
return 0;
}
输入示例 ①:
20↙
100.5↙
HTTP://c.biancheng.net↙
N = 20、F = 100.5、STR = HTTP://c.biancheng.net
输入示例 ②:
8920↙
10.2579↙
HTTP://data.biancheng.net↙
N = 89、F = 10.25、STR = HTTP://data.biancheng。
这段代码使用了多个 scanf() 函数连续读取数据,为了避免受到缓冲区中遗留数据的影响,每次读取结束我们都使用
scanf("%*[^\n]"); scanf("%*c");
来清空缓冲区。
限制读取数据的长度在实际开发中非常有用,最典型的一个例子就是读取字符串:我们为字符串分配的内存是有限的,用户输入的字符串过长就存放不了了,就会冲刷掉其它的数据,从而导致程序出错甚至崩溃;如果被黑客发现了这个漏洞,就可以构造栈溢出攻击,改变程序的执行流程,甚至执行自己的恶意代码,这对服务器来说简直是灭顶之灾。
在用 gets() 函数读取字符串的时候,有一些编译器会提示不安全,建议替换为 gets_s() 函数,就是因为 gets() 不能控制读取到的字符串的长度,风险极高。
就目前学到的知识而言,虽然 scanf() 可以控制字符串的长度,但是字符串中却不能包含空白符,这是硬伤,所以 scanf() 暂时还无法替代 gets()。不过大家也不要着急,稍后我还会补充 scanf() 的高级用法,届时 scanf() 就可以完全替代 gets(),并且比 gets() 更加智能。
2)特定の文字を一致させます
%s 控制符会匹配除空白符以外的所有字符,它有两个缺点:
- %S、特定の文字は、まさにこのような小文字、数字など、または小数として読んで、読むことができない、%sの缶は何もしません。
- %Sは%S遭遇スペース、その単語の間にスペースが分離されているので、例えば、複数の単語は、文字列に格納することができない、空白を含めることができない、いくつかの場合において、それは、より恥ずかしいだろう文字列に読み込ま私はオーバー読みます。
要想解决以上问题,可以使用 scanf() 的另外一种字符匹配方式,就是%[xxx]
,[ ]
包围起来的是需要读取的字符集合。例如,%[abcd]
表示只读取字符abcd
,遇到其它的字符就读取结束;注意,这里并不强调字符的顺序,只要字符在 abcd 范围内都可以匹配成功,所以你可以输入 abcd、dcba、ccdc、bdcca 等。
请看下面的代码:
- 書式#include <stdio.hに>
- INT メイン(){
- 文字列str [ 30 ]。
- scanf関数("%[ABCD]" 、STR )。
- printf ("%sの\ n " 、STR )。
- リターン 0 ;
- }
入力例①:
abcdefgh↙
ABCD
入力例②:
baccbaxyz↙
baccba
使用コネクタ
書かれた文字のセットを簡単にするために、scanfの()は、ハイフンの使用サポートし-
、例えば、%[AZ]、%[0-9の範囲の文字を表す ] 等が挙げられます。
ASCIIコードにハイフン文字相当の左側には、ハイフン文字の右にも、ASCIIコードに対応する文字のASCIIの範囲内で読み出される2つの文字が配置されています。今度は、その振る舞いが定義されていない、場合左ASCIIコードにしても文字が、右未満であることに注意してください。
共通ハイフン例:
%[a-z]
文字ABC ... XYZ、範囲を読み、すなわち小文字を示します。%[A-Z]
ABCの文字を読むことを意味します... XYZの範囲、すなわち大文字。%[0-9]
範囲012 ... 789、進数での文字を読むことを意味します。
あなたはまた、例えば、それらを組み合わせることができます。
%[a-zA-Z]
手段は大文字と小文字を読み取るには、そのアルファベットのすべての文字。%[a-z-A-Z0-9]
表すには、すべての小数点以下の数字とアルファベットの手紙を読んで。%[0-9a-f]
16進数を読んですることを意味します。
次のプレゼンテーションを考えてみます。
#include <stdio.h>
int main(){
char str[30];
scanf("%[a-zA-Z]", str); //只读取字母
printf("%s\n", str);
return 0;
}
输入示例:
abcXYZ123↙
ABCXYZ
一部の文字が一致しません
假如现在有一种需求,就是读取换行符以外的所有字符,或者读取 0~9 以外的所有字符,该怎么实现呢?总不能把剩下的字符都罗列出来吧,一是麻烦,二是不现实。
C语言的开发者们早就考虑到这个问题了,scanf() 允许我们在%[ ]
中直接指定某些不能匹配的字符,具体方法就是在不匹配的字符前面加上^
,例如:
%[^\n]
改行を除くすべての文字にマッチし、改行は読み停止しました。%[^0-9]
小数点以下の数字を除くすべての文字にマッチし、小数点以下の数値は、経験の読み取りを停止します。
请看下面的例子:
- 書式#include <stdio.hに>
- INT メイン(){
- チャー0009 [ 30 ]、STR2 [ 30 ]。
- scanf関数("%[^ 0-9]" 、0009 )。
- scanf関数("%※[^ \ N- ]" ); scanfの("%のC *" ); //バッファクリア
- scanf関数("%[^ \ n ]" 、STR2 )。
- printf ("STR1 =%S \ nはSTR2 =%S \ n " 、STR1 、STR2 )。
- リターン 0 ;
- }
入力例:
ABCXYZ @#87edf↙
C C ++のjavaのpython行くjavascript↙
STR1 = ABCXYZ @#
STR2 = C、C ++のJavaのpython JavaScriptを行きます
文字列の行を読み取り、取得したコード行6は、()関数はまったく同じであることに留意されたいです。あなたは言って、明らかに間違っている、()、scanf関数を参照してください)もscanf関数を言うスペースうん、(文字列を読み取ることができます)完全に(取得交換することはできません。
さらに、scanfのは()も機能を持っていない()それを取得され、含まれていない文字列を指定する文字列の最大長を指定することができます。
例えば、ラインを読む桁の文字列が含まれない場合があり、長さが30を超えることはできません。
#include <stdio.h>
int main(){
char str[31];
scanf("%30[^0-9\n]", str);
printf("str=%s\n", str);
return 0;
}
输入示例 ①:
http://c.biancheng.netます。http://biancheng.net↙
STR =のhttp://c.biancheng.netます。http://
输入示例 ②:
私は8years.↙のためにプログラミングされている
列str =私がプログラミングされています
总之,scanf() 不仅可以完全替代 gets(),并且比 gets() 的功能更加强大。
3)文字の読み取りが破棄されます
在前面的代码中,每个格式控制符都要对应一个变量,把读取到的数据放入对应的变量中。其实你也可以不这样做,scanf() 允许把读取到的数据直接丢弃,不往变量中存放,具体方法就是在 % 后面加一个
*
,例如:
%*d
Aは、読み取り、廃棄の整数を表します。%*[a-z]
小文字は読み捨てる表し;%*[^\n]
それは改行以外のすべての文字を捨てると述べました。
请看下面的代码演示:
- 書式#include <stdio.hに>
- INT メイン(){
- int型のn ;
- 文字列str [ 30 ]。
- scanf関数("%* D%D" 、 &N )。
- scanf関数("%*は[AZ]" )。
- scanf関数("%[^ \ n ]" 、STR )。
- printf ("N =%dの、STR =%S \ N " 、N 、STR )。
- リターン 0 ;
- }
入力例:
100999abcxyzABCXYZ↙
N = 999、STR = ABCXYZ
結果の分析:最初の100は、整数のscanf()にある%*d
リードを捨て、整数999は、最初に%d
読み出し、そしてnに割り当てられます。このとき、abcxyzABCXYZバッファ残り、第二のscanf()が読み取られ、破棄ABCXYZために、最後の残りのABCXYZのscanf()読み取りおよびSTRに割り当てることです。
私たちが実現していませんが、入力バッファのビットラメかかわらず、それを空にしますが、有効である、直接廃棄された文字を読み込みます。「でクリア(リフレッシュ)、それらの奇妙な行動は根本的に解消するバッファー:」を、私たちは、緩衝液が空)(使用scanf関数を与えられています
scanf関数( "%※[^ \ n]は"); scanf関数( "%* C");
ここでは、説明する必要があります。
あなたを理解する最初の必要性は、時間がバッファを空にするために必要とされるまで、バッファは改行の最後の文字でなければならない、それである\n
入力バッファ行バッファリングモードので、ユーザは、改行が生成されますキーを入力し、現在の入力を終了押します、その後、読み始めるための関数を入力します。scanf("%*[^\n]");
空の前にすべての改行文字、scanf("%*c");
最後に残った改行は空にしてください。
一部のユーザーは、これらの二つの文、書き込みをマージ:
scanf関数( "%* [^ \ n]は%* C")。
これは間違っています。声明は、少なくとも一つの他の文字の前に改行が要求されるので、MERGE文の後、単一の改行を空にすることはできません、試合をリードする、単一の改行は失敗します。
概要
scanf()の完全な制御文字列が書き込まれます。
%{*} {幅}タイプ
前記{}オプション表します。各部分の意味は、特定のは、以下のとおりです。
type
これは、例えば、読み出されたデータのタイプを示し、%のD、%S、%[AZ]、%[^ \ n]となど、種類が有していなければなりません。width
これは不要、最大読み取り幅を示しています。*
不要、破棄された読み出されたデータを表します。