青山学院大学

前期試験 ・ 2009 年 7 月 30 日 4 時限実施 ・ ページ

授業
科目
計算機実習 I 学生番号 学科 学年 組 番 フリ
ガナ
  評点
                   氏名    
担当者 DÜRST, M.J., 松田、
松本、武藤、矢吹

英語の用語 (14 点)

プログラミング一般やプログラミング言語 C において使われる次の英語の用語の日本語訳と説明を書きなさい。日本語訳ではできるだけ片仮名を使わないようにしてください。

array
配列; 同じ型の複数の要素を順番にメモリに配置し、添え字を使って使用できるもの。

floating point number
浮動小数点数; 極めて大きいや小さい数をある程度の精度で計算機内に表現する仕組み。

modulo operator
剰余演算子; a % b で a を b で割っての余りを計算する演算子。

standard output
標準出力; 画面やリダイレクトのファイルへの出力。

actual parameter
実引数; 関数に実際に引き渡される値のこと。

dereference operator
間接演算子; ポインタが指す値を返す演算子

call by value
値渡し; 関数に値そのものを渡し、変更されても元のところに影響がない仕組み。

式の値 (12 点)

次のテーブルの式の値を計算しなさい (i は int の変数)。

番号 式 値 番号 式 値
例 2+3*5 17 例 2+3*5 17
3*0 ? 4 : 5 5 15 & 25 9
0x83 | 5 135 i=19, ++i, i-- 20
'3' - '9' -6        20 - 12-6 2       
0777 1023 (int)2.345E6 2345000
~(~22 & ~33) 55 i = 22.33 22
12 << 3 96 39 >> 2 9

前期試験 ・ 2009 年 7 月 30 日 4 時限実施 ・ ページ

printf の書式 (10 点)

変数 c、d、f、i の後に下記の表の printf 文を実行する。各出力を 1文字ずつ表に記入しなさい。スペースは SP、小数点は DOT と書く。出力が予想不可能の場合、最初の文字のところに @@ と書く。0 の様な文字は全てゼロ。'a' の文字コードの番号は十進数で 97。

char c = 'g';
double d = 33.333;
float f = 20.2;
int i = 15;
番号 printf 文 文字 1 文字 2 文字 3 文字 4 文字 5 文字 6 文字 7 文字 8 文字 9 文字 10
例 printf("%d", i); 1 5
printf("%d", c); 1 0 3
printf("0x%x", i); 0 x f
printf("%04X", i); 0 0 0 F
printf("%5c", c); SP SP SP SP g
printf("%-5d", i); 1 5 SP SP SP
printf("%+d", i); + 1 5
printf("%%d", i); % d
printf("%.3f", f); 2 0 DOT 2 0 0
printf("%.3E", f); 2 DOT 0 2 0 E + 0 1
printf("%.3f", d); 3 3 3 DOT 3 3 0

free 関数 (9 点)

free 関数を使うときに注意すべき点を三つ挙げ、説明しなさい。

必要のなくなったメモリは必ず返さないといけない。そうしないといつかメモリが足りなくなります。

まだ必要のなメモリは絶対返してはならない。するとメモリが再利用される可能性があり、混乱になる。

メモリを返すときには malloc などでもらったポインタ以外で返さない。そうしないもらってもないメモリの部分を「返す」ことになる。

入力の終わりの感知 (6 点)

次の入力関数の場合、入力の終わり (end of file) をどうやって感知できるか説明しなさい。

getchar: int としての戻り値が EOF の場合。

fgets: 戻り値が NULL の場合。

scanf: 戻り値が EOF の場合。

青山学院大学

前期試験 ・ 2009 年 7 月 30 日 4 時限実施 ・ ページ

授業
科目
計算機実習 I 学生番号 学科 学年 組 番 フリ
ガナ
  評点
                   氏名    
担当者 DÜRST, M.J., 松田、
松本、武藤、矢吹

ファイル入出力 (合計 20 点)

プログラムの穴埋め (15 点)

下記は、ファイル "alphabet.txt" から半角文字を一つ読み込み、その ASCII コード番号を "number.txt" に出力するプログラム、及び入出力ファイルの例である。空欄を正しく埋めなさい。

#include <stdio.h>

int main (void)
{
    FILE* fp;
    char c;

    fp = fopen("alphabet.txt","r");
    fscanf(fp,"%c",&c);
    fclose(fp);

    fp = fopen("number.txt","w");
    fprintf(fp,"%d",c);
    fclose(fp);
    return 0;
}

入出力ファイル例

入力ファイル "alphabet.txt": A
出力ファイル "number.txt": 65

エラー処理 (5 点)

"alphabet.txt" が存在していない状態で、上記のプログラムを実行すると、異常終了する。これを避けるためには、プログラムをどのように改良すればよいか書きなさい。

fopen 関数の戻り値が NULL であるかどうかを調べ、
NULL の場合はエラーメッセージを出して、
プログラムを終了するようにする。

typedef の意義 (6 点)

プログラムの中で typedef をどこ、なぜで使うべきなのか説明しなさい。

typedef で複雑の型に別名をつけることが可能。特に構造体の場合にはよくつかわれるが、
構造体限定ではない。別名をつけることでプログラムが細かい具体的な C 言語の型から
応用の分野の用語や概念に抽象化される。それによってより読みやすく、分かりやすくなる。

前期試験 ・ 2009 年 7 月 30 日 4 時限実施 ・ ページ

ポインタ (合計 16 点)

入れ替え関数 swap (6 点)

2つの変数 x, y の中身を入れ替える関数 swap を作りたい。空欄に適切なコードを埋めなさい。

プログラム

void swap (int *x, int *y)
{
    int work;
    work = *x;
    *x = *y  ;
    *y = work;
}

逆順関数 reverse (4 点)

配列 array の中身を逆順に並べ替える関数 reverse を作りたい。空欄に適切なコードを埋めなさい。ただし上記の問で作成した関数 swap を使うものとする。

プログラム

void reverse (int *array, int n)
{
    int i, j;
    for (i=0, j=n-1; i < n/2; i++, j--)
    swap (array+i, array+j); //または &array[i], &array[j]
}

プログラムの実行結果 (4 点)

上記の問で作成した関数 reverse を利用するプログラムを作成した。実行結果を答えなさい。

プログラム

int main (void)
{
    int i;
    int number[5] = { 2, 4, 6, 8, 10};
    reverse (number, 5);
    for (i=0; i < 5; i++)
        printf ("%d, ", *(number+i)); // (A)
    printf ("\n");
    for (i=0; i < 5; i++)
        printf ("%d, ", (*number)+i); // (B)
    printf ("\n");
    return 0;
}
10, 8, 6, 4, 2,     
10, 11, 12, 13, 14, 

優先度 (2 点)

以下の処理は (A) (B) どちらと実行結果が同じになるか: (B)

for (i=0; i < 5; i++)
    printf("%d, ", *number+i);

青山学院大学

前期試験 ・ 2009 年 7 月 30 日 4 時限実施 ・ ページ

授業
科目
計算機実習 I 学生番号 学科 学年 組 番 フリ
ガナ
  評点
                   氏名    
担当者 DÜRST, M.J., 松田、
松本、武藤、矢吹

再帰による配列の最小値の計算 (合計 18 点)

数列 s0, s1, s2,..., sn-1 の最小値を以下のような再帰的な考え方により求めることができる。

  1. 0 以上 n-1 以下の任意の整数 a, b (a≦b) を定義する。
  2. a = b ならば (すなわち、処理対象の整数が一つしかないとき)、sa が求めるべき最小値となるので、sa を戻り値として返す。
  3. a < b ならば、sa と sb の中央の位置を境に数列を二分し、それぞれの最小値を再帰的に求め、そのうち小さい方の値を返す。

プログラムの穴埋め (10 点)

以下は、再帰を用いて最小値を求めるプログラムである。空白を埋めて完成させなさい。

#include <stdio.h>

int min (int s[], int a, int b)
{
    int c, m1, m2;
    if (a == b)
        return s[a];
    c = (a+b)/2;
    m1 = min( s, a, c  );
    m2 = min( s, c+1, b );
    printf("c=%d  m1=%d  m2=%d\n", c, m1, m2);
    return (m1 < m2) ? m1 : m2;
}

int main (void)
{
  	int s[] = {95, 30, 90, 60, 80};
  	printf("minimum=%d\n", min( s, 0, 4 ));
  	return 0;
}

実行結果の穴埋め (8 点)

上記のプログラムを実行したときの結果を完成させなさい。

c=0  m1=95  m2=30
c=1  m1=30  m2=90
c=3  m1=60  m2=80
c=2  m1=30  m2=60
minimum=30

文字コード (6 点)

UTF-8 一文字あたりのバイト数に分けて文字の種類を書きなさい。

  1 バイト: ローマ字 (基本のものだけ)

  2 バイト: アラビア文字、ヘブライ文字、ギリシア文字、「記号付き」ローマ字

  3 バイト: (半角・全角) 片仮名、平仮名、漢字

前期試験 ・ 2009 年 7 月 30 日 4 時限実施 ・ ページ

文字列処理 (16 点)

C言語の標準ライブラリには、文字列の長さを (バイト単位で) 返す関数 strlen が用意されている。この関数と同様の働きをする関数 mystrlen を実装したい。

以下の空白を埋めて、関数 mystrlen とそれを利用するプログラムを完成しなさい。

#include <stdio.h>

// 関数 mystrlen の定義
int mystrlen (const char *str)
{
    int i=0;
    while (str[i])
        i++;
    return i;
}

int main (void)
{
    // 文字列「ABCDE」の長さを求める
    char str[] = "ABCDE";
    printf("%d\n",  mystrlen(str) ); //出力値: 5

    // 文字列「3210」の長さを求める
    printf("%d\n",  mystrlen("3210") ); //出力値: 4

    return 0;
}

制御文の選択 (10 点)

次のそれぞれ二つの制御文をどう使い分ければいいのか詳しく説明しなさい。

for 文と while 文

for 文では初期化、継続条件、「次の一歩」をまとめて一か所に指定できる。 典型的な
使い方は配列の一個一個の要素の処理です。しかし複数の指数を同時に操作したり、
複数の条件を同時にチェクすることも可能です。while 文は継続条件だけが決まった場所に
あります。したがって while 文は初期化が特に必要ない、「次の一歩」が繰り返す
処理の中で行われているなどのときに最適である。回数が分かる時には多くの場合
for で、終了条件だけが分かる時に while が最適。

if 文と switch 文

if 文は else とともに一般的な枝別れの制御う文なのに、switch は特殊なものである。
switch の場合、「整数の定数と等しい」という制約があり、それがないと switch 文が使えない。
逆に switch 文の場合には複数の case で同じ処理をしたり、case を break で終わらなく、
次の case に流れ込む (要注意!)、case 以外を default でし示す機能もあります。
一般的には三つや四つのケース以上で可能であれば switch を使うが、そうでない
ときには if/else を使うべきである。

青山学院大学

前期試験 ・ 2009 年 7 月 30 日 4 時限実施 ・ ページ

授業
科目
計算機実習 I 学生番号 学科 学年 組 番 フリ
ガナ
  評点
                   氏名    
担当者 DÜRST, M.J., 松田、
松本、武藤、矢吹

Q & A フォーラム (16 点)

次の質問 (一部省略) が Q & A フォーラムにだされたので答えなさい。

#include 後にスペースが無くてもコンパイルできるのに、なぜだめでしょうか。
欧米で単語の間にスペースを使うと同様で、ここのスペースはプロのプログラマの常識。
pow(2, n) % n で error: invalid operands to binary % が出たが、なぜ。
pow の戻り値は浮動小数点数だが、% 演算子は整数でしか使えない。
条件文を書いたが、invalid lvalue in assignment のエラーになりました。
== のつもりで = を書いた可能性があります。assignment は代入、lvalue はその目的 (左の値)。
parse error at end of input と出たが、プログラムの終わりに問題は見当たらない。
原因は何かの括弧の閉じ忘れです。プログラムの頭から確認した方がいいです。
macro "getchar" passed 1 arguments, but takes just 0 となった。
getchar の引数の数が 0 なのに引数を一つ渡そうとした。
テストのために diff を使いましたが、出力なしに終わってしまいました。
diff は二つのファイルの違う部分だけ出力するので、出力がないというのはファイルが同じという意味。
int *p; と書くとき、ここの「*」はどんな演算子でしょうか。
宣言・定義の * は演算子ではないが、使用のときに *p と書くと int 型だという意味で参照演算子に近い。
char buffer[3]="end"; で何か問題があるのだろうか。
文字列定数は \0 で終わるので、合計4文字は用意された場所に合わない。

授業へのコメント (合計 6 点)

授業でよかった点、そして改善すべき点などについて教えてください。

よかった点 (何か書いたら 3 点):

[@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@]
[@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@]

改善すべき点 (何か書いたら 3 点):

[@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@]
[@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@]