「C言語/制御文」の版間の差分
削除された内容 追加された内容
scanf_s("%d", &i, 100); では引数過剰。va_listで引数の数や型を間違えると解析困難なバグの原因になるので注意。 _s 付きのセキュアな関数も、この様なプログラマのミスには無力。 タグ: 2017年版ソースエディター |
scanf/scan_f のEOFチェック漏れ多数。 タグ: 2017年版ソースエディター |
||
127 行
printf("数値を入力してください。:\n");
int i;
if (scanf("%d", &i)
printf("End of File に達しました。\n");
return 1;
}
if (i == 0)
printf("入力値は0\n");
141 ⟶ 144行目:
:if文には、if形式、if-else形式の2通りの形式があり、またそれらを組み合わせてもよい。
Visual C/C++ では、scanf が「非推奨とマークされている関数」にあたり、設定によってはビルドに失敗します。⇒ [https://docs.microsoft.com/ja-jp/cpp/error-messages/compiler-warnings/compiler-warning-level-3-c4996?view=msvc-160 コンパイラの警告 (レベル 3) C4996]▼
これを回避するには、ソースコードに <syntaxhighlight lang="C" inline>#pragma warning(disable:4996)</syntaxhighlight> を補
ここでは scanfの境界検査インターフェース版のscanf_sを使った実装を紹介します<ref>逆に、BSDのlibcやglibcには scanf_s のような境界チェックインタフェース(C11 Annex K)は用意されていません。</ref>(scanf_sの3つめの引数 1は、記憶するデータの個数で、第1引数がスカラオブジェクトを指している場合、それは1要素の配列であるとみなされます。<ref name="jtc1-sc22-wg14-n1570-k.3.5.3.2">{{cite book▼
| url = http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf▼
| title = N1570 Committee Draft — April 12, 2011 ISO/IEC 9899:201x▼
| page=592, §K.3.5.3.2 ''The fscanf_s function''▼
| quote = If the first argument points to a scalar object, it is considered to be an array of one element▼
| publisher = ISO/IEC}}</ref>なので第3引数の値は 1 です。<ref>過去の版で 10 とされていましたが、正しくは 1 です。</ref>)▼
;境界検査インターフェース版:<syntaxhighlight lang="c">
#include <stdio.h>
int main(void) {
▲ printf("数値を入力してください。:");
▲ int i;
printf("End of File に達しました。\n");
▲ scanf_s("%d", &i, 1);
return 1;
}
printf("入力値は0\n");▼
else
}
</syntaxhighlight>
184 ⟶ 193行目:
</syntaxhighlight>
C99では、<code><stdbool.h></code> が導入され上記のコードは次の様に書くことができます。
<syntaxhighlight lang="C">
#incude <stdbool.h>
if (i !=
//↓
if (i)
199 ⟶ 208行目:
==== if文のネスト ====
if文の中にif文を入れることを、ネストまたは入れ子という。
;if文のネストの使用例:<syntaxhighlight lang="C" highlight="10,11" line>
#include <stdio.h>
205 ⟶ 214行目:
printf("数値を入力してください。:");
int i;
if (scanf("%d", &i)
printf("End of File に達しました。\n");
return 1;
}
if (0 <= i)
if (i <= 10)
211 ⟶ 223行目:
}
</syntaxhighlight>
;if文のネストの使用例(境界チェックインタフェース版):<syntaxhighlight lang="c" highlight="10,11" line>
#include <stdio.h>
int main(void) {
printf("数値を入力してください。:");
int i;
if (scanf_s("%d", &i)
printf("End of File に達しました。\n");
return 1;
}
if (0 <= i)
if (i <= 10)
225 ⟶ 239行目:
</syntaxhighlight>
なお、上の
;ネストしたif文
#include <stdio.h>
233 ⟶ 247行目:
printf("数値を入力してください。:");
int i;
if (scanf("%d", &i)
printf("End of File に達しました。\n");
return 1;
}
if (0 <= i && i <= 10)
printf("入力値は0以上10以下");
296 ⟶ 313行目:
<ref>『JISX3010:2003』p.101「6.8.4.2 switch文」</ref>
switch文とbreak 文とを使って、場合分け(複数個の「場合」のある場合)をできます。
たとえば
305 ⟶ 322行目:
(以下略)
のような場合に、switch文とbreak 文で、場合分けをできます。
コードはイメージ的に言うと、
336 ⟶ 353行目:
というコードなら、もしa=2なら、実行されるのは、文m2だけでなく、さらに文m3や文m4も実行してしまいます。
このような仕組み(つまりbreak 文がないかぎり、次の関数を実行してしまう)のことを'''フォールスルー'''( ''fall through'' ) と呼びます。
{{コラム|フォールスルー|
353 ⟶ 370行目:
defaultラベルもなければ、ブロックの次の文に制御を移します。
break 文はswitchブロックの次の文に制御を移します。
同一のswitch文のブロックの中に、同一の整数定数式の値を持つcaseラベルがあってはなりません。
377 ⟶ 394行目:
printf("一桁の数値を入力してください。:");
int i;
if (scanf("%d", &i)
printf("End of File に達しました。\n");
return 1;
}
switch (i) {
case 2:
458 ⟶ 478行目:
/* ... */
}
-->▼
</syntaxhighlight>
▲-->
</ref>。
607 ⟶ 627行目:
</syntaxhighlight>
|}
いずれのコードも、継続条件は常に
無限ループを用いる場合、後述する break br文を用いるなどして適切にループから脱出できるようにする必要があります。
;無限ループを使った例:<syntaxhighlight lang="C">
632 ⟶ 652行目:
</syntaxhighlight>
:※註 過去の版では、scanf の戻り値をチェックしていませんでしたが EOF を返す可能性があり、これを無視すると、それこそ'''無限ループ'''になってしまうので、戻り値も必ずチェックしましょう。また、この部分は return 文による脱出の例にもなっています。
▲Visual C/C++ では、scanf が「非推奨とマークされている関数」にあたり、設定によってはビルドに失敗します。⇒ [https://docs.microsoft.com/ja-jp/cpp/error-messages/compiler-warnings/compiler-warning-level-3-c4996?view=msvc-160 コンパイラの警告 (レベル 3) C4996]
▲ソースコードに <syntaxhighlight lang="C" inline>#pragma warning(disable:4996)</syntaxhighlight> を補って迂回する方法もありますが、
▲ここでは scanfの境界検査インターフェース版のscanf_sを使った実装を紹介します(scanf_sの3つめの引数 1は、記憶するデータの個数で、第1引数がスカラオブジェクトを指している場合、それは1要素の配列であるとみなされます。<ref name="jtc1-sc22-wg14-n1570-k.3.5.3.2">{{cite book
▲| url = http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf
▲| title = N1570 Committee Draft — April 12, 2011 ISO/IEC 9899:201x
▲| page=592, §K.3.5.3.2 ''The fscanf_s function''
▲| quote = If the first argument points to a scalar object, it is considered to be an array of one element
▲| publisher = ISO/IEC}}</ref>なので第3引数の値は 1 です。<ref>過去の版で 10 とされていましたが、正しくは 1 です。</ref>)
;境界検査インターフェース版 無限ループ:<syntaxhighlight lang="c">
680 ⟶ 691行目:
[[#goto文|goto]] identifier ;
[[#continue文|continue]] ;
[[#break 文|break]] ;
[[#return文|return]] expression<sub>opt</sub> ;
792 ⟶ 803行目:
このように、continue 文は、そのループ内の以降の処理をスキップしつつも、カウントを1回ぶん、進めます。
=== break 文 ===
break 文( break statement)は、最小のswitch文または反復文を囲むものの実行を終了させます<ref name="jtc1-sc22-wg14-n2596-6.8.6.3">{{cite book
| url=http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2596.pdf
| title= N2596 working draft — December 11, 2020 ISO/IEC 9899:202x (E)
| page=127, §6.8.6.3 ''The break statement''
| publisher = [http://www.open-std.org/jtc1/sc22/wg14/www/projects ISO/IEC JTC1/SC22/WG14]}}</ref><ref>『JISX3010:2003』p.105「6.8.6.3 break 文」</ref>。
break 文は、switch本体またはloop本体の中以外に現れてはいけません。
break 文の記述は次のようになっている。
;形式:<syntaxhighlight lang="C">
break;
812 ⟶ 823行目:
double d;
printf("正の数を入力してください。(0以下で終了):");
if (scanf("%lf", &d)
printf("End of File に達しました。\n");
return 1;
}
if (d <= 0)
break;
821 ⟶ 835行目:
=== for文の中のif文のbreak ===
<!--[[File:Destination Break Programming in If sentence in For sentence.svg|thumb|600px|break 文の移動先の説明図]]-->
<syntaxhighlight lang="C" highlight="5,9" line>
for (・・・) {
836 ⟶ 850行目:
</syntaxhighlight>
kこのように、for文の中にif文があり、if文のブロックの中にbreak;がある場合、一番内側のfor文の終わりに処理が移ります(ここでは、ラベル break_point の位置)。
for文が2つ以上ある場合、break 文で複数のfor文を一度に抜け出すことは'''不可能'''です。
=== return文 ===
864 ⟶ 878行目:
</syntaxhighlight>
<!-- 型や演算子について「制御文」で触れるのは蛇足では?
== 論理型 ==
論理型とはデータ型の内の1つで
JISX3010:2003(ISO/IEC 9899:1999)において(いわゆる「C99」に相当のJIS)、論理型はキーワード_Boolを用いて宣言され
偽は0 , 真は1 (及び0以外) を用いて表現される。
<ref>『JISX3010:2003』p.32「6.3.1.2 論理型」</ref>
論理型において、ヘッダファイル<stdbool.h>をインクルードすることで、_Boolの代わりにbool、0の代わりにfalse, 1の代わりにtrueを用いることができる<ref>『JISX3010:2003』p.182「7.16 論理型及び論理値<stdbool.h>」</ref>。
bool false true いずれも typedef ではなく、マクロで実装すると規定されているので、従前のソースコードと識別子の衝突が起こった場合 #undef することが出来ます。
== 演算子 ==
=== 比較演算子 ===
条件判定式の <code>if(a <= b)</code> などの <nowiki> <= </nowiki>や <nowiki> >= </nowiki> や <nowiki> == </nowiki> などが来る部分の演算子のことを比較演算子(ひかく えんざんし)という
{{See also|C言語/演算子と式#比較演算子 {|class="wikitable"
904 ⟶ 908行目:
|}
これらの論理演算では、条件を満たしているなら、if文などの制御式は 1
条件が満たされていないなら、 if文などは 0 を返す。▼
たとえば
if (a <= b)
の場合
いっぽう、
if (a <= b)
の場合
古い標準C言語には論理型が無かったので、かつては整数の1と0によってC言語では論理の真偽を表していた。▼
=== 論理演算子 ===
=== 増分及び減分演算子 ===
-->
== 脚注 ==
<references/>
== 参考文献 ==
* 日本工業標準調査会(当時、現:日本産業標準調査会)『JISX3010 プログラム言語C』2003年12月20日改正
[[Category:C言語|せいきよふん]]
|