レポート見本 1

データ構造とアルゴリズム I レポート課題

題名
関数とポインタ
学籍番号
04kc999
氏名
坂本直志

課題

課題 1-1

次の条件を満たす関数 dispArray() を作りなさい。

  1. 入力は整数型のポインタ
  2. 入力されたポインタに対して、順に格納されている正の整数を 10 個ずつ 表示する。
  3. 入力に -1 が入っていたら終了する

例えば整数型の配列 a[] が 1 から 15 まで順に入っていて、最後に -1 が入っ ている時、dispArray(a) は次のような出力をする。

1 2 3 4 5 6 7 8 9 10
11 12 13 14 15

課題 1-2

次の条件を満たす関数 rotate() を作りなさい。

  1. 入力は整数型のポインタ
  2. 入力データはポインタから順に正の整数が並び、最後に -1 の値で終了す る
  3. この関数は入力されたポインタに対して、一番最後の正の整数値を 先頭に移動し、残りのデータは一つずつ後ろにずらす。

例えば 1, 2, 3, -1 という配列の先頭番地を rotate() に与えると 2, 3, 1, -1 となります。

課題 1-3

課題 1-1, 1-2 で作成した dispArray(), rotate() に対して次のプログラム を動かし結果を報告しなさい。

#include <stdio.h>
void dispArray(int *p);
void rotate(int *p);
#define N 99
main(){
  int *a[5];
  int b[]={-1};
  int c[]={1,-1};
  int d[]={1,2,3,-1};
  int e[N+1];
  int i,j;
  for(i=0;i<N;i++){
    e[i]=i;
  }
  e[N]=-1;
  a[0]=b; a[1]=c; a[2]=d; a[3]=e; a[4]=NULL;
  for(i=0;a[i]!=NULL;i++){
    dispArray(a[i]);
    for(j=0;j</*学籍番号の下 3 桁*/; j++){
      rotate(a[i]);
    }
    dispArray(a[i]);
  }
}

基礎知識

ポインタ

C 言語では変数の格納されている番地を扱うことができる。 変数名の前に & を付けると、その変数の番地を意味する。 また、変数の番地を取り扱う変数も用意されている。 そのような変数をポインタと言う。 ポインタは格納される値の型で区別される。 int の値が入る変数のポインタは int 型のポインタなどと言う。 そして int 型のポインタの宣言は int *ポインタ名 のよ うにする。 ポインタに対して、その番地に入っている値は*ポインタ名で表す。 以下に簡単な例を示す。


int x, *y;
x=1;
y=&x;
printf("%d\n",*y); /* 1 が表示される */

C 言語では配列変数はポインタにより実装されている。 配列 a[0], a[1] に対して、 a は a[0] の番地を示している。 つまり a と &a[0] は同じになる。 また、ポインタに対しても [値] とすると配列と同じように要素にアクセスで きる。 さらに、ポインタに 1 を足すとメモリの番地として 1 増えるのではなく、配列 として次の要素を指すようになる。 つまり次のような操作が許される。


int a[2];
int *x;
a[0]=5;
a[1]=6;
x=a;
printf("%d\n",*x); /* 5 が表示される */
printf("%d\n",x[1]); /* 6 が表示される */
x+=1;
printf("%d\n",*x); /* 6 が表示される */

つまり配列の宣言とポインタの宣言は領域を確保するかしないかだけで、基本 的には同じような意味となっている。

関数

C 言語ではプログラムを分割、再利用するために関数と言う概念がある。 関数は関数名(引数1,引数2, ...)という形で呼び出すと値を返す。 返してきた値を変数に代入するには変数=関数名(引数1,引数2, ...)という構文になる。 C 言語でプログラムを実行する時に呼び出されるのが main 関数である。

一方、関数の内部で定義された変数はローカル変数と呼び、他の関数か らアクセスできない。 関数の外側でも変数の定義ができる。 外側で定義した変数をグローバル変数と呼ぶ。 グローバル変数にはあらゆる関数からアクセスができるので、関数の情報を受 け渡すのに使用できるが、受渡しがうまく行ってない場合に原因を突き止める のが難しい。

C 言語の関数は値呼び出しである。 つまり関数の引数は関数側にとっては値が代入されているローカル変数となる。 したがって、関数の内部で値を変更しても、呼び出し側の引数の値を変更すること はできない。 そのため、変数の内容を関数で変更させるには、変数の番地を関数に与え、関数 内部ではポインタにより変数にアクセスする必要がある。

番兵

番兵とは複数のデータを扱う際に、データの終りにさらにデータの終りを示す データを与えるものである。 番兵を用いることによりデータの個数を意識しなくても複数のデータを処理す ることができるようになる。 配列変数を関数で処理する場合も、番兵を与えておけばデータの個数を関数に 渡す必要がなくなる。

プログラムの解法

課題1-1

データの個数を 10 個ずつ処理することになるので、数を数える変数を宣言し て 10 個毎に改行を行うようにする。

データの入力はポインタで与えられ、データの終りは -1 という番兵で与えら れるので、一番外側の繰返しは注目している配列の値が -1 でないという条件 で行う。 そして、注目している値を出力した後、数を数え 10 の倍数になっていれば改 行を出力する。

このようにして作成した dispArray 関数を付録に示した。 また、下のテストプログラムと結合したところ、題意を満たしていることがわ かった。


void dispArray(int *p);
main(){
  int a[]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,-1};
  dispArray(a);
}

課題1-2

(rotate 関数の方針の説明省略)

(アルゴリズムの説明省略)

このようにして作成した rotate 関数を付録に示した。 また、下のテストプログラムとさらに課題 1-1 で作成した dispArray 関数と 結合したところ、題意を満たしていることがわかった。


void dispArray(int *p);
void rotate(int *p);
main(){
  int a[]={1,2,3,-1};
  int b[]={-1};
  int c[]={1,2,3,4,5,6,7,8,9,10,-1};
  dispArray(a);rotate(a);dispArray(a);
  dispArray(b);rotate(b);dispArray(b);
  dispArray(c);rotate(c);dispArray(c);
}

課題1-3

課題 1-3 ではここまで作成した dispArray() 関数と rotate()関数を使用し て様々なデータを与えている。 実行例を付録に示す。 ここでは値がない場合と、値が一つの場合、値が 3 つの場合と、値が 99 個 の場合を考え、それぞれ学籍番号の下三桁(著者の場合 999)の数の回数だけ rotate()関数を実行するものである。

値がない場合
rotate前も後もなにも表示されない(改行のみ表示)が正しい
値が一つの場合
rotate前も後も値が一つ表示される
値が 3 つの場合
rotate 前は 1 2 3 と表示される。 この場合 3 回 rotate されると元の配列に戻る。したがって、 999 回 rotate されると、999 は 3 の倍数なので、やはり元の順番に戻る。 つまり 1 2 3 が表示される。
値が 99 個の場合
rotate 前は 0 から 98 までの数が表示される。 これが 999 回 rotate されることを考える。 999 = 990+9 となるので分けて考える。 0 から 98 までの数は 99 個あるので、99 回 rotate が行われると元に戻る。 したがって、990 回 rotate すると、これは 99 の倍数だからやはり元に戻る。 したがって、 999 回 rotate する場合、 990 回目に元に戻るので残りの 9 回 rotate することだけで順序が変わる。 これにより先頭が 90 で 98 まで順番に値が並び、その後 0 から 89 までの 値が並んで表示されれば正常である。

まとめ、考察

今回は関数とポインタを使用した関数 dispArray と rotate を作成し、課題 1-3 で組み合わせて実行した。

考察すべき点であるが、今回は簡単過ぎてなにも考えずに完璧にプログラムで きたので特になにも書く事はない。 また課題自体も完璧であるのでなにも指摘すべきことがない。

参考文献

  1. 講義資料 http://edu.net.c.dendai.ac.jp/ad/2/2004/
  2. B.W.カーニハン, D.M.リッチー著, 石田晴久訳「プログラミング言語C」第二版。共立出版(1989)

付録

課題1-1のプログラム

課題1-2のプログラム

課題1-3の実行例

坂本直志 <sakamoto@c.dendai.ac.jp>
東京電機大学工学部情報通信工学科