前期試験 ・ 2013 年 8 月 1 日 4 時限実施 ・ ページ
授業 科目 |
計算機実習 I | 学生番号 | 学科 | 学年 | 組 | 番 | フリ ガナ |
評点 | ||||||||
氏名 | ||||||||||||||||
担当者 | DÜRST, Martin J.、松原、松村、盛川、米澤、白川、高橋 |
プログラミング一般やプログラミング言語 C/C++ において使われる次の英語の用語の日本語訳と説明を書きなさい。日本語訳ではできるだけ片仮名を使わないようにしてください。
string
文字列;0 個以上の文字 (char 型の値) の後に「\0」(ナル文字) を格納した、char 型の配列
expression statement
式文;式の後にセミコロンを続けた形の文
structure
構造体;複数のデータを組み合わせたデータ型
derived type
派生型; 基本的な型から派生された型、例: 配列、ポインタ、構造体、関数
recursive function
再帰的関数、再帰を使った関数、すなわち自己呼び出しする関数
formal parameter
仮引数; 関数の定義中で使われる引数、関数内では変数と同様に振る舞う
indirection operator
間接演算子; ポインタが指す値を返す演算子
call by reference
参照渡し;関数に参照を渡す。呼出し元の変数に影響を与える
side effect
副作用;プログラムの実行による式の計算以外の結果 (入出力、グローバル変数の変更など)
次のテーブルの式の値を計算しなさい。(ヒント: + が << より優先)
番号 | 式 | 値 | 番号 | 式 | 値 |
例 | 2+3*5 |
17 |
例 | 2+3*5 |
17 |
35 / 6 |
5 |
35 | 6 |
39 |
||
62 % 11 |
7 |
35 & 7 |
3 |
||
35 ^ 16 |
51 |
1 + 3, 2 |
2 |
||
2 - 2 ? 9 : 15 |
15 |
0x7A - 0x63 |
23 |
||
55 >> 3 |
6 |
3+5 * 7 |
38 |
||
'9' - '4' |
5 |
(int) 0.345E4 |
3450 |
||
~~27 |
27 |
'a' - 'A' |
32 |
前期試験 ・ 2013 年 8 月 1 日 4 時限実施 ・ ページ
次のプロブラムの断片は、標準入力から文字データを buffer
変数に読み込んで、そこから標準出力へと出力する。空欄を埋めなさい。
char buffer[80]; while((fgets(buffer, 80, stdin)) != NULL){ printf("%s", buffer); }
上記のプログラム断片を含まれるプログラム cat.exe
を使って、ファイル
input.txt
からデータを読み込んで、ファイル output.txt
に書き出すコマンドラインを書きなさい。
cat.exe <input.txt >output.txt
fgets
関数の仕組み (4 点)fgets
関数は「一行入力」と言われています。行の長さによって、上記の断片の挙動を細かく説明しなさい。
fgets の最後の二バイト分は改行とナル文字に使われるので、
行の長さが 78 バイトまでは一行ごとにループが一回回ります。
行の長さが 79 バイト以上では、一回ループが回るごとに 79 バイト分の
データが処理されます。場合によっては最後に改行文字だけの入力になります。
上記のプログラム断片の fgets
関数を一回呼んだ場合、文字コードや文字種によって最大で何文字が読み込まれるのか算出しなさい。
文字コード | 文字種 | 文字数 | 文字コード | 文字種 | 文字数 |
---|---|---|---|---|---|
Shift_JIS | 半角英数字 | 78 | UTF-8 | 半角英数字 | 78 |
Shift_JIS | 全角英数字 | 39 | UTF-8 | 全角英数字 | 26 |
Shift_JIS | 半角カナ | 78 | UTF-8 | 半角カナ | 26 |
Shift_JIS | 全角かな | 39 | UTF-8 | 全角かな | 26 |
Shift_JIS | 漢字 | 39 | UTF-8 | 漢字 | 26 |
Shift_JIS | ギリシャ文字 | 39 | UTF-8 | ギリシャ文字 | 39 |
UTF-8 | ヘブライ文字 | 39 | UTF-8 | ハングル文字 | 26 |
fgets
関数の必要性 (4 点)多くの教科書では fgets
関数のではなく、gets
関数が使われている。gets
関数はなぜ絶対に使ってはいけないのかを詳しく説明しなさい。
gets 関数は fgets 関数と同じように一行入力に使いますが、
読み込む長さの制限がありません。それにより、入力される行が長い
ときに用意されているメモリの領域を超え、隣の変数などを上書きする。それは
Segmentation Fault やウイルスの侵入につながる。
前期試験 ・ 2013 年 8 月 1 日 4 時限実施 ・ ページ
授業 科目 |
計算機実習 I | 学生番号 | 学科 | 学年 | 組 | 番 | フリ ガナ |
評点 | ||||||||
氏名 | ||||||||||||||||
担当者 | DÜRST, Martin J.、松原、松村、盛川、米澤、白川、高橋 |
次のプログラムは、学生の試験成績を管理するプログラムである。 100人分の学生情報と試験成績のデータを入力すると、試験科目ごとの平均点、全科目の平均点、を算出するようにしたい。このプログラムの空欄を埋めなさい。
#include <stdio.h> typedef struct { int number; char name[20]; int japanese; int math; int english; } Student; int main(void) { double total_japanese = 0, total_math = 0, total_english = 0, average_japanese, average_math, average_english, average_overall; Student students[100]; // 入力部分省略 for (i=0; i < 100; i++) { total_japanese += students[i].japanese; total_math += students[i].math ; total_english += students[i].english ; } average_japanese = total_japanese / 100; average_math = total_math / 100; average_english = total_english / 100; average_overall = (average_japanese + average_math + average_english) / 3; // 出力の一部部分省略 printf("全科目の平均点: %5.2lf\n", average_overall); return 0; }
プログラム開発の場合、テストを使うのが非常に大事であることを授業で学んだ。
テストの有効な使用を細かく説明しなさい。
プログラム開発はできるだけこまめに行った方がいいです。細かい変更でも
再度コンパイル、テストをした方がいいですが、そのために手動でテストをするのではなく、
自動でテストした方がいいです。授業で習った方法としては、入力データをファイルに用意し、
期待の出力のデータもファイルで用意し、diff で自動的に期待と実際の差異をとる。
テストでは簡単な使用例だけではなく、様々なケース (例: 長い入力、空の入力)
を含め用意した方が良い。一部の入力でしか動かないプログラムは使い物になりません。
さらに、プログラムが機能的にできあがったところでも、読みやすさや更なる変更・発展のために
書き直す (refactoring の) 場合、テストを使って安心して効率よく進むことが可能。
前期試験 ・ 2013 年 8 月 1 日 4 時限実施 ・ ページ
swap
関数) (11 点)次の左側のプログラム (A) は、swap
関数 (2 つの値を交換する関数) の典型的な間違い例である。
swap
関数を呼び出した際に、値が正しく交換されるように訂正した右側のプログラム (B) の空欄を埋めなさい。
また、2 つのプログラムの実行結果の空欄を埋めなさい。
2つのプログラム例:
/* プログラム (A) */ /* 間違った swap 関数 */ #include <stdio.h> void swap(int a, int b) { int tmp; tmp = a; a = b; b = tmp; } int main(void) { int x=1, y=2; printf("x = %d, y = %d\n", x, y); swap(x, y); printf("x = %d, y = %d\n", x, y); return 0; } |
/* プログラム (B) */ /* 正しい swap 関数 */ #include <stdio.h> void swap(int *a, int *b) { int tmp; tmp = *a; *a = *b; *b = tmp; } int main(void) { int x=1, y=2; printf("x = %d, y = %d\n", x, y); swap(&x, &y); printf("x = %d, y = %d\n", x, y); return 0; } |
プログラム (A) の実行結果: x = 1, y = 2 x = 1, y = 2 |
プログラム (B) の実行結果: x = 1, y = 2 x = 2, y = 1 |
次のプログラムは配列中の値の最大値を求め、その値のインデックス(その値が配列の何番目にあるか)を返す関数とその使用例である。
右側の「int find_max(int array[], int size)
」関数を正しく機能するように埋めなさい。
プログラム (2 段組):
#include <stdio.h> /* 配列中の最大値を探す関数 */ /* 第1引数は配列の先頭ポインタ */ /* 第2引数は配列のサイズ */ int find_max(int array[], int size); int main(void) { int n[] = {3, 12, -2, 4, 25, 9, 10}; int s = 7; int id; id = find_max(n, s); printf("Max value is %d\n", n[id]); return 0; } |
int find_max(int array[], int size) {int i = 0; int max = array[0]; int max_i = 0; for (i=1; i < size; i++) { if(array[i] > max) { max = array[i]; max_i = i; } } return i;} |
前期試験 ・ 2013 年 8 月 1 日 4 時限実施 ・ ページ
授業 科目 |
計算機実習 I | 学生番号 | 学科 | 学年 | 組 | 番 | フリ ガナ |
評点 | ||||||||
氏名 | ||||||||||||||||
担当者 | DÜRST, Martin J.、松原、松村、盛川、米澤、白川、高橋 |
下記のプログラムは組合せ(combination)nCrを計算するプログラムであるが、コードが不足しているため正しく動作しない。 正しい計算結果を出力するためには、どこにどのようなコードを追加すれば良いか、答えなさい。 複数箇所の修正が必要な場合は、全て答えなさい。
挿入箇所 (行番号と詳細) | 挿入内容 |
1行目と2行目の間 | include <stdlib.h> |
2行目と3行目の間 | long factorial(int n); |
15行目と16行目の間 | return product; |
20行目と21行目の間 | long ans; |
28行目()の中 | n, r |
1) #include <stdio.h> 2) 3) long combinations(int n, int r) 4) { 5) return factorial(n) / factorial(r) 6) / factorial(n-r); 7) } 8) 9) long factorial(int n) 10) { 11) long product = 1; 12) int i; 13) 14) for (i = 2; i <= n; i++) 15) product *= i; 16) } 17) 18) int main(void) 19) { 20) int n, r; 21) 22) printf("Input n and r: "); 23) scanf("%d %d", &n, &r); 24) if (n < 0 || r < 0 || n < r){ 25) printf("不正な入力です。プログラムを終了します。"); 26) exit(0); 27) } 28) ans = combinations(); 29) printf("nCr= %ld\n", ans); 30) 31) return 0; 32) }
上記のプログラムの factorial
関数を再帰的関数の形式で書き直しなさい。ただし上記の問題の訂正箇所に留意し、正しく動作するよう書き直すこと。
long factorial(int n) {
if (n <= 1) return 1; else return factorial(n-1) * n;
}
前期試験 ・ 2013 年 8 月 1 日 4 時限実施 ・ ページ
プラン名 | 基本料金 (円) | 通話料 (円/分) | 無料通話分 (円) |
---|---|---|---|
ときどきプラン | 980 | 30 | 1000 |
おしゃべりプラン | 1980 | 20 | 2000 |
以下のプログラムでは、入力された1ヶ月あたりの通話時間 (分) に基いて、 2つの携帯電話の通話料金のプラン (右の表参照) を比較し、お得な方のプランの名前を出力する。 いずれのプランでも、その月の通話料が無料通話分に収まる場合は基本料金のみ、そうでない場合、 基本料金と、超過した分の通話料を合わせた金額を支払う。
// main.cpp
#include <stdio.h>
#include "Plan.cpp"
int main(void)
{
Plan a = Plan((char *)"ときどきプラン",
980, 30, 1000);
Plan b = Plan((char *)"おしゃべりプラン",
1980, 20, 2000);
int mins;
printf("1ヶ月あたりの通話時間(分): ");
scanf("%d", &mins);
Plan better_plan = a.compare(b, mins) ? a : b;
printf("「%s」の方がお得です。\n",
better_plan.get_name());
return 0;
}
|
// Plan.cpp #include "Plan.h" Plan::Plan(char *n, int mc, int o, int am) { name = n; monthly_cost = mc; overage = o; anytime_mins = am; } char* Plan::get_name() { return name; } // 月ごとの支払い総額を算出 int Plan::total_cost(int minutes) { int call_charges = overage * minutes; if(call_charge > anytime_mins) return monthly_cost + call_charges - anytime_mins; else return monthly_cost; } // 別のプランと月ごとの支払い総額を比較 int Plan::compare(Plan other, int m) { int my_total_cost = total_cost(m); int other_total_cost = other.total_cost(m); return my_total_cost <= other_total_cost; } |
// Plan.h
class Plan {
char *name; // 通話プラン名
int monthly_cost; // 基本料金 (円)
int overage; // 通話料 (円/分)
int anytime_mins; // 無料通話 (円)
public:
Plan(char *n, int mc, int o, int am);
char* get_name();
int total_cost(int m);
int compare(Plan other, int minutes);
};
|
Plan.h
より、Plan
クラスのコンストラクタの宣言を抜き出しなさい。 (2 点)
Plan(char *n, int mc, int o, int am);
コンストラクタの役割および実行される段階について答えなさい。 (2 点)
コンストラクタはクラスのインスタンスが生成される際に実行され、初期化を行う。
C における構造体と、C++ におけるクラスの大きな違いを2つ挙げなさい。 (4 点)
オブジェクト指向における「カプセル化」の概要とその利点について説明しなさい。 (3 点)
カプセル化は、インスタンスがメンバ変数に持つデータをクラスの外部から保護することを指す。 カプセル化を行うことで、プログラムの各部分の独立性を高め、クラス内部での変更が容易になる。
前期試験 ・ 2013 年 8 月 1 日 4 時限実施 ・ ページ
授業 科目 |
計算機実習 I | 学生番号 | 学科 | 学年 | 組 | 番 | フリ ガナ |
評点 | ||||||||
氏名 | ||||||||||||||||
担当者 | DÜRST, Martin J.、松原、松村、盛川、米澤、白川、高橋 |
次の演算子それぞれの意味 (又は、存在しない場合その旨) を示しなさい。
番号 | 演算子 (単項) | 説明 | 番号 | 演算子 (二項) | 説明 | 番号 | 演算子 | 説明 |
---|---|---|---|---|---|---|---|---|
& | アドレス演算子 | & | ビットごと論理積 | && | 論理積 | |||
* | 間接演算子 | * | 掛算 | ** | 存在しない | |||
- | 符号反転 | - | 引き算 | -- | ディクレメント | |||
< | 存在しない | < | 小なり | << | 左シフト | |||
+ | (ほぼ)効果無し | + | 足し算 | ++ | インクレメント | |||
| | 存在しない | | | ビットごと論理和 | || | 論理和 |
プログラムを読みやすくするための三つアドバイスとその理由を書きなさい。(9 点)
なぜプログラムの読みやすさが大事なのかの理由を二つ列挙しなさい。(4 点)
この授業で一番分かりにくかったことを書きなさい。(具体的に書いてあれば内容にかかわらず 3 点)
@@@@
この授業で一番勉強になったことを簡単に説明しなさい。(具体的に書いてあれば内容にかかわらず 3 点)
@@@@