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

----------

問題110x4

1.1
構造体と共用体の違いを述べよ.

(解答)

構造体
異なる型の変数をひとまとめにして同時に扱うためのデータ型であり、宣言した変数の分だけメモリ空間が
確保される。
配列のように同じ型のデータ列でなければならないという制約がなくなる、複数のデータ型を構造体として
列挙して宣言すれば、構造の決まったデータ処理をする上で扱いやすいものとなる特徴がある。
構造体を配列やポインタとして宣言し利用することもできる点も付記しておく。
例えば、以下のように宣言する。

struct kouzou{
       int n;
       char name[10];
       double value;
};

と宣言すれば、n[4バイト]name[1×10バイト]value[8バイト]で合計22バイト分のデータ列がメモリ内
に確保される。
そして、一つのデータとしては、nname[10]valueがセットで扱われることとなり、各値
はそれぞれアクセスすることとなる。

共用体
異なる型の変数をひとまとめにして場合によって使い分けて扱うためのデータ型であり、宣言した変数の一番
大きいバイト数の分だけメモリ空間が確保される。

変数のように同じ型のテータでなければならないという性質がなくなる、複数の型のデータを共用体を用いて
宣言すれば、型により処理が異なるデータ処理をする上で扱いやすいものとなる特徴がある。
共用体を配列や
ポインタとして宣言し利用することもできる点も付記しておく。

例えば、以下のように宣言する。

union kyouyou{
       
int n;

       char name[10];
       double value;
};

と宣言すれば、n[4バイト]name[1×10バイト]value[8バイト]の中で一番大きい10バイトのメモリが確保
される。
そして、一つのデータとしては、nname[10]valueのどれかで扱われることとなり、各値を同時に
アクセスすることはできない。

1.2
C言語プログラミングにおいて「ポインタ」機能が必要となるのはどのような場面か.具体的に記せ.

(解答)

ポインタを利用するメリットやその効果は以下のものが挙げられる。

1.ある関数の中で宣言したデータを他の関数において同じデータを使いまわしたい場合に有効である。
特に大きな配列や構造体である時は、データ構造そのものをそのまま使いたい。

2.メモリ内に入れたデータ列を動かすことなく、データの順番を入れ替える処理をしたい場合に有効である。
データ数が多く、メモリ内で動かすことに意味がない場合、データのありかだけわかればよいのでアドレス
だけを参照する。

3.ある関数で処理した複数の値を返したい、別の関数で利用したい場合に有効である。戻り値(返り値)の
ように1つの値しか返せないという問題が解消する。

4.データの大きさ、中身が不明確、あるいはあまり使われないことが予想される場合に有効である。
格納されるデータの型が不確定であったり変化する場合、ひとまずアドレスだけを確保しデータ超に応じて
メモリを確保する。

これらを用いることの効果は、それぞれ、以下のものが対応する.

.処理の高速化、膨大なメモリ消費の抑制
.処理の高速化
.関数の移植性、再利用性
.膨大なメモリ消費の抑制

よって,ポインタで記述することで,以上の効果が見込まれる場合,ポインタを積極的に利用することが良い
と考えられる.

1.3
以下の中からバイナリファイルをすべて選び,記号(a-g)を記せ.括弧内は拡張子である.

a. 実行ファイル(.exe)
b.ソースファイル(.cpp)
c. Wordファイル(.docx)
d. Excelファイル(.xlsx)
e.カンマ区切りファイル(.csv)
f.メイクファイル, Makefile
g. jpeg画像ファイル(.jpeg, .jpg)

(解答)

バイナリファイルとは,テキスト(ASCII)ファイル以外と考えてよい.
汎用的に利用できる文字に関するテキスト(ASCII)コードに対し,各ソフトウェアに対応した2進数コード列で
示されるファイルを探せばよい.

バイナリファイルは,実行ファイル,Wordvファイル,Excelファイル,jpegファイルである.
テキストファイルは,ソースファイル,カンマ区切りファイル,メイクファイルである.

1.4
演習で使用しているborland c/c++コンパイラの役割について,以下の単語をすべて用いて説明せよ.
(ソースファイル,CPU,実行ファイル,翻訳,文法エラー)

(解答)

プログラム作成にあたり,プログラマは[ソースファイル]を記述するがこれはテキストファイルであり,その
ままの状態で[CPU]は命令を理解できない.
コンパイラはこの[ソースファイル]を[翻訳]し,記述等に問題があれば[文法エラー]として扱い,これを
エラーメッセージを表示し,プログラマに知らせる機能を持つ.
もし問題がなければ,翻訳したものをオブジェクトファイルに」変換し,ヘッダファイルやライブラリとの関連
性を反映するためのリンクという作業を行い,[CPU]が実行可能な[実行ファイル]を生成する.

----------

問題220点)
構造体を用いて成績データの処理を行うプログラムを作りたい.

2.1
一人分の氏名(最大で全角10文字,全角は1文字あたり2バイト),点数(整数),判定(S,A,B,C,Fのうちの
どれか1文字)の3つの変数からなる構造体を定義せよ.構造体の定義部分のみ解答すればよい.

(解答)

struct hantei{
       char name[20]; /*氏名 文字列*/
       int score;             /*得点 数値*/
       char result;   /*判定 文字*/
}

解説

上記のように宣言すれば,構造体が記述できます.
注意点は,文字列に関しては配列で示す必要があることですが,換言すれば,構造体の中に,変数と配列を混在
させることも可能です.

2.2
この2.1で定義した構造体を用いて10000万人分のデータを保存するためには,最低何バイトのメモリーが必要と
なるか.ただし,データ圧縮は行わないとする.

※試験中,上記記述に関して訂正あり
誤) 10000万人分
正) 10000人分

(解答)

一人当たり,氏名文字列2×10バイト,得点数値4バイト,判定文字1バイトで25バイトを要する.
10000人であれば,250000バイトのメモリを要することとなる.

----------

問題320点)
変数a, b, c, dがある.(a+b)/c d乗の計算を行う関数funcを作成したい.a,b,cは実数,dは正の整数とする.

3.1
上記の計算を行う関数を作成せよ.以下の関数部分のみ解答すればよい.

float func( ? ? ? )
{
       ...
       ...
       
       return ???;
}

(解答)

float func(double a, double b, double c, int d){
       return (float)(pow(((a+b)/c), (double) d));
}

解説

冪乗の計算をするにはmath.h内の関数powを利用するが,引数,返り値ともdouble型となっているため,
関数funcの引数はdouble型としています.
関数funcfloat型として定義されているので,念のためキャストを行っています.

dは整数型であるため,powの引数にするにはキャストを行っておく必要があります.

3.2
main関数中でa,b,c,dをキーボードから入力し,上記の関数を呼び出し,演算結果を画面に表示するプロ
グラムを作成せよ.

(解答)

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

float func(double, double, double, int);

main(){
       double a, b, c;
       int d;
      
       printf("This software calculates pow(((a+b)/c), d).");
       printf("\n Input a=?");
       scanf("%lf", &a);
       printf("\n Input b=?");
       scanf("%lf", &b);
       printf("\n Input c=?");
       scanf("%lf", &c);
       printf("\n Input d=?");
       scanf("%d", &d);

        printf("\n The result of pow(((a+b)/c), d) is= %f", func(a, b, c, d));
}

----------

問題420点)
要素数が n個の実数型配列 aがあり,配列の中身を一つずつ移動させたい.(ローテーションと言う)
即ち,a[0]a[1]a[1]a[2], ..., a[n-1]a[0]とする

4.1
配列 aをローテーションする関数を作成せよ.引数としてポインタ変数と要素数を受け取ること.

void rotate( ? ? ? )
{
       ...
       
  ? ? ? ?
}

(解答)

void rotate(double *p, int n){

        double tmp;

       tmp = p[n-1]

        for(i=0; i<n-1; i++){
               p[i+1] = p[i];
       }

        p[0] = tmp;

}

解説

授業もしくは例題として用いられる二つの変数の入れ替えと同様のアルゴリズムとなっています.

用意された配列に関してポインタ配列を引数とするので double *pとしています.また,以下のように
記述しても同義語となっています.これはシンタックスシュガーと呼ばれ,プログラムを理解しやすく
するために用いられる言語仕様です.

voit rotate(double p[], int n)

どちらで記述しても構いません.

4.2
main関数内にて配列 a[5] = {1,2,3,4,5};として,rotate関数を利用するプログラムを作成せよ.
確認のために,rotate前後の配列の中身を画面に表示し確認するようにすること.

(解答)

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

void rotate(double*, int);

main(){
       double a[]={1, 2, 3, 4, 5};    /*宣言と配列内の初期化*/
       int n = 5;                                    /*配列内要素数*/
       int i;

        printf("The initial values of the array are; \n");

        for(i=0;i<n;i++){                       /*配列を表示*/
               printf("a[%d] -> %f \n");
       }

        rotate(a, n);                           /*関数を実行*/

        printf("The result values are; \n");

        for(i=0;i<n;i++){                       /*並べ替えた配列を表示*/

                printf("a[%d] -> %f \n");

        }
}

上記関数を記述


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