古代魔術Cの最後の講義です。ここでは応用的な機能を学習します。

whileforと同じく、ループを実装する機能です。ですが、扱い方はforよりシンプルです。

while(継続条件){

}


whileは{}の中を有効範囲とし、継続条件が真である限り有効範囲を処理し続けます。
継続条件が偽になった時、whileから脱出します。


118


ちなみに、真偽は整数値で表すことができます。
0が偽を表し、それ以外の数が真を表します。

問36:ということはwhileの継続条件に1と書くとどうなるでしょうか。




ご明察の通り、whileでできることはforでもできます。
なぜなら、forにも継続条件を書く欄があるからです。for(初期化; 継続条件; 終了処理)

時代背景的には、まずwhileが先に生まれ、forが存在しなかった時代があります。
whileも単純にコーディングできる点が魅力なのですが、本講義でwhileを取り扱うとなると、forも指導する必要があり、ページ数が増えてしまう為にF限目まで敢えて教えていませんでした。
皆さんはwhileもforもどちらも使いこなして下さい。
アドバイスですが、forは回数が決まっているループに、whileは回数が決まっていないループに使うと良いでしょう。


問37:次のコードをforで書き直しなさい。

118


━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
更に、whileの親戚にdo while;があります。しかしこれはあまり使われません。
第一に、whileで事足ります。第二に使いこなすのが少し難しいです。第三に、コードが読みにくくなるので使うべきではありません。

do {

} while(継続条件);


do whilewhileの相違点は、{}の有効範囲が、継続条件の真偽に関わらず1度は実行される点です。
しかし、継続条件がコードの下方に記述されるため、上からプログラムを読み進めていく時に、do whileの条件を探す為に一度下にスクロールする必要性が生じる為、あまりきれいな文法ではありません。使うべきではない文法を練習しても仕方ないのでここでは紹介のみに留めます。どうしても使う必要が生じたら各自調べて下さい。
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
goto という文法もあります。しかしgoto は現在では使われていません。gotoは好きな行へ処理を飛ばすことができるのですが、上から下へ流れていく基本原則を破壊するので、プログラムが読みにくくなります。
しかも、理論上gotoを使用しなくてもあらゆるプログラムは書けます。

また、多重ループからの脱出に使用できるという反論もありますが(かつてはボクもこの意見でした)、そういう場合はループそのものを関数化して、return;するべきだと思います。

使うべきではない文法を練習しても仕方ないのでここでは紹介のみに留めます。どうしてもどうしても使う必要が生じたら各自調べて下さい。
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
条件演算子「?」はif の単行版です。

短いifを書く時は、?を使うとすっきり書くことができます。
しかし、同じことがifでもできるので覚えても覚えなくても良いです。

122


次のソースコードは同じ挙動をします。


121

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
ifは実は単行でも使用できます。{}で囲まなかった場合は、ifの有効範囲は次のセミコロン(;)までとなります。

123

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
forも単行でも使用できます。{}で囲まなかった場合は、forの有効範囲は次のセミコロンまでとなります。

124

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
continue;はループの内側でループの終端へジャンプさせる文です。

125

あまり使用しないので、頭の片隅にでも入れておいて下さい。
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
if else の後ろに繋げることもできます。else で繋いだ箇所をelse if と呼びます。

else ifは、先頭のifが偽の時に初めて条件が判定されます。
先頭のifが真の時はelse ifは偽扱いとなります。
もちろん文末のelseも偽扱いです。

126


もし、else ifを使用しないと、文末のelseは直近のifのみを判定対象とします。

127

elseif (Number == 200)以外の時に発動するので、Number==100の時も頑張りましょうと表示されるのです。

また、else if は∞に連結できます。
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
short型とfloat型はそれぞれint型とdouble型のミニチュアです。

int(整数型) :-2,147,483,648 ~ 2,147,483,647(-21億から21億までの値を保存可能)
short(整数型):-32,768 ~ 32,767
double(少数型):1.7E +/- 308 (15 桁)
float(少数型):3.4E +/- 38 (7 桁)

現在はあまり使われていません。
今はPCの性能が上がったので、節約の為にミニチュアの変数を使う必要はないのです。
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
int型にunsignedを付けると、符号なし型になります。つまり-(マイナス)符号が付けられなくなるということです。その代わり、正数の最大値は2倍になります。

unsigned int:0 ~ 4,294,967,295(0から42億までの値を保存可能)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
変数は、同じ型であれば,演算子で区切ることで連続して宣言、初期化できます。

128


しかし、うっかり初期化を忘れてしまった時に気づきにくいのであまり推奨されていません。
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Cではソースファイルのどこに関数を書いても構いません。
1枚のソースファイルへ1つの関数を書くか、.hファイルへ記述するのが原則ですが、
main関数の上に書いても認識されます。

131


main関数の下へ書く場合、関数のプロトタイプ宣言が必要です。
プロトタイプ宣言とは、.hのインクルードと同じことをしているだけです。


もしint Add5(int i);がない場合、main関数へ突入した時点でAdd5の正体をコンパイラが掴めません。なので、main関数へ処理が突入する前にプロトタイプ宣言でコンパイラへ関数を教えてあげる必要があります。プロトタイプ宣言は、関数の戻り値と名前と仮引数を記述し、行末へセミコロン;を付けます。
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
整数へのポインタを持つこともできます。

129


通常の変数は他の関数から参照することはできませんが、ポインタはそれが可能です。
なぜなら、ポインタ変数へ入っているデータは、メモリ上のアドレスだからです。
つまり、ポインタ変数を引数へ渡せば、その関数から他の関数の変数を操作することができるのです。ただ、数値データをポインタで操作するのは処理速度的にも好ましくないので、あまり推奨されていません。なので頭の片隅にでも入れておいて下さい。

130


文字列定数を代入する時は&を付けませんでしたが、それ以外の型であれば&を付けて下さい。例えば整数型の変数へ入っている値がアドレスかもしれないとコンパイラは解釈するからです。
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
ポインタで指し示した文字列定数を変更することはできないと紹介しました。
しかし、ポインタ変数へ新しい文字列定数のアドレスを代入することはできます。


134


ところで非公式の呼び方というか、ボクが勝手に呼んでいるだけですが、ポインタ変数ではなく、アドレス変数と呼んでもよいかもしれません。ポインタ変数とは、アドレスを格納する変数なので。
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
実はポインタ変数は連続して初期化できません。
ポインタ変数:アドレスを格納した変数
なぜなら、ポインタ変数の正しい宣言方法はint *p;だからです。

しかし、Cはフリーフォーマットなので、int* p;と宣言しても問題ないのです。この方が読みやすいですよね。

ポインタ変数を連続初期化する時は、int *p, *q;と書きます。
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
実はchar型は整数型としても使用できます。
その場合、格納できる値の範囲は–128 ~ +127です。
unsigned charの範囲は0 ~ 255です。
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
インクリメント演算子とデクリメント演算子は、変数の後ろに付けることもできます。

132


ただし、前置verと後置verは挙動が若干違います。

133


後置インデクリメントはその式の中で最も遅いタイミングで値を更新します。
なので、Answerへ代入が行われた後で値が更新されたのです。

また、後置インデクリメントは前置インクデリメントよりもパワーを必要とするので、現在はあまり使われていません。C++で書くときは基本、前置インデクリメントを使います。
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
代入演算子は=だけではありません。
+=は代入先へ右辺の値を加算します。(例:Answer += 2; // Answerへ2を加算)
-=は代入先から右辺の値を減算をします。(例:Answer -= 2; // Answerから2を減算)
*=は代入先へ右辺の値を乗算します。(例:Answer *= 2; // Answer*2をAnswerへ代入)
/=は代入先へ右辺の値を除算します。(例:Answer /= 2; // Answer/2をAnswerへ代入)
%=は代入先へ右辺の値を除算した余りを代入します。(例:Answer %= 2; // Answer%2をAnswerへ代入)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
char型に限らず、int型やdouble型でも配列を宣言することができます。
char型の時と使用方法は同じです。

135


なお、{}で代入できるのは初期化の時だけです。
また、{}で指定しなかった箇所は0が代入されます。
さらに、文字列定数を初期化する時の手法は使えません。
136

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Cでは配列は多次元に拡張できます。

137

しかしややこしいのであまり使われません。
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
#define マクロで定数を定義し、名前を付けることができます。

#define MAX 3
と書いた場合、ソースコード上でMAXという単語はコンパイル時に3として扱われます。

169

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Cではメモリを実行時に確保することができます。
通常のプログラムでは、実行前に必要なメモリ(変数の領域)を確保するのですが、実行中に確保することもできるのです。

例えばユーザーが入力した名前の文字数に応じてchar型の変数を確保することもできます。

次のプログラムでは、実行時にint型の領域を3つ確保しています。

139


mallocとfreeを使います。
mallocでメモリを確保し、freeで確保したメモリを解放します。
freeで解放しないとメモリリークを起こします
メモリリーク:使わない領域がメモリにできる現象

mallocとfreeはstdlib.hをインクルードすることで使用できます。
mallocの引数へは確保する領域をバイト単位で指定します。
このプログラムでは整数型(4バイト)を3つ分確保して使用しています。
mallocの値を12以下にするとエラーとなります。しかし、メモリの確保は実行時に行われるので、コンパイラはエラーを検出できません。

戻り値がvoid型なので、キャスト演算子で強制的に型を合わせます。
mallocの戻り値はアドレス変数です。確保した領域の先頭のアドレスを返却します。

freeへは、解放すべきアドレス変数を渡します。

このソースコードの値を代入する部分へ着目してみましょう。
*MemoryPointer = 1;
*を付けるとそのアドレス変数が指し示す実態を意味します。
*MemoryPointerは整数型ですから、整数の値を代入できます。

*(MemoryPointer + 1) = 2;
は、MemoryPointerというアドレス変数の次のアドレス変数を意味します。

mallocで確保した領域は連番で配置(char型の配列と同じ)されているので、アドレス変数へ1を足すことで次の領域を表すことができるのです。つまり+1で4バイト移動したことになります。

メモリの実行時確保を使用せずとも同じ処理をするプログラムは書けるので、初学者のうちは頭の片隅へ置いておく程度でよいでしょう。
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
お疲れ様でした!
これでCの基本機能は全て学習し終えました。
しかし、これでもまだ紹介しきれていない機能もあるのです(バイナリファイルの取扱など)

ですが、ここまでの機能を駆使しても様々なプログラムは書けます。
応用的な力は、専門的な力であり、局所的にしか使用できないことが多いです。
なので、どの分野へ行っても、どのライブラリやAPIを使うにしても使用できる機能を中心に紹介してきました。

これから、様々な見たことのないソースコードがあなたを待ち受けるでしょうが、基本は変わりません。また、わからなければこのページへ辿り着いた時と同じように検索すればよいのです。

ここまでお読み頂き本当にありがとうございました。
より上を目指すのであれば他のWEBページを参照したり、本を購入してもよいでしょう。