mallocとfree
処理速度の分析が終わったので、メモリの使用量の問題の解説。 メモリの使用量が多かった場合の問題点を質問してみるが、 仮想記憶が動き出して処理速度の低下につながるといった認識は乏しい。
固定サイズ配列の問題
定番の質問として、クラスの名簿を作りたい。宣言はどう書くか?と質問してみる。 普通だったら、以下のような宣言が多い。
// 1クラス50人、名前は長くても漢字10文字程度 char name[ 50 ][ 20 ] ;
しかしながら、このプログラムでは、寿限無のような長い名前は覚えられないし、大学のような 大人数1クラスであれば、破たんする。 一方で、発生頻度が低いのに、寿限無や巨大クラスを想定した宣言をすれば、 メモリのほとんどは利用されず、効率が悪くなる。
C言語では、配列は基本固定サイズであり、以下のような変数によって、 サイズを指定することはできない。 新しいプログラム言語であれば、任意長配列も使えるが、それはプログラム言語が便利に なっただけであり、アルゴリズムと効率を学ぶこの授業であれば、その便利なプログラム言語が、 裏で何をしてくれているのか知っておく必要がある。
int n = 式 ; int a[ n ] ; // こんなことはできない。
mallocとfree
malloc は、必要に応じて指定されたbyte数のメモリを確保してくれる命令。前述のような 変数で指定される配列確保であれば、以下のようになる。
int n = 式 ; int *a = (int*)malloc( sizeof( int ) * n ) ; if ( a != NULL ) { 配列を使う処理 ; free( a ) ; }
mallocは、void*型ポインタを返すので、適切なデータのポインタに型キャストで変換してから 用いる。また、メモリ確保に失敗した場合には、NULLポインタを返すので、 if 文によるチェックが必要となる。 利用が終わったメモリ空間は、free() によって、返却し後で再利用される。
free() が適切に呼び出されず、確保したメモリを不要になった時に返却しないと、 使用されないメモリ空間が発生する。(メモリリーク) 「最後に確保したメモリから、不要になる」ような、関数の中でのみ使われる配列であれば、 alloca() なども便利である。 また、malloc+freeで確保されるヒープメモリは、プロセスの停止と共にOSに返却されるため、 処理が終わるとともに、メモリが不要となり、プロセスが終了するのであれば、 あえてfree()を書かない場合もある。しかしながら、初心者のうちは適切にfreeを呼び出す プログラム習慣を身に着けるべきであろう。
昨年度のテスト過去問題…(05/09)
- 05/09 昨年度のテスト過去問題のページの更新ができていなかったので、更新作業。ファイルは保存してあったけど、問題ページからリンクが無かった… #fnct http://tinyurl.com/d5kcxvl
この記事は、 の @TohruSaitohに掲載した #fnct タグ付き記事を、まとめたものです。
N進数と文字数値変換
N進数の話の演習として、C言語における8進数,16進数の話や、 文字コード、エスケープ文字などを説明の後、 文字列⇔数値の相互変換プログラムを説明。
テスト前演習課題とするが、レポートでの採点基準を説明。
- プログラムの難易度
- プログラムの説明
- 実行結果(動作が怪しくなりそうなケースの動作検証をしているか)
- 動作検証や、プログラムの改良についての考察
課題テーマN進数
参考資料で10進数⇔文字列変換(atoi,itoa)などを取り扱ったので、 これを拡張し、8進,16進,N進などを取り扱えるようにする。 自信があれば、小数点を含む文字列の変換などに取り組む。
鯖江Webアプリコンテスト EI4山腰君 最優秀賞
鯖江市をPRするWebアプリを作るコンテストにて、 EI4年の山腰 貴大君が「鯖江の野望」にて、最優秀賞に選ばれました。
補数とN進数
前回の授業で数値範囲についての説明はしたけど、 2の補数表現やN進数の話が抜けていたので、説明。 基本は、他の授業で既に行われているが、小数点以下のN進数変換などを 交えながら、Nで割りながら余りを書き並べるとか、Nをかけながら整数部を書き 並べるといった、N進数変換を説明。
この前に、説明の不十分であった、ポインタ渡し・配列渡しなどを 説明しておく。
複素数クラスの演習
GW真ん中の授業。といっても、先週の複素数クラスの演習なので、 出席をとって各自演習。 質問などの確認をしたけど、ひとまず専攻科学生なら、自分で調べるだろう。 ただ、"C++,複素数クラス"なんてぐぐると、operator+( Complex… )みたいな、 演算子オーバロードばりばりな、サンプルコードになりそうなので、 ひとまず注意だけしておく。
nagios3でトラブルメールが飛ばなかった
OSをoldstableからstableに変更したサーバだけど、サーバ監視ソフトを当然入れたんだけど、nagios3でトラブル時にメールが飛ばない。 色々チェックして悩んでいたけど、 ようやく判明。contacts_nagios2.cfg の、contact_name の項目で alias が設定ミスで、 他の項目の名前とかぶっていた。
nagios3 の起動時のエラーチェックは、それなりに充実しているから、安心していたけど、 alias の衝突は無チェック&内部データテーブルは alias 名で管理されてるのね….
ハノイの塔とマージソートの分析
再帰呼び出しを含む処理の、速度分析の説明として、ハノイの塔とマージソートを 説明する。
ハノイの塔
ハノイの塔は、3本の塔にN枚のディスクを積み、ディスクの上により大きいディスクを積まずに、移動させるパズル。 ハノイの塔の移動回数を とした場合、 少ない枚数での回数の考察から、
ということが予想される。
この予想が常に正しいことを証明するために、ハノイの塔の処理を、 最も下のディスク1枚と、その上の(N-1)枚のディスクに分けて考える。 これより、
ということが言える。 ディスクが 枚で、予想が正しいと仮定すると、
枚では、
となり、 枚でも、予想が正しいことが証明された。 よって数学的帰納法により、1枚以上で予想が常に成り立つことが証明できた。
マージソートの処理速度分析
最も高速なソートアルゴリズムとして、クイックソートがあげられる。 しかし、説明が分かり難いので、同じ処理速度のオーダとなる、 マージソートの分析で説明する。
マージソートのアルゴリズムは、
- データが1件の時は、そのまま。
- それ以上の件数では、
- データを中央で2分割して、それぞれをマージソートを行う。
- 出来上がった2つのデータ列を、先頭から2つを比較し小さい方から移し替える。
この方式であれば、再帰方程式として、以下の式が示される。
N=1,2,4,8,…と、代入を繰り返すと、処理時間は、 であることがわかる。
複素数のクラスと隠蔽化
前回までで、オブジェクト指向でのクラスの説明が終わったので、 class宣言の外にメソッド実体を書く方法(クラス限定子"::")や、 inline宣言などを説明し、実際の例として複素数クラスを用いて演習にとりかかってもらう。
// 直交座標系 class Complex { private: double re , im ; public: inline Complex( double r , double j ) : re( r ) , im( j ) {} inline void print() { printf( "%lf + j%lf" , re , im ) ; } inline void add( Complex& z ) { re += z.re ; im += z.im ; } } ; void main() { Complex a( 1 , 2 ) ; Complex b( 2 , 3 ) ; a.add( b ) ; a.print() ; } // 極座標系 class Complex { private: double ab , th ; public: inline Complex( double r , double j ) : ab( sqrt( r*r + j*j ) ) , th( atan2( j , r ) ) {} inline void print() { printf( "%lf ∠ %lf" , ab , th ) ; } inline void add( Complex& z ) { // 演習のネタ } } ;
直交座標系のクラスと、極座標系のクラスにて、 複素数の加減乗除のメソッドを実装し、 これにより隠蔽化が可能で、クラス内を変更(リファクタリング) しても利用者に影響が少なくできることを体感してもらう。