計算機言語 I 第 11 回
教科書 12 章 : typedef と構造体
この資料: http://www.math.u-ryukyu.ac.jp/~suga/gengo/2023a/11.pdf
レポートへのツッコミ
特になし.
今回は,教科書 12章の構造体の講義にします.
12.1: typedef
typedefはプログラマが新たな変数の型を定義することができるための仕組みです. 使い方は, 教科書にあ る通りです. 次に述べる構造体の記述を簡略化するのに多く用いられますが,これ以外にも,コンパイラの仕様 の違いを吸収するのにも用いられます.
よく用いられるのが, 基本データ型の範囲の違いです. Cでは, 基本データ型(特に int)に対して,その値 の範囲を仕様で規定していません. これは,「Cはハードウェアに密着して,より効率の良い実行ファイルを作 成する」というのが開発目的であったためで,その特徴を残すためにこのような仕様になっています.
ところが,プログラマ的にはlong int型が32bitだったり64 bitだったりの変化があると,処理系に合わ せてプログラムを書き換えなければならない事態が発生します.
最近のCでは,ヘッダファイルでこの処理系の差を吸収する仕組みが用意されています. /usr/include/stdint.h
には,その処理系のサイズに合わせた整数型の定義がなされています. 例えば,上のヘッダファイルをinclude しておくと,
uint32_t
は,その処理系に合わせた符号無し32bit整数型であることが保証されます.
1
構造体
構造体は,複数の変数型をまとめて一つの変数にしたものです. 配列が,同じ変数型を複数個まとめたもので あることと対比できます.
宣言の仕方, typedefを活用して宣言をわかりやすくするなどは,教科書を参照してください. 構造体メン バへの参照方法も教科書の通りです.
PascalやModula–2というプログラム言語を開発したN. Wirth (ビルト)の有名な著書に, アルゴリズム+データ構造=プログラム(原題Algorithms + Data Structres = Programs) というものがあります(日本語訳は,残念ながら現在絶版中).
現在のこの講義では, Cの文法を中心に述べていますが,本格的なプログラミングでは,「処理対象に対して 適切なデータ構造を定義して, さらに処理を行う適切なアルゴリズムを記述する.」が求められます. 構造体は
「適切なデータ構造の定義」のための仕組みです. 最近開発されたプログラミング言語では,「オブジェクト指 向」と呼ばれるものが導入されています. オブジェクト指向は, データ構造+アルゴリズムを一つの対象(オ ブジェクト)にし,さらにこれに集合論的な包含関係を付け加えたものとも言えます. オブジェクトは, Cで言 うと,関数と今回講義する構造体を一体化したものです. それにより,以前に述べた「値の変化を局所的にす る」ということと, 重複した無駄な記述をしないことを実現させます.
いくつかの注意
教科書では,構造体の配列が書かれていて,教科書通りの内容以外に述べることはないのですが,実践的なプ ログラムでは,「構造体へのポインタの配列」を用いられることが多いです.
理由は,前回述べた「配列のコピーができない」というのと同じ部分です.
前回少し述べましたが,構造体は,文法上「代入によるコピー」ができます. すなわち,変数a, bが構造体 型だとすると,
b = a;
は,変数bのメンバの全てに,aのメンバの値が代入されます. しかし,このコピーの動作は, CPU的には「ひ とつひとつコピーする」以外に方法がなく, 手間がかかるわけです.
実践的なプログラムでは,ポインタをうまく利用して, できる限り「構造体のコピー」のようなことは発生 しないようにします.
この辺が上で述べた「アルゴリズムを知る」部分と関係します.
教科書のプログラムで用いられているstrcpy は文字列をコピーするライブラリ関数ですが, 基本的に
ASCIIコード用に設計されているため,日本語が入った文字に使うには, 注意が必要です.
教科書では, 複素数を構造体を用いて定義していますが, 99年の仕様 C99で複素数型が定義されました. complex.hというヘッダファイル(/usr/include/complex.h)を読んでみてください.
2
レポート問題 : 締め切り 7 月 3 日 ( 月 ) 10:00 JST
今回教科書で,成績処理プログラムの例が挙げられています. 計算機概論I でawkを用いた成績処理を例示 しました. 次回以降,同じような内容をCで書くという事を考えていきます. 今回は,成績を乱数発生機能を 利用して作成することにします. 件名: gengo2023 report 11
• 次のような出力をするプログラム mkdata.cを書け. 213101D 84
213102B 39 ...
中略
...
213139B 77 213140E 29
ここで, 1列目は, 2021年度入学の入学生40名の学籍番号(チェックディジット付)で,学籍番号とチェック
ディジットは次のルールで与えられる.
21 3 1 01 D
入学年度 理学部は3 数理科学科は1 学科内の番号 チェックディジット α, βを0から9 までの数とし, 学籍番号の数字部分が2131αβであったとき,
7× 2 + 6× 1 + 5× 3 + 4× 1 + 3× α + 2× β
1桁目 2桁目 3桁目 4桁目 5桁目 6桁目
の値を11で割った余りの下1桁をγ とする. γ の値によってチェックディジットは,次の値になる.
0 1 2 3 4 5 6 7 8 9
B A K J H G F E D C
2列目は, C の処理系にある擬似乱数発生関数 rand() を用いて試験の得点らしいデータを作成する. rand()を利用するには,ヘッダファイルstdlib.hをincludeする必要があるので,プログラムの初めの方に
#include <stdlib.h>
を記述する. rand()は0からstdlib.hで与えられているRAND_MAXまでの整数値を生成する擬似乱数発生 関数なので, これを0から100(99でも良い)の整数値に, 割り算などを利用して変換する. 変換方法は何通り もあり,結果も違ってくるが,それは問題としない. (注意: 上手にしないと整数値のオーバーフローが起こる.) また,double 型の値が出るような場合は,これを int型にキャストするなり,「近い整数値にする」なりをし て整数値にする. 例えば,double型の変数aに対して, (int) aはaの値を整数値に変換する. (その際,四 捨五入なのか切り捨てなのか切り上げなのかは,ここでは問題にしない.) 数学関数rint(a)はdouble型の 変数値aにもっと近い整数値を返す.
3