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

削除された内容 追加された内容
Ef3 (トーク | 投稿記録)
→‎発展的な話題: 直接構造体の配列を初期化すればよいし、いまは初期化リスト中で [2] = (struct product_list){ "野菜ジュース", 190 } の様に順位を指定した初期化も出来る。
タグ: 2017年版ソースエディター
Ef3 (トーク | 投稿記録)
敬体に統一。
タグ: 2017年版ソースエディター
2 行
 
== 条件分岐 ==
もし明日晴れだったら、出かけよ畑を耕そう。晴れでなか雨が降ったら、出かけないでいよ本を読もう。」のように、何かの条件によって処理が分かれることを条件分岐といいます。
 
C言語では条件分岐の為に、選択文が用意されています。
21 行
 
たとえば、プログラムでは「もし変数aが4だったら、変数gには15を代入しなさい」は、
:<syntaxhighlight lang="C"c>
if (a == 4)
g = 15;
27 行
と記述します。
 
:<syntaxhighlight lang="C"c>
if (a == 4)
</syntaxhighlight>
34 行
if 文は条件式が 0 でなければ、続く文を実行し、0 であれば実行しません。
 
;if文の例:<syntaxhighlight lang="C"c>
#include <stdio.h>
 
55 行
 
もし、条件式を変更すると、・・・
:<syntaxhighlight lang="C"c>
#include <stdio.h>
 
78 行
=演算子は左辺に右辺を代入した後その値を返すため、右辺が0の場合は偽となり、右辺が0以外の場合は真となります。
コンパイルエラーとはなりませんが、予期しない結果を引き起こします<ref>clang や gcc であれば、コマンドラインオプション -Wparentheses で警告されるようになります。</ref>。
:<syntaxhighlight lang="C"c>
if (i = 0)
printf("iは0");
85 行
 
* 誤った;の付加
if文でよくある間違いの1つに、if文の後に誤った;を付加することがあります
:<syntaxhighlight lang="C"c>
if (i == 0);
printf("iは0");
93 行
 
==== if文の書式 ====
if文には次の2通りの形式があります
 
;if形式:<syntaxhighlight lang="C"c>
if ( 式 )
</syntaxhighlight>
;if-else形式:<syntaxhighlight lang="C"c>
if ( ) 文1 else 文2
文1
else
文2
</syntaxhighlight>
どちらの形式でも、文1は、式の比較が0に等しくない場合に実行されます。
if-else形式では、式の比較値が0に等しい場合、文2が実行されます
 
; 制約事項
118 ⟶ 114行目:
if文もまた文であるため、上の2つの形式を組み合わせて次のように連続して記述することもできます。
 
:<syntaxhighlight lang="C"c>
if ( )
else if ( )
else if ( )
.
.
else
133 ⟶ 128行目:
 
if文に限りませんが、文はブロック(複合文; ''Compound statement'' )であってもかまいません。
;if文の使用例:<syntaxhighlight lang="C"c>
#include <stdio.h>
 
153 ⟶ 148行目:
 
;まとめ
:if文とは、選択文の内の1つであり、式(制御式)の論理値に従って、指定する文(文)を実行するかどうか選択します。
: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"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
166 ⟶ 161行目:
| publisher = ISO/IEC}}</ref>なので第3引数の値は 1 です。<ref>過去の版で 10 とされていましたが、正しくは 1 です。</ref>)
 
;境界検査インターフェース版:<syntaxhighlight lang="c">
#include <stdio.h>
 
192 ⟶ 187行目:
を無効にします。
}}
 
==== if文の書き換え ====
if文は、0が偽、0以外が真であることを用いて、次のように簡潔に書き換えることができます。
<syntaxhighlight lang="C">
if (i != 0)
//↓
if (i)
 
if (i == 0)
//↓
if (!i)
</syntaxhighlight>
 
C99では、<code><stdbool.h></code> が導入され上記のコードは次の様に書くことができます。
<syntaxhighlight lang="C">
#incude <stdbool.h>
 
if (i != false)
//↓
if (i)
 
if (i == false)
//↓
if (!i)
</syntaxhighlight>
 
==== if文のネスト ====
if文の中にif文を入れることを、ネストまたは入れ子という。
;if文のネストの使用例:<syntaxhighlight lang="C"c highlight="10,11" line>
#include <stdio.h>
 
235 ⟶ 205行目:
}
</syntaxhighlight>
;if文のネストの使用例(境界チェックインタフェース版):<syntaxhighlight lang="c" highlight="10,11" line>
#include <stdio.h>
 
253 ⟶ 223行目:
なお、上の入れ子のifの例は &&演算子 を用いて、次のように簡潔に書き換えることができます。
 
;ネストしたif文を&&演算子で置き換えます。:<syntaxhighlight lang="C"c highlight=10 line>
#include <stdio.h>
 
274 ⟶ 244行目:
<code>strcmp</code> 関数は文字列どうしを比較して、一致したときに(1ではなく)0を返す標準ライブラリ関数です。
 
;コード例:<syntaxhighlight lang="C"c highlight="7,11" line>
#include <stdio.h>
#include <string.h>
 
int main(void) {
const char a[30] = "taro";
 
if (strcmp(a, "taro") == 0) {
printfputs("太郎taroだった \n");
} else {
printfputs("太郎taroない \n");
 
if (strcmp(a, "taro") != 0) {
printf("太郎でない \n");
}
}
</syntaxhighlight>
;実行結果:<syntaxhighlight lang=text>
太郎taroだった
</syntaxhighlight>
 
 
下記のようなにも書ける。
;コード例:<syntaxhighlight lang="C" highlight="7,11" line>
#include <stdio.h>
#include <string.h>
 
int main(void) {
char a[30] = "taro";
 
if (!strcmp(a, "taro")) {
printf("太郎だった \n");
}
 
if (!!strcmp(a, "taro")) {
printf("太郎でない \n");
}
}
</syntaxhighlight>
;実行結果
太郎だった
 
{{コラム|C言語では文字列は第一級オブジェクトではない|
323 ⟶ 272行目:
=== switch文 ===
==== 基本 ====
switch文とbreak 文とを使って、場合分け(複数個の「場合」のある場合)を分けができます。
<ref>『JISX3010:2003』p.101「6.8.4.2 switch文」</ref>
 
switch文とbreak 文とを使って、場合分け(複数個の「場合」のある場合)をできます。
 
たとえば
372 ⟶ 319行目:
例外的に現在実行中のcaseの下にある次のcaseを実行したい場合にだけ「fallthrough」というキーワードを付け加えるという仕組みをとっています(2022年10月時点のC言語には「fallthrough」キーワードはありません<ref name="fallthrough">C++には fallthrough というアトリビュートが有り、ISO/IEC/JTC1/SC22/WG/14 に [http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2408.pdf N2408 The fallthrough attribute]として提案され、C23に追加される予定です。</ref>)。
 
C言語を知りGo言語やSwift言語を学ぶ人は、switch文がディフォルトではフォールスルーしないことに気がつかづ混乱することがあります(これらの新興言語では、ループの中のswitch文のcase節でbreakするとループから抜けてしまう)。
[[Ruby]]ではこの混乱を避けるためswitch/case文ではなく、case/when(then)文を用意し転換教育がスムースに行われるよう配慮されています。
}}
385 ⟶ 332行目:
同一のswitch文のブロックの中に、同一の整数定数式の値を持つcaseラベルがあってはなりません。
 
switch文の記述は次のようになっています
*switch-case-...-default文
;形式:<syntaxhighlight lang="C"c>
switch (整数式) {
case 整数定数式:
break;
.
.
.
default:
文;
400 ⟶ 345行目:
</syntaxhighlight>
 
;switch文の使用例:<syntaxhighlight lang="C"c>
#include <stdio.h>
 
424 ⟶ 369行目:
</syntaxhighlight>
 
== 繰返し文 ==
返し文( ''iteration statement'' ; より一般的には反復文)は、制御式( ''controlling expression'' )の0との比較が一致するまで、ループ本体( ''loop body'' )と呼ばれる文を繰返し実行します<ref name="jtc1-sc22-wg14-n2596-6.8.5">{{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 = 125, §6.8.5 ''Iteration statements''
| publisher = [http://www.open-std.org/jtc1/sc22/wg14/www/projects ISO/IEC JTC1/SC22/WG14]}}</ref>。
返し文はブロックで、そのスコープは、そのブロックを囲むブロックのスコープの狭義の部分集合( ''strict subset'' )です。
ループ本体もまた、繰返し文のスコープの狭義の部分集合をスコープとするブロックです。
返し文は、その制御式が定数式ではなく、本体、制御式、(for文の場合)式-3で以下の操作が行われていない場合、実装上は終了するとみなすことができます。
 
構文
448 ⟶ 393行目:
| page = 125, §6.8.5.1 ''The while statement''
| publisher = [http://www.open-std.org/jtc1/sc22/wg14/www/projects ISO/IEC JTC1/SC22/WG14]}}</ref>。
;形式:<syntaxhighlight lang="C"c>
<!-- C99 の 6.8.5.1 The while statement には The evaluation of the controlling expression takes place before each execution of the loop body.としか書かれていない。
<ref>『JISX3010:2003』p.102「6.8.5.1 while文」</ref>
while文とは、繰り返し文の内の1つであり、式(制御式)の論理値が真である間、指定する文(ループ本体)の実行を繰り返す。
while文には、制御式と、ループ本体が含まれる。
while文では、制御式の論理値の評価は、ループ本体の各実行の前に行われる。
while文では、制御式の論理値があらかじめ偽であれば、ループ本体は1度も実行されない。
-->
;形式:<syntaxhighlight lang="C">
while ( 式 )
</syntaxhighlight>
 
;while文の使用例:<syntaxhighlight lang="C"c>
#include <stdio.h>
 
469 ⟶ 407行目:
i++;
}
//「0 1 2 3 4 」と表示される。
}
</syntaxhighlight>
;コード例実行結果:<syntaxhighlight lang="C" highlight="7,11" linetext>
0 1 2 3 4
</syntaxhighlight>
 
 
=== do-while文 ===
479 ⟶ 420行目:
| page = 125, §6.8.5.2 ''The do statement''
| publisher = [http://www.open-std.org/jtc1/sc22/wg14/www/projects ISO/IEC JTC1/SC22/WG14]}}</ref>。
 
<!--
;形式:<syntaxhighlight lang="C"c>
<ref>『JISX3010:2003』p.102「6.8.5.2 do文」</ref>
do-while文とは、繰り返し文の内の1つであり、式(制御式)の論理値が真である間、指定する文(ループ本体)の実行を繰り返す。
do-while文には、制御式と、ループ本体が含まれる。
do-while文では制御式の論理値の評価は、ループ本体の各実行の後に行われる。
do-while文では、制御式の論理値にかかわらず、ループ本体は少なくとも1度は実行される。
-->
;形式:<syntaxhighlight lang="C">
do
492 ⟶ 427行目:
</syntaxhighlight>
 
;do文の使用例:<syntaxhighlight lang="C"c>
#include <stdio.h>
 
501 ⟶ 436行目:
i++;
} while (i < 5);
//「0 1 2 3 4 」と表示される。
}
</syntaxhighlight>
;形式実行結果:<syntaxhighlight lang="C"text>
0 1 2 3 4
</syntaxhighlight>
 
523 ⟶ 460行目:
: 省略された式-2は、非ゼロの定数によって置き換えます。
 
;[https://paiza.io/projects/1WZmT-1GXcpN9fJO1umqNw?language=c for文の使用例]:<syntaxhighlight lang="C"c line>
#include <stdio.h>
 
537 ⟶ 474行目:
==== for文とスコープ ====
先の「for文の使用例」の変数 i のスコープは
:<syntaxhighlight lang="C"c start=4 line>
for (int i = 0; i < 5; i++)
printf("%d ", i);
546 ⟶ 483行目:
==== for文のネスト ====
for文の中にfor文を入れることを、ネストまたは入れ子という。
;for文のネストの使用例。九九を表示しま。:<syntaxhighlight lang="C"c>
#include <stdio.h>
 
566 ⟶ 503行目:
!while文!!do文!!for文
|-
|style="vertical-align:top"|<syntaxhighlight lang="C"c>
while (1)
</syntaxhighlight>
|style="vertical-align:top"|<syntaxhighlight lang="C"c>
do
while (1);
</syntaxhighlight>
|style="vertical-align:top"|<syntaxhighlight lang="C"c>
for (;;)
</syntaxhighlight>
|}
いずれのコードも、継続条件は常に非ゼロの整数(あるいは、非ゼロの整数とみなされます)ので文の実行を無限に繰返します。
無限ループを用いる場合、後述する break br文を用いるなどして適切にループから脱出できるようにする必要があります。
 
;無限ループを使った例:<syntaxhighlight lang="C"c>
#include <stdio.h>
 
606 ⟶ 543行目:
:※註 過去の版では、scanf の戻り値をチェックしていませんでしたが EOF を返す可能性があり、これを無視すると、それこそ'''無限ループ'''になってしまうので、戻り値も必ずチェックしましょう。また、この部分は return 文による脱出の例にもなっています。
 
;境界検査インターフェース版 無限ループ:<syntaxhighlight lang="c">
#include <stdio.h>
 
656 ⟶ 593行目:
goto文は、可変的に変更された型を持つ識別子のスコープ外から、その識別子のスコープ内にジャンプしてはなりません<ref name="jtc1-sc22-wg14-n2596-6.8.6.1"/>
 
;goto文の形式:<syntaxhighlight lang="C"c>
goto 識別子 ;
</syntaxhighlight>
;ラベル文の形式:<syntaxhighlight lang="C"c>
識別子 :
</syntaxhighlight>
;[https://paiza.io/projects/KhbOJ-86RYOk0V_up6nyjQ?language=c 例]:<syntaxhighlight lang="C"c>
#include <stdio.h>
 
690 ⟶ 627行目:
 
上の例であれば、
;return文を使いgoto文をなくした例:<syntaxhighlight lang="C"c>
#include <stdio.h>
 
718 ⟶ 655行目:
;コード例
:{|
|<syntaxhighlight lang="C"c>
while (/* ... */) {
/* ... */
726 ⟶ 663行目:
}
</syntaxhighlight>
|<syntaxhighlight lang="C"c>
do {
/* ... */
734 ⟶ 671行目:
} while (/* ... */);
</syntaxhighlight>
|<syntaxhighlight lang="C"c>
for (/* ... */) {
/* ... */
745 ⟶ 682行目:
:上のコード例での continue は、goto continと同等です<ref>2番目の例のcontin:ラベルに続くのは、NULL文です。1つ目と3つ目の例のnull文は、ラベルによって暗示されてます。</ref>。
 
;形式:<syntaxhighlight lang="C"c>
continue;
</syntaxhighlight>
;[https://paiza.io/projects/IM89XiUvAXhyRY6_KHv7hA?language=c continue文の使用例]:
:<syntaxhighlight lang="C"c>
#include <stdio.h>
 
int main(void) {
// 1から14までの整数の中で、3の倍数以外を表示しま
for (int i = 1; i <= 14; i++) {
if (i % 3 == 0) {
787 ⟶ 724行目:
break文は、switch本体またはloop本体の中以外に現れてはいけません。
 
break文の記述は次のようになっています
;形式:<syntaxhighlight lang="C"c>
break;
</syntaxhighlight>
;例:<syntaxhighlight lang="C"c>
#include <stdio.h>
#include <math.h>
812 ⟶ 749行目:
=== for文の中のif文のbreak ===
<!--[[File:Destination Break Programming in If sentence in For sentence.svg|thumb|600px|break 文の移動先の説明図]]-->
<syntaxhighlight lang="C"c highlight="5,9" line>
for (・・・) {
for (・・・) {
839 ⟶ 776行目:
式を持つreturn文は、戻り値の型がvoidである関数の中に現れてはなりません。式を伴わないreturn文は、戻り値の型がvoidである関数の中でのみ現れます<ref name="jtc1-sc22-wg14-n2596-6.8.6.4"/>。
 
;形式:<syntaxhighlight lang="C"c>
return 式;
</syntaxhighlight>
;[https://paiza.io/projects/-WEWEhXg14BxtL3A9tMsiA?language=c 例]:<syntaxhighlight lang="C"c>
#include <stdio.h>
 
849 ⟶ 786行目:
 
int main(void) {
int i = function(); //関数functionを呼び、返却値をiに代入しま
printf("iの値は%d。", i);
}
858 ⟶ 795行目:
論理型とはデータ型の内の1つで、真(true)か偽(false)かの2種類の論理値をとります。
JISX3010:2003(ISO/IEC 9899:1999)において(いわゆる「C99」に相当のJIS)、論理型はキーワード_Boolを用いて宣言されます。
偽は0 , 真は1 (及び0以外) を用いて表現されます
<ref>『JISX3010:2003』p.32「6.3.1.2 論理型」</ref>