「C言語/制御文」の版間の差分

削除された内容 追加された内容
Ef3 (トーク | 投稿記録)
タグ: 2017年版ソースエディター
Ef3 (トーク | 投稿記録)
→‎無限ループ: scanf/scanf_sの戻り値は EOF の可能性があり、無視すると無限ループに陥る。
タグ: 2017年版ソースエディター
493 行
 
==== 無限ループ ====
無限ループとは、文の実行が無限に繰り返されることである
{| class="wikitable"
<syntaxhighlight lang="C">
|+ 無限ループのコード
while(1)
!while文!!do文!!for文
|-
|style="vertical-align:top"|<syntaxhighlight lang="C">
while (1)
</syntaxhighlight>
|style="vertical-align:top"|<syntaxhighlight lang="C">
上のように記述すると、
do
while文の制御式の論理値が常に真であるため、
文の実行が無限に繰り返される。
while (1);
無限ループを用いる場合、
</syntaxhighlight>
後述するbreak文を用いるなどして、
|style="vertical-align:top"|<syntaxhighlight lang="C">
適切にループから脱出できるようにする必要がある。
for (;;)
</syntaxhighlight>
|}
いずれのコードも、継続条件は常に真であるので文の実行を無限に繰り返します。
無限ループを用いる場合、後述するbreak文を用いるなどして適切にループから脱出できるようにする必要があります。
 
;無限ループを使った例:<syntaxhighlight lang="C">
;例
#include <stdio.h>
<syntaxhighlight lang="C">
// 無限ループ
#include<stdio.h>
 
int main(void) {
for (;;) {
{
printf("ループの中。\n");
while(1){
printf("ループの中。\n");
 
char kotaeans;
printf("ループを脱出しますか? 「はい」y /「いいえ」nN\n ");
if (scanf("%c", &kotaeans) == EOF); {
printf("End of File に達しました。\n");
 
return 1;
if (kotae=='y') {
}
printf("ループを脱出します。\n");
if (ans == 'y') {
break;
printf("ループを脱出します。\n");
}
break;
}
}
printf("ループの外です。\n");
}
printf("ループの外です。\n");
}
</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> を補って迂回する方法もありますが、
:※ ウィンドウズのVisual C 系(Visual C++やC#など)のコンパイラだと、上記のコードはエラーになり動作しない。フリーソフト『学習用C言語開発環境』で上記コードが動作することを確認ずみ。
ここでは 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">
#include <stdio.h>
 
int main(void) {
ウィンドウズのVisual C系コンパイラの場合、下記のコードのように、scanfをscanf_sに変えてください。(なお、scanf_sの3つめの引数(下記の例では「10」)の数字は、記憶するデータ数です。)
for (;;) {
printf("ループの中。\n");
 
char ans;
<syntaxhighlight lang="c">
printf("ループを脱出しますか? 「はい」y /「いいえ」N\n ");
// Visual C系コンパイラ用
if (scanf_s("%c", &ans, 1) == EOF) {
// 無限ループ
printf("End of File に達しました。\n");
#include<stdio.h>
return 1;
 
}
int main(void)
if (ans == 'y') {
{
printf("ループを脱出します。\n");
while (1) {
break;
printf("ループの中。\n");
}
 
}
char kotae;
printf("ループを脱出しまの外でか? 「はい」y /「いいえ」n\n ");
scanf_s("%c", &kotae,10);
 
if (kotae == 'y') {
printf("ループを脱出します。\n");
break;
}
}
printf("ループの外です。\n");
}
</syntaxhighlight>
:※註 過去の版では、scanf_s の戻り値をチェックしていませんでしたが EOF を返す可能性があり、これを無視すると、それこそ'''無限ループ'''になってしまうので、戻り値も必ずチェックしましょう。また、この部分は return 文による脱出の例にもなっています。
 
このプログラムを終了するには、y(Yの小文字)を入力してエンターキーを押します。入力する「y」は直接入力モード(Windowsの場合は半角英数)にしてください。
 
なお、文字変数の中身を示す「'y'」のように、文字リテラルは ' (シングルクォーテーションマーク)で囲みます。文字列リテラルを囲む " (ダブルクォーテーションマーク)と間違えないうようにしましょう<ref>生徒に教えていると、" であるべきところを '' と書いているパターンのほうが多く、また発見が遅れます。</ref>。
このプログラムを終了するには、yを入力してエンターキーを押せば終了します。入力する「y」は直接入力モード(Windowsの場合は半角英数)にしてください。
 
なお、文字変数の中身を示す「'y'」のように、文字型の1文字データの中身をあらわすときに使う「' '」については、(二重引用符ではなく)一重引用符であることに気をつけてください。
 
=== do-while文 ===