Document

プログラミングC 平成27年度中間試験
平成27年11月20日 3限
注意事項

問題用紙は表紙を含めて両面刷り6枚(12ページ)である。解答用紙は片面刷り4枚である。試
験開始と共に問題用紙・解答用紙を確認し、乱丁・落丁などあれば直ちに申し出る事。

解答用紙の各ページそれぞれに学籍番号と氏名を記入すること。

解答時間は13:20~14:40の80分間とする。

解答開始の指示があるまで、表紙の注意を良く読む事。ただし中の問題を見てはならない。

途中退席は開始後40分 (14:00)まで認めない。

筆記具のみを机の上に置くことができる。

机の中には一切ものを入れてはならない。

携帯電話は電源を切り、鞄の中に入れておくこと。着信音が鳴った場合は不正とみなす。

演習室で受験する学生は、必ずワークステーションからログアウトし、ディスプレイの電源を消し
ておかなければならない。

すべての不正行為に対して断固たる処置を行う。

なお、下例のように、実行例を表示する際にはコンピュータの表示は普通の文字、キーボードからの
入力は太字斜体にて表示する。
% ./a.out
Enter your name -> Aizu Taro
-1-
問題 1
以下のプログラムの出力を答えよ。
解答の際、Solaris か Mac のどちらかのシステムを想定し、解答欄の想定システムに○を付けて選択す
ること。(選択していない場合は、システムによって出力が変わる問題の採点がされない)
。
プログラム
#include <stdio.h>
#include <string.h>
int main()
{
char str1[16]= "Science";
char str2[] = "Engineering";
char *edu[] = {"Programming",
"English",
"Mathematics"};
char *p;
int i;
printf("(1)
printf("(2)
printf("(3)
printf("(4)
%d\n",
%d\n",
%d\n",
%d\n",
sizeof(str1));
sizeof(str2));
sizeof(edu));
sizeof(edu[0]));
printf("(5) %d\n", strlen(str1));
printf("(6) %d\n", strlen(edu[0]));
p = str1;
printf("(7) %s\n",
p+3);
printf("(8) %c\n", *(p+1));
printf("(9) %c\n", *p+1);
p=str2+5;
printf("(10) %s\n",p);
printf("(11) %c\n",p[4]);
str1[3] = '\0';
printf("(12) %s\n",str1);
}
return 0;
-2-
問題 2
問2-1
下記のプログラムの出力を解答せよ。
プログラム
#include <stdio.h>
int accm(int);
int num;
int main(){
int i,j=1;
}
num=1;
for(i=0;i<4;++i){
j = accm(j);
}
return 0;
int accm(int in){
static int s=0;
int i=0;
s+= in;
i+= in;
printf("in=%d, s=%d, i=%d, num=%d\n",in, s, i, num);
num+= 2;
}
return in+1;
問2-2
上記のソースコードで使われている変数(num, main 中の i,j と accm 関数中の in,s,i)について、
以下の条件に該当する変数全てに○を付けなさい。なお、答えは1つとは限らない。
(1) 自動変数
(2) 静的変数
(3) 外部変数
(4) 関数の仮引数
(5) 生存期間が関数 accm の実行中のみである変数
(6) 関数内を実行中に accm から参照できる変数
-3-
問題 3
学籍番号と成績からなるファイルがある。以下は、このファイルをコマンドライン引数に指定して読み
込み、上位者 5 名を降順(大きい順)に並べ、表示するプログラムである。配列 list 内には、成績上
位者の要素番号が格納され、list[0]が最高点の人の要素番号、score[list[0]]がその点数を示すこ
とになる。list の内容は、i 番目の人の成績と list 内の成績上位者の点数とを比較し、i 番目の成績
が大きい場合、ins_list 関数を利用し、list のその場所に i を挿入することで作成している。実行例
やプログラム中のコメントを参考に、下線部を埋めて完成させなさい。なお、データの最大数と表示す
る上位者の人数はそれぞれマクロ MAX と NO で指定され、エラーメッセージや使用方法は標準エラー出
力に出力するものとする。また、同じ番号の下線部には同じ内容が入る。
実行例
% cat score.dat
s27001 43
s27002 54
s27003 86
s27004 72
:
:
% ./a.out
Usage : ./a.out datafile
% ./a.out score.dat
No.1 : s27012 91
No.2 : s27015 89
No.3 : s27003 86
No.4 : s27011 84
No.5 : s27007 83
%
プログラム
#include <stdio.h>
#include <stdlib.h>
#define MAX 300
#define NO 5
void ins_list(int *, int, int);
int main(int argc, char *argv[])
{
FILE *fp;
char id[MAX][10]; /* 学籍番号 */
int score[MAX]; /* 点数 */
int list[NO]; /* 成績上位者の要素番号が入る(降順) */
int i,j,k,n; /* 一時変数(i,j,k)と読み込んだデータ数(n) */
/* データファイルが指定されているかチェック */
if (____(1)____) {
fprintf(____(2)___, "Usage : ./a.out datafile\n");
exit(1);
}
-4-
/* ファイルを開く */
fp=fopen(____(3)____,"r");
if (____(4)____) {
fprintf(____(2)____, "file open error:%s\n", ____(3)____);
exit(2);
}
/* データの読み込み */
for (i=0; i<MAX; i++) {
if (fscanf(fp,"%s%d",________(5)________)==EOF) break;
}
n=i; /* 読み込んだデータの個数を設定 */
fclose(fp);
/* 成績上位者リストの初期化 */
/*
(初期値として0番目の人が上位者とされる) */
for (j=0; j<NO; j++) list[j]=0;
/* main process */
for (i=1; i<n; i++ ) /* 1番目から処理を開始 */
{
for (j=0; j<NO; j++) {
k=list[j]; /* 上位者の要素番号 */
if (________(6)________) { /* 上位者リストの成績とを比較 */
________(7)________; /* list 配列中の j 番目に i を挿入する */
break;
}
}
}
/* 成績上位者の表示 */
for (j=0; j<NO; j++) {
k=list[j]; /* 上位者の要素番号 */
printf("No.%d : %s %3d\n",j+1, ________(8)________);
}
}
return 0;
/* list 配列の st 番目に index を挿入する関数 */
void ins_list(int *list, int st, int index)
{
int j;
}
/* 挿入するために st 以降の要素を後ろにずらす */
for (________(9)________ j--) {
list[j] = ________(10)________;
}
list[st]=index; /* 挿入 */
-5-
問題 4
下記のプログラムの出力値を解答せよ。2 次元配列内は隙間なく格納されていることを保証する。
プログラム
#include <stdio.h>
#define NROW 3
#define NCOL 6
int main(){
int num1[10] = {5, 4, 3, 2, 1, 9, 8, 7, 6, 5};
int num2[NROW][NCOL] =
{{2, 4, 6, 8, 10, 12},
{3, 2, 1, 3, 2, 1},
{1, 2, 3, 4, 5, 6}};
int *p, *q, i, s=0;
p = &num1[4];
printf("(1) %d\n", *p);
printf("(2) %d\n", *p++);
printf("(3) %d\n", *(p-3));
printf("(4) %d\n", *(p+2));
p+=2;
printf("(5) %d\n",*p);
printf("(6) %d\n",*p+2);
p = &num2[2][0];
printf("(7) %d\n", *(p+4));
printf("(8) %d\n", *(p-2*NCOL));
p = &num2[0][2];
printf("(9) %d\n", *(p+4));
printf("(10) %d\n", *++p);
printf("(11) %d\n", *p+3);
}
p = num1;
q = &num2[1][3];
for ( i=0; i<6; i++ ){
s += *p + *q;
p++;
q++;
}
printf("(12) %d\n", s);
return 0;
-6-
問題 5
標準入力から英単語を読み取り、単語を表示するプログラムを作成する。このプログラムは、英単語をす
べて読み取った後、文字数が最も多い単語とその文字数を表示し、さらに最も長い単語以外のすべての
単語を表示する。この際、

入力される単語の数は 1024 単語以下

入力される単語は英小文字で構成されている

入力される単語は空白で区切られている

入力される単語の長さは 255 文字以内

最も長い単語が複数ある場合、最初に現れた単語を採用する

Ctrl-d(または EOF)が入力されたら終了
とする。
実行例を参考にしながら空欄を埋め、このプログラムが目的の動作をするよう、下線部を埋めよ。
実行例
%./a.out
a class of the students by the students for the students
Ctrl-d
Longest word: students
Length: 8
a class of the by the for the
%./a.out
a class of the teachers by the teachers for the students
Ctrl-d
Longest word: teachers
Length: 8
a class of the by the for the students
プログラム
#include <stdio.h>
#include <string.h>
#define MAXWORD 1024
#define MAXCHAR 256
int main(){
int
char
char
int
int
int
maxlen=0;
/*単語の最大長*/
maxstr[MAXCHAR];
/*最大長の単語*/
words [MAXWORD][MAXCHAR]; /*標準入力から読み込んだ単語*/
len;
/*調査する単語の長さ*/
wordno=0;
/*読み込んだ単語の数*/
i;
maxstr[0]=__(1)__; /*文字列を空にしておく*/
/* 標準入力から単語を読み込む */
while(scanf("%s",words[wordno])!=EOF){
____(2)____;
}
-7-
/*最長かつ最初に現れた単語を記録する */
for(i=0; i<wordno; ++i){
len = ____(3)____;
/* len に i 番目の単語の長さを格納 */
if(len>maxlen){
______(4)______; /* maxstr に i 番目の単語を格納 */
______(5)______;
}
}
/*最長かつ最初に現れた単語を表示*/
printf("Longest word: %s\n",maxstr);
printf("Length: %d\n",maxlen);
for(i=0; i<wordno; ++i){
/*最長かつ最初に現れた単語でなければ表示*/
if(______(6)______){
printf("%s ", words[i]);
}
}
printf("\n");
}
return 0;
-8-
問題6
英文文章のテキストファイル spim.txt を読み、そのテキスト中の各母音と子音の出現数を表示するプロ
グラムを作成する。母音とはアルファベットの[a, i, u, e, o]のことであり、子音とは母音以外のアル
ファベットのことである。大文字小文字は区別しないこととする。この問題では引数を大文字から小文
字に変換して返す、ライブラリ関数 tolower()を使う。下線部を埋めプログラムを完成させよ。
実行例
% ./a.out
a:14
i:14
u:7
e:15
o:12
Consonant:106
%
[spim.txt]
SPIM/SAL is a port, to the Apple Macintosh Personal Computer, of SPIM, a MIPS
R2000/3000 simulator that was written by James Larus for instructional use at the
University of Wisconsin Computer Sciences Department.
プログラム
#include
#include
#include
#include
<stdio.h>
<ctype.h>
<stdlib.h>
<string.h>
/* tolower のために include */
/* exit のために include */
/* strlen のために include */
#define MAX 1000
_____(1)_____; /* プロトタイプ宣言 */
char vowel[5] = {'a', 'i', 'u', 'e', 'o'}; /* a i u e o で初期化 */
int main(){
int i, vowelConsCnt[6] = {0, 0, 0, 0, 0, 0};
char c,words[MAX];
FILE *fp;
/* a i u e o と子音の出現数 */
fp = fopen(_____(2)_____);
if(fp == NULL){
printf("FileNotFound.\n");
exit(1);
}
for(i = 0; i < MAX; i++){ /* 1 文字づつ配列 words に格納する */
if(fscanf(_____(3)_____) == EOF) break; /* EOF になるまで 1 文字読む */
words[i] = tolower(c);
/* 小文字に変換し、格納する */
}
___省略____
/* 文字列 words の最後尾を null 文字とする */
_____(4)_____;
/* 関数 VowelCount の呼び出し */
-9-
for(i = 0; i < 5; i++){
/* 結果を出力する */
printf(_____(5)_____);
}
printf("Consonant:%d\n",vowelConsCnt[5]);
fclose(fp);
return 0;
}
/*
母音かどうかを調べ、カウントする関数
第 1 引数: 調べる文字配列 第 2 引数: 各母音と子音の出現数(結果)
各母音の出現数は[0]が a, [1]が i, [2]が u, [3]が e, [4]が o, [5]が子音の出現数である。
*/
void VowelCount(char* str, int* vowelConsCnt){
int i, j, cnt, flag;
cnt = _____(6) _____;
/* 文字配列の長さを求める*/
}
for(i = 0; i < cnt; i++){
flag = 0; /* 母音かどうかを判定するフラグを初期化 */
for(j = 0; j < 5; j++){ /* 文字が母音かどうかを調べる */
if(_____(7)_____){
vowelConsCnt[j]++;
flag = 1;
}
}
if(_____(8)_____){
/* 母音でなかった時 */
if(_____(9)_____){
/* 文字がアルファベット小文字ならば */
vowelConsCnt[5]++;
}
}
}
- 10 -
問題 7
以下は、2人のプレイヤーで行う英単語のしりとりゲームのプログラムである。プレイヤー1、2がそ
れぞれ交互に単語を入力するが、辞書に存在しない単語や既に入力済の単語、しりとりになっていない
単語については得点にならず、次のプレイヤーに入力権が移る。単語はすべて小文字で入力され、最初は
apple から始まる。Ctrl+d が入力された時の得点に応じて勝敗が表示されるが、プログラムには複数の
間違いがあり、正しくコンパイル/実行ができない。
プログラム中のコメントも参考に、誤りを修正し、完成させなさい。ただし、変数宣言および表示文に
は間違いがないものとする。なお、修正箇所は最小行数の変更とし、
「行番号 修正後の記述」のように
書くこと(行の追加は認めない)
。
(例: 「20行目 if (a==b) { 」
)
プログラム
1 : #include <stdio.h>
2 : #include <string.h>
3 : void dict_in(void);
/* 辞書データの初期化(定義省略) */
4 :
/* 外部変数 dicts[][]に辞書データが入る*/
5 : int dict_check(char *);
/* 辞書にあるかチェック(定義省略) */
6 : int word_check(char *);
/* 入力済単語チェック */
7 : int chain_check(char *);
/* しりとりのチェック */
8 : void next(int *, int *, int); /* 得点加算と次プレイヤ指定 */
9 :
10 : char dicts[30000][30];
/* 辞書データ */
11 : char words[100][30]={"apple"}; /* 入力済の単語 */
12 : int dictno, wordno=1; /* dicts と words の実データ数 */
13 :
14 : int main()
15 : {
16 :
char str[128];
17 :
int i, player=0, score[2]={0,0}, point;
18 :
/* player=0,1 でプレイヤー1、2を示す。score はそれぞれの累積得点 */
19 :
20 :
dict_in(); /* 辞書データの初期化 */
21 :
while(1) {
22 :
point=0; /* 得点の初期値 */
23 :
printf("Player%d : %s に続く単語を入力して下さい: ",player+1,words[wordno-1])
24 :
if (scanf("%s",str)!=EOF) break;
25 :
if (dict_check(str)==0) { printf("辞書には無い単語です\n");
26 :
} else if (word_check(str)==1) { printf("既に出た単語です\n");
27 :
} else if (chain_check(str)==1) {
28 :
printf("正しい\n");
29 :
words[wordno]=str; /* 入力済単語に登録 */
30 :
wordno++;
31 :
point=1;
32 :
} else {
33 :
printf("間違いです\n");
34 :
}
35 :
next(player, score, point); /* 得点を加算し、次のプレイヤーにする */
36 :
}
- 11 -
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
printf("\nPlayer1: %d 点, Player2: %d 点\n", score[0],score[1]);
if (score[0]<=score[1]) printf("Player1 の勝ち\n");
else if (score[0]>score[1]) printf("Player2 の勝ち\n");
else printf("引き分け\n");
}
return 0;
/* 既に入力済のとき、1 を返す。それ以外は 0 */
int word_check(char *str)
{
int i;
for (i=0; i<wordno; i++) {
if (strcmp(str, words[i])==0) break;
}
if (i<wordno) return 1;
return 0;
}
/* 点数加算と次のプレイヤーにする */
void next(int *player, int *score, int point)
{
score[player]+=point;
player=(player+1)%2;
}
/* しりとりが正しければ 1、間違いなら 0 を返す */
int chain_check(char *str)
{
int k;
k=strlen(words[wordno-1]);
if (words[wordno-1]==str) return 1;
return 0;
}
- 12 -