file-scope(static)とextern文
プロコンの競技部門の学生さんたちが、最後の追い込み。 各パーツに分かれて動作確認が取れてきたし、 1つのプログラムに合成する最後の段階になっている様子。 しかしながら、合成した後プログラムが動かないとの相談。 1度目の処理は動くけど、2回目で動かないという状態なので、 不完全な初期化データを使って動かなくなっているのではと想像する。 といっても、そう簡単に間違いが見つかる訳もないけど、 ひとまずコードを見せてもらう。 すると、覚えたての分割コンパイルで、ヘッダファイルの中に、 static int array[…] ; といった記載が見つかる。
このままでは、array[] が、各C言語ファイル毎に、file-scope の別な実体を持つため、 大域変数渡しの副作用が伝わらなかったり、その結果として未初期化が発生したり。
ファイルスコープ
C言語では、静的変数の局所変数を作りたい場合、関数ブロック内で "static"キーワードを指定すればよい。 しかしながら、関数ブロック外で static キーワードをつけると、 分割コンパイルした場合、file-scope を持つようにコンパイルされる。 つまり、各ファイル毎の大域変数は、たとえ同じ名前の大域変数が別ファイルに あったとしても、別な記憶領域を確保してくれる。
(( aaa.c )) int x1 ; // 静的変数・大域変数 static int x2 ; // 静的変数・大域変数・ファイルスコープを持つ void foo() { static int x3 ; // 静的変数で局所変数 : } (( bbb.c )) extern int x1 ; // aaa.c の x1と同じ実体を参照できる。 static int x2 ; // aaa.cのx2とは大域変数だけど別の実体をもつ
分割コンパイルして、各ファイルで共通の変数や関数を定義する場合は、 以下のように行う。 ポイントは、extern によって宣言すると、実体は別のところにある変数となる。
(( common.h )) int foo() ; // プロトタイプ宣言 extern int bar ; // 実体はどこかで確保される変数として宣言 (( aaa.c )) #include "common.h" int bar = 123 ; // 変数barの実体 int foo() { // 関数foo()の実体 } (( bbb.c )) #include "common.h" void main() { bar = 234 ; // aaa.c の大域変数barに代入 printf( "%d" , foo() ) ; // aaa.c の関数foo()を呼び出し }
関係データベースとSQL
データベースの基礎の説明が終わったので、 データベースの実際のデータベース操作言語SQLの詳細を説明する。
関係データベースの用語
関係データベースでは、表構成のデータで表現され、 集合であらわされる項目の複数の組み合わせで表現される。 1つの項目フィールドの取り得る値の集合をAとした場合、 直積とは、 で表現される。A,Bの間の関係とは、直積の一部
であらわされる。
SQLの基本
SQLの基本として、データのテーブルを作る "CREATE TABLE" 文の説明として、 数値型・文字型・日付型などの型の名前や説明を交えながら説明。 参考にしている教科書では、CREATE VIEWの説明がある割に、CREATE TABLEの説明が無い… この他に、INSERT文の説明を行う。
データを探す場合は、SELECT文を使うが、 選択とは、特定条件のレコードを探す処理、射影でそのレコードの中の特定のカラムを取り出す。 結合とは、カラムの組み合わせを記述すものである。
SELECT [射影] FROM [結合] WHERE [選択] ; 例: SELECT S.名前 FROM S,P WHERE P.点数>80 AND S.学科='電子情報' ;
教科書で説明の無い部分として、WHERE節の中のBETWEEN,LIKE,IS NULLなどを紹介。
来週は副問い合わせ文などの説明の後、Web上のSQL演習環境を説明した後、練習課題とする。
計算機システム:OSの歴史と機能概要
コンピュータの歴史の説明の後の、8bit,16bitのパソコンの発達をうけ、 32bitパソコンの発達やOSの発達について説明する。
16bitパソコンの登場とともに、マイクロソフト社のMS-DOSや、GUIを取り入れたApple社の Macintoshの発達したころ、16bitコンピュータはシングルタスク・シングルユーザであった。 この頃の汎用機では、その計算機パワーを活用すべくマルチユーザ・マルチタスクで 処理が行われていた。 この便利な機能を、ミニコンやパソコンで使いたいという要求がでてきた。 この中で、C言語を開発したカーニハンやリッチーは、Multicsをミニコンで動かすために、 unixを開発した。 unixでは、複数ユーザが同時に複数の処理をこなすために、プログラムが並行動作している 別プログラムに悪影響を及ぼさないようにするなどの保護機能・セキュリティ機能が 重要になってきた。 32bitコンピュータが出てきたころになり、パソコンでもようやくマルチタスク・マルチユーザを 実現するための保護機能を実装できるようになってきた。 パソコンOSでは、Windows 95/98/Me/Home等ではシングルタスク・シングルユーザ がベースであった。しかし、OS/2やWindows/NT/2000/Xp/Vista/7とマルチタスク・マルチユーザ の機能が発達していった。 一方、unixでは、BSD/SysVの2系統に分かれて発達する中、 インターネットを利用したオープンソースのOSのLinuxが発達していく。
コンピュータの基本構成
計算の手順はプログラムであり、計算に必要なデータと共に使われることで、 ソフトウェアと呼ばれる。プログラムの計算手順の考え方はアルゴリズムと呼ばれる。 コンピュータは、CPU,メモリ(主記憶),補助記憶装置,周辺装置から成り立っている。 ほとんどのコンピュータは、ノイマン型と呼ばれる構成で、 (1)メモリから命令を読む,(2)命令を解読,(3)データをメモリから読む,(4)計算,(5)結果をメモリに書き込むの処理を繰り返して行われる。
主記憶のメモリには、不揮発性のROMと揮発性のRAMがあり、 最近のOSでは、処理に応じてプログラムの中身を変える必要から、 RAMがほとんどとなっている。 しかし、このままでは電源を入れた直後のコンピュータは動けない。 このためメモリの一部はROMがあり、この中には、 周辺装置の使い方のBIOSと、電源投入直後の処理のブートローダのプログラムが 書き込まれている。 コンピュータは、ブートローダがBIOSを使って、補助記憶装置内のOSを主記憶に呼び出して OSが動き始める。利用者が、アプリケーションを起動すると、 OSが補助記憶装置内のプログラムをRAMに呼び出して処理が行われる。
プログラムを動かすにあたって、CPUでは機械語で処理が行われる。 昔はプログラムはアセンブリ言語を使って記述していた。 しかし高級言語の登場によって、プログラムが書きやすくなった。 高級言語で書かれたプログラムが動くにあたって、実行方式にはコンパイラ方式と インタプリタ方式がある。 コンパイラ方式は、処理前に機械語をすべて生成してあるため、実行速度が速い。 しかしテストプログラムを動かすような場合、全命令を機械語に直す時間がかかるので、 インタプリタ方式が多用される。コンパイラ方式は実行時に高級言語で書かれた ソースプログラムが不要のため、プログラムの考え方が盗まれることがない。
2010年10月10日(第185回)
誠市、ご縁市、さばえめがねまつりが開かれました。
- メールテーマ:めがね
- 合同学園祭実行委員会よりゲストお二人に来ていただきました!
- 高専祭のお知らせ
- 数学の部屋 第52回 MMM研究会の高専祭の出し物について 長水先生
math101010.mp3
商店街では、誠市・ご縁市・さばえめがねまつりが開催中でした!!
スタジオでは合同学園祭実行委員の方が写真を撮っています
構造体ポインタ渡し&オブジェクト指向
先週の構造体の基本の説明を受け、構造体の実際的な使い方の紹介を行う。 後半では、構造体をうまく使えば、データ隠蔽、手続き隠蔽ができて、 手続き・データ設計者と、それを利用する人に分かれて大きいプログラムが書ける… といった説明を行う。 また、この発展形としてのオブジェクト指向の導入部分を説明する。 ただし、オブジェクト指向のネタは、本来の授業範囲外でテストには出さない。
構造体のポインタ渡し
構造体を使っていると、そのデータを使った処理の記述が増えてくる。 この場合は、以下のように関数に構造体へのポインタを渡して操作を行う。
struct Person { char name[ 10 ] ; int age ; } ; // ポインタ渡しに慣れるまではアロー演算子は使わない。 void set( struct Person*p , char s[] , int a ) { // 質問:なぜ (*p).name = s ; ではいけないのか? strcpy( (*p).name , s ) ; (*p).age = a ; } // 慣れたら、アロー演算子。 void print( struct Person*p ) { printf( "%sさんは%dさいです\n" , p->name , p->age ) ; } void main() { struct Person saitoh ; set( &saitoh , "saitoh" , 45 ) ; print( &saitoh ) ; }
このようなスタイルに慣れると、呼び出し側(この例ではmain()の中)には、 データ構造の中身、手続きの中身を知らなくても、プログラムが書ける。 このようにデータ構造をブラックボックスでとらえられることをデータの隠蔽化、 処理の中身をブラックボックス化することを手続きの隠蔽化という。
そのまんまオブジェクト指向に…
この辺に慣れてくると、オブジェクト指向も理解しやすくなってくる。 オブジェクト指向では、データ構造⇒オブジェクト、データに対する手続き⇒メソッドと呼び、 この2つを合わせてクラスと呼ぶ。
class Person { char name[ 10 ] ; int age ; void set( char s[] , int a ) { strcpy( name , s ) ; age = a ; } void print() { printf( "%s%d" , name , age ) ; } } ; void main() { Person saitoh ; saitoh.set( "saitoh" , 45 ) ; saitoh.print() ; }
授業で眠そうにしている学生さんがいたので、ちょいとイヤミきつめで注意。 緊迫感がなさそうだし、3年だと「あと2年しかない」、「不景気で就職も進学も大変」 というネタでやる気をださないと苦労するのは自分…と雑談を交えた授業となった。
避難訓練&進路希望調査
今日は、昼から避難訓練があるので、授業が短縮授業であった。 しかし来週には保護者面談を実施するので、 自分の授業 の前に、進路希望調査の用紙を配る。 様式は、就職用と進学用で表は履歴書っぽい書式で、裏面は就職先・進学先・業種や、 それに伴う意欲を確認するようなものとした。 これを、保護者面談までor面談当日に提出してもらう予定。
しかしながら、まだ夢のような希望を言ってくる人もいそうなので、 「夢を語る時間はもう終わった」と明言する。
2分木データの処理
先週は2分木の概念の理解と検索処理の話をしたので、 今日は実際に木の全要素に対する処理などを再帰を交えて説明を行った。
2分木の前に、簡単な再帰に慣れてもらうために、 単純リストでのループを使った処理を再帰で記述する練習。 以下のようなcount()を示した後、単純リストの全データ表示と、全データ合計を書いてもらう。 この際に、再起でプログラムを書くコツとして、「処理できない問題は小さく分けて考える」 という定番の説明をおこなう。
// ひとまず再帰に慣れるために線形リストで... int count( struct List* p ) { if ( p == NULL ) return 0 ; else return 1 + count( p->next ) ; }
この後、実際に2分木のデータ処理として、リストに対する全データ表示を記述してもらう。 あらかじめ単純リストの説明の後だったので、意外とすんなり理解してくれた様子。 この説明のあと、全データ件数count(struct Tree*)や、全データ合計sum( struct Tree* )や、 ループで記述可能であるけれどあえて、find( struct Tree* p , int key ) なども考えてもらう。
// 2分木で全データを昇順に表示 void print( struct Tree* p ) { if ( p != NULL ) { print( p->left ) ; printf( "%d" , p->data ) ; print( p->right ) ; } }
この話の関連として、print() は、深さ優先探索であり、記述は手間だけど別な探索では、 幅優先探索といった用語を紹介する。 また、2分木のcount(),sum(),print()などは、通常再帰でなければ記述できない処理であり、 find()はループでも記述可能で、この違いは末尾再帰呼び出しになっているかの 違いであることを紹介する。
データベースの基礎
ガイダンスに続き、データベースの基礎的な総括を行う。
データベースでは、エンドユーザは、WebやGUIアプリなどを経由してデータにアクセスするが、 そのWeb,GUIアプリは、応用プログラマが作成し、実際のデータベースには、SQLを経由して アクセスが行われる。実際のデータベースは、データベース管理者が定義・生成・2次記憶割り付け・再編成などの細かなチューニングを行う。
データベースシステムの実例
データベースシステムの実例ということで、Oracle などの製品名に加え、 Webとの一貫したシステム構築では、LAMP(Linux+Apache+MySQL+PHP)構成といった 用語なども紹介する。
応用プログラマにしてみれば、SQLを経由することで、データをプログラムから分離ができ、 実際の内部の構造を知ることなく独立性が得られる。また、データの一貫性を保つことは、 データベースを利用しないと大変であるが、データベースでは(a)正当性確認,(b)同時実行制御,(c)障害回復などを行ってくれるので、一貫性のあるデータ管理が容易となる。
プライバシーの保護などの話の一環として、最近のシステムでデータベースを利用する場合、 大きな問題となるSQLインジェクションといった手法の存在なども紹介する。
データベースに対する視点
データベースに対する視点として、エンドユーザからの要求を応用プログラマが処理する場合、 データベースの一部分だけであったり、複数のデータベースを大きな単独の表で扱えると便利であったりする。こういう応用プログラマの視点を外部スキーマと呼ぶ。 しかし実際には、複数の表からなるデータベースでは更新なども容易な(正規化された) 表であるほうが良い。このような視点は、概念スキーマと呼ばれる。 さらにデータベースの内部では、このデータを高速に処理するためのインデックスが付加されたり、実際のファイル上に記録されるデータ形式がとられる。これらは内部スキーマと呼ばれる。この利用者の視点に応じたスキーマ構成を、3層スキーマ・アーキテクチャと呼ぶ。
データモデル
データベースでは、階層的なデータ構造は木構造で表現できる。 (ファイルに記録する際では、XMLなどの表現をとったりする。) しかし、階層の深い物の取り扱いは不便となる。現実のデータでは、これらが複雑に絡み合う ことが多く、ネットワークモデルなどと呼ばれる。 これらのモデルは汎用性が高いものの、検索や取り扱いが複雑となるため、 関係モデル(Relational model)が広く使われている。
情報処理技術者試験受験者から質問
情報処理技術者試験を受ける学生さんが、質問にくる。 「第3正規形って何?」例年の質問ネタである。 でもなかなかうまい説明ができない。 こんなんが、データベース教えていていいのかな…
ということで、解りやすく説明しているページを探してみた。
- 第2正規形は、部分関数従属性を取り除く。 「キーから非キー」への関数従属性を整理する。 A→Bを取り除く。
- 第3正規形は、第2正規形から推移関数従属性を取り除くこと。 「非キーから非キー」への関数従属性を整理する。 A→B→Cを取り除く。(A→Bは第2正規形で取り除かれているはず)
計算機システムガイダンス・歴史
専攻科1年対象-後期の計算機システムの初めての授業。 選択で、生産・環境あわせて15名ほどの人数だった。 ガイダンスとして、授業の内容や試験・レポートの実施方法を解説する。 前半の私の担当では、コンピュータシステムで重要となる、 OSの話とネットワークの話…
コンピュータの歴史
コンピュータの歴史ということで、 ネピアの計算尺やパスカルの歯車計算機で計算するという概念の始まり、 ジャカールやバベッジによるパンチカードで仕事の順番を記述するという概念の始まり、 ブール代数やチューリングによる2進数と処理でコンピュータの理論の始まり といったあたりを簡単に紹介する。
次に、第1世代(真空管)、第2世代(半導体)、第3世代(IC)、第3.5世代(LSI)といった、 コンピュータの発達の歴史に沿って、プログラム言語やOSが出てきたあたりを説明する。 第4世代以降は、パソコンの世界の発達を中心に説明する。
4ビットコンピュータi4004,8ビットコンピュータi8080で、 インテル社がパソコン用CPUを売り出す話から、 モートローラの6800系の市場競争の始まりを説明し、16bitコンピュータが開発される際に、 i8080→i8086における命令互換性の配慮が成功の一因であったことを説明する。 また、IBM社のPC/ATにおける情報公開が、3rdパーティによる互換機発売&価格競争で 低価格化&普及となった成功について説明する。 この時代では、TinyBASICとMS-DOSでのビルゲイツの登場とマイクロソフト社が、 ソフトウェア中心の時代に変化させている。 これらの裏で、Apple社は、MacintoshでGUIの導入から、優れた操作性による成功を 収めつつ、ハードウェア情報非公開が高価格化&衰退の原因となったことを紹介する。
次の授業では、シラバス配布せねば…
32bit化と保護機能の実装とOSのセキュリティの関係を解説の予定。