第9回 関数とプログラム構造(3) 再帰 プリプロセッサ ファイルの取り込み マクロの置換 条件付き取り込み 再帰呼び出し 関数が、自分自身を呼び出すことを再帰呼び出しと いう 再帰呼び出しは、アルゴリズム(処理の流れ)的に 使用すると記述がすっきりする場合がある。 ただし、関数呼び出しは、呼び出しオーバヘッドが かかるので、処理が遅くなる 無限再帰をしないように気をつける 再帰を停止する条件を必ずつける 再帰が使われる例 階乗の計算 数字から文字列への変換 quick sort (qsort) 再帰を使った例) 階乗計算 int kaijou(int n){ if( n > 1 ) 再帰呼び出し return (n*kaijou(n-1)); else if( n = 1 ) return 1; else{ printf(" illegal number : %d \n",n); return -1; } } Cのプリプロセッサ Cでは、プリプロセッサによって言語仕様が与えられ る コンパイレーションの分離した最初のステップ 実際の動作 ファイルの取り込み ... #include トークンの文字列への置換 ... #define プリプロセッサによって、マシン依存やシステム依存 のコードを分離したり、選択可能にする ファイルの取り込み ファイルを取り込む指令 <ヘッダファイル名> ... システム標準のヘッ ダファイル。システムのinclude directoryでヘッダファイル を探す #include "ヘッダファイル名" ... ユーザのヘッダファイル。 ユーザの指定したディレクトリかcwdから探す #include 取り込み指示されたファイルは、その場所にその内 容が展開される ヘッダファイルにファイル間で共有する関数のプロト タイプ宣言や、extern宣言、#define などを置くこと でバグが混入することを抑える 取り込むヘッダファイルを修正したら、取り込むソー スファイルは全て、コンパイルし直さなければ修正 は反映されない。 マクロの置換 - #define #define name 置換テキスト ... name を置換テキストに置き換えて 定義する ⇔ #undef name ... nameを未定義にする #define 定義された名前の通用範囲は、定義された場所からソー ス・ファイルの最後まで 定義に、以前の定義を用いてもよい #define LENGTH 10 #define SQUARE LENGTH*LENGTH 置換は、文字記号に対してのみ行われ、””で囲まれる文字列定数 には適用されない 名前、置換テキストは任意のものでよい マクロの置換は、関数呼び出しの代わりに使用できる #define max(A,B) ((A) > (B) ? (A) : (B)) マクロの置換を乱用すると、バグの温床になるので使用には注意を する。 マクロの置換による副作用の考察 #define による置換は、単なる文字列の置き 換えなので、使い方によっては正しくない処 理となる #define square(x) (x)*(x) square(z+1); はどのように展開されるか? #define maxof(a,b) ((a) > (b) ? (a) : (b)) maxof(i++,j++)は、何がまずいのか? #による””内への置換 ””(引用符)で囲まれた中の仮引数は置換さ れない 置換テキストの中でパラメータ名の前に#を 置くと””で囲まれた文字列に展開される #define dprintf(expr) printf(#expr " = ...." ); ⇒ printf(" expr = "); プリプロセッサ用の連結演算子## プリプロセッサ用の##演算子は、マクロ展開 の最中に2つの引数を連結する #define paste(front,back) front ## back paste(name,1) れる ⇒ name1 という文字記号が作ら 条件付き取り込み #if 定数整数式 定数整数式が真ならば、#elif か#else あるいは#endifまで取り込み 偽ならば、スキップ #ifdef 名前 ... 名前が前に定義されていれば以下をとりこ み ⇔ #ifndef 名前 ... 名前が定義されてなければ #elif ... プリプロセッサのelse if にあたる #else ... プリプロセッサのelse にあたる #endif ... 条件付き取り込みを閉じるために#ifや#ifdef に対 応して必ず1対1で必要
© Copyright 2024 ExpyDoc