次の条件を満たす関数 dispArray() を作りなさい。
例えば整数型の配列 a[] が 1 から 15 まで順に入っていて、最後に -1 が入っ ている時、dispArray(a) は次のような出力をする。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
次の条件を満たす関数 rotate() を作りなさい。
例えば 1, 2, 3, -1 という配列の先頭番地を rotate() に与えると 2, 3, 1, -1 となります。
課題 1-1, 1-2 で作成した dispArray(), rotate() に対して次のプログラム を動かし結果を報告しなさい。
#include <stdio.h> dispArray(int *p); 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 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 言語ではプログラムを分割、再利用するために関数と言う概念がある。
関数は
一方、関数の内部で定義された変数はローカル変数と呼び、他の関数か らアクセスできない。 関数の外側でも変数の定義ができる。 外側で定義した変数をグローバル変数と呼ぶ。 グローバル変数にはあらゆる関数からアクセスができるので、関数の情報を受 け渡すのに使用できるが、受渡しがうまく行ってない場合に原因を突き止める のが難しい。
C 言語の関数は値呼び出しである。 つまり関数の引数は関数側にとっては値が代入されているローカル変数となる。 したがって、関数の内部で値を変更しても、呼び出し側の引数の値を変更すること はできない。 そのため、変数の内容を関数で変更させるには、変数の番地を関数に与え、関数 内部ではポインタにより変数にアクセスする必要がある。
番兵とは複数のデータを扱う際に、データの終りにさらにデータの終りを示す データを与えるものである。 番兵を用いることによりデータの個数を意識しなくても複数のデータを処理す ることができるようになる。 配列変数を関数で処理する場合も、番兵を与えておけばデータの個数を関数に 渡す必要がなくなる。
データの個数を 10 個ずつ処理することになるので、数を数える変数を宣言し て 10 個毎に改行を行うようにする。
データの入力はポインタで与えられ、データの終りは -1 という番兵で与えら れるので、一番外側の繰返しは注目している配列の値が -1 でないという条件 で行う。 そして、注目している値を出力した後、数を数え 10 の倍数になっていれば改 行を出力する。
このようにして作成した dispArray 関数を付録に示した。 また、下のテストプログラムと結合したところ、題意を満たしていることがわ かった。
dispArray(int *p);
main(){
int a[]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,-1};
dispArray(a);
}
rotate 関数は与えられたポインタで指された配列に対して、先頭の値を最後 に入れるように配列をずらすものである。 これは次のようにするとうまくいく
このようにして作成した rotate 関数を付録に示した。 また、下のテストプログラムとさらに課題 1-1 で作成した dispArray 関数と 結合したところ、題意を満たしていることがわかった。
dispArray(int *p);
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 ではここまで作成した dispArray() 関数と rotate()関数を使用し て様々なデータを与えている。 実行例を付録に示す。 ここでは値がない場合と、値が一つの場合、値が 3 つの場合と、値が 99 個 の場合を考え、それぞれ学籍番号の下三桁(著者の場合 999)の数の回数だけ rotate()関数を実行するものである。
今回は関数とポインタを使用した関数 dispArray と rotate を作成し、課題 1-3 で組み合わせて実行した。
考察すべき点であるが、今回は簡単過ぎてなにも考えずに完璧にプログラムで きたので特になにも書く事はない。 また課題自体も完璧であるのでなにも指摘すべきことがない。