2013年度 情報処理・演習2 中間試験の解答解説


問題1 アンケートのデータベースを設計するために,
IDNo.氏名,年齢,回答1(番号),回答2(数文字の記述),回答3(番号)
から構成されるデータを扱いたい.

1)上記のデータの構造体を作成せよ.変数の型に注意すること

struct enqt_str{
 int id;
 char name[20];
 int age;
 int ans1;
 int ans2;
 int ans3;
}

2)メイン関数にて構造体を用いて具体的なデータを記述せよ.
例えば50人分作るとして,初期値として代表的に2人分くらい作ればよい.
なお, scanfで対話して入力する,fscanfでファイルから読み出すなど,各自工夫しても構わない.

main(){
 struct enqt_str enqt_dat[50] = {
  {1, 渡邊健太, 20, 1, 4, 5},
  {2, 嶋田渉, 21, 2, 2, 3},
  ・・・
 }
}

参考
構造体名を決めず,以下のように構造体の構造だけを先に定義しておき,関数内で構造体名を
決めて利用する方法もある.

typedef struct{
 int id;
 char name[20];
 int age;
 int ans1;
 int ans2;
 int ans3;
} enqt_str;

main(){
 enqt_str enqt_dat[50] = {
  {1, 渡邊健太, 20, 1, 4, 5},
  {2, 嶋田渉, 21, 2, 2, 3},
  ・・・
 }
}


問題2 変数a, b, cがある.(a+b)のc乗を計算したい.cは正の整数でよい.

1)上記の関数を作成せよ.

double calc_n_jo(double a, double b, int c){
 double kai;
 int i;
 for(i = 0; i < c; c++){
  kai = kai + (a+b);
 }
 return kai;
}

※ math.hを読み込んでいるので,pow(a+b, c);を用いても良い.

2)上記の関数をメイン関数で呼び出し,演算を行うプログラムを作成せよ.
a=1.3, b=2.8, c=5として初期値を与えてよい.

#include <stdio.h>
#include <math.h>

double calc_n_jo(double, double int);


main(){
 double a = 1.3;
 double b = 2.8;
 int c = 5;

 printf("power of (a+b) = %f", calc_n_jo(a, b, c));
}


double calc_n_jo(double a, double b, int c){
 double kai;
 int i;
 for(i = 0; i < c; c++){
  kai = kai + (a+b);
 }
 return kai;
}


問題3 グローバル変数をプログラム中にて利用したい.

1)グローバル変数とは何か,どのように使うか,説明せよ.

グローバル変数とは,開発しているプログラム内の関数の全てから参照できる変数である.
この変数は,メイン関数の前に宣言し,開発しているプログラムに関連するあらゆる関数から呼び
出せる性質が特徴的である.また,関数内での処理により,その値を書き換えることも可能である.

2)グローバル変数を使う際の注意点について説明せよ.

グローバル変数は,開発しているプログラム内の関数の全てから参照できる変数であるが,
その内容を変更することも可能であることに注意しなければならない.
従って,以下の点を注意すべきである.

1)グローバル変数を書き換える関数が存在していないことと変数内が確実に保持されている
2)グローバル変数を書き換える関数が存在していること
3)グローバル変数を書き換える関数が存在している場合,どのように利用されているか

つまり,グローバル関数を使った以上は,その内容が書き換えられたかどうか,どのような書き換え
がなされたか,またその影響はどのようなものであるかを完全に把握しておく必要があるのである.

参考
グローバル変数は極力使うべきではないと考えている参考書も多い.ソースコードが大きい場合,
他人と共有してソフト開発している場合,仕様を充分に明確に残していない場合,上記の通り,不便
だけでなく,結果を保証できない面でも危険なものであると言える.
しかしながら,アルゴリズム上,グローバル関数を書き換える関数がはっきりしていてその動作に問題
なく,,グローバル関数の値を常にモニターするような利用法であれば,便利な場合もある.

こうした一般論は経験則に基づく貴重なものであるが,仕様と必要性がはっきりしている場合には,
使ってみるのも一策であることも確かである.(避けられれば避けた方が無難なことが多いのも確か)


問題4 変数a, b, cがあり,変数の内容をa→b,b→c,c→aと入れ替えたい.
また,データ数は5を考えている.

1)変数内のデータを入れ替える関数を作成せよ.ポインタを用いて作成すること.

void irekae(double* a, double* b, double* c){

 double aa, bb, cc;

 bb = *a;
 cc = *b;
 aa = *c;
 *a = aa;
 *b = bb;
 *c = cc;
 }
}

上記は最低ラインの解答.aa, bb, ccをまとめた配列にしてもかまわない.
あるいは,関数の変数一つでも可能である.

2)メイン関数内にてこの処理を行うプログラムを作成せよ.データ群は適宜初期化して作成せよ.

main(){
 struct irekae sort[5];
 double* dat[3][5]={
  {1, 2, 3},
  {2, 4, 6},
  {3, 6, 9},
  {4, 8, 12},
  {5, 10, 15}
 }
 int i;

 for(i=0; i<5; i++){
  irekae(dat[0][i], dat[1][i], dat[2][i]);
 }

 for(i=0; i<5; i++){
  printf("%f %f %f \n", dat[0][i], dat[1][i], dat[2][i]);
 }

}


問題5 以下について説明せよ

1)分割コンパイル(複数ファイルの利用)とは何か.その利点は何か.

CまたはC++言語にて,複数のソースファイルを利用したソフトウェア開発をすることがある.
その理由は,
1)機能ごとの関数群を別ファイルにしておき再利用性を上げること,
2)メイン関数のソースを簡潔にして処理内容を明確にすること,
3)デバッグを完了した関数を誤って改変しないよう中身を固定すること,
などがあり,そのために複数に分けるのである.
一度コンパイルしたソースは毎回コンパイルする必要もないので,そのままオブジェクトファイルとして
保持しておき,変更されたソースファイルのみコンパイルするようにすれば,実行ファイルを早く生成
できるという利点もある.

2)計算機解析,シミュレーションについて注意すべきことを説明せよ.
授業で用いた,複素数やフーリエ解析を題材に利用して説明しても良い.

プログラムは間違い(バグ)を含んでいることを留意しておかなければならない.バグとしては,
1) 文法の間違い
2) アルゴリズムが不適切
3) 変数や関数の呼び出しの際,関数同士やポインタ間の関係が意図通りでない
4) 数値の切り捨てや丸めによる誤差が発生する
5)演算の順番によっては,誤差が生じ,乗除によりさらに誤差が蓄積する
等がある.1)はコンパイル時にエラーとなるため発見はしやすいが,2)以降はバグであるかすらわから
ないことがあるため注意の必要がある.
オーバフローを起こして数値が滅茶苦茶になれば間違いであることもわかる,あるいは数値が不連続に
飛ぶような場合も間違いであると分かるが,もっともらしい値を出力も多々ある.
誤差蓄積も程度が小さければ間違いと言えない,あるいはシミュレーション条件によって誤差の出方も
異なることがある,ということを理解しておく必要がある.

本日の講義では,このことについて扱うことにする.