【C言語】ポインタと配列の関係を端的にまとめてみた

今回は、C言語のポインタと配列の関係、関数への受け渡し方について簡単な例を用いながらまとめたいと思います。

1. ポインタ配列を作る

まず、今回説明するためにポインタ配列を作ります。

int *x;
x=(int *)malloc(sizeof(int)*10);

で完成です。

int a[10];
int *x;
x = &a[0];

などで同じようなポインタ配列を作ることができますが、配列でポインタを使うときはmalloc関数を使うこととします。このメリットは暇なとき調べてみて下さい。配列名も x 一つになるので混乱せずに済みます。笑

2. ポインタ配列に関する規則

次に、ポインタ配列を作ると次のような規則が生まれます。iは変数

x[i] = *(x+i)

&x[i] = x+i

x[i]と*(x+i)は、x[i]の要素にアクセスする式
&x[i]とx+iは、要素x[i]を指すポインタです。

これはいつか必ず覚えることになるので学び始めに知っておくとかなり楽です。

int a[10];
int *x;
x = &a[0];

で作った場合はさらに、

x[i] = a[i] = *(x+i) = *(a+i)
&x[i] = &a[i] = x+i = a+i

となります。

3. ポインタ配列をつかうメリット

例えば、ポインタを利用せず 配列a[20] の各要素を 配列b[20] にコピーする場合、

for(int i=0;i<20;i++){
b[i] = a[i];
}

と書きます。for文を使って値を一つ一つ格納する必要があります。

一方で、ポインタを利用してコピーをしてみると――

b=a;
または
&b[0]=&a[0];

と書くだけでfor文を使わずにコピーができます。
これは、aと同じ先頭アドレスにbがアクセスしている状況です。

b = aと書いた後にa[3] = 9と書いた場合、b[3]に格納されている値も自動で9になります。これはよくあるポインタの特徴ですよね!

ポインタを使わない場合は、新たに別のアドレスから値を一つ一つ格納する必要があるため、処理に時間がかかる、メモリ領域は多く使う、など良い点がありません。      

↓ポインタを使ったコピーのコード例

int main(void){
  int *a=(int *)malloc(sizeof(int)*5); 
  int *b=(int *)malloc(sizeof(int)*5);
  for(i=0; i<5; i++){ 
    *(a+i)=7;    //aの全要素に7を格納
  }
  b=a;     //bとaは完全に同一な配列になる。
  return 0;
} 

4. 関数に配列を渡す

最後に、配列の関数への受け渡し方についてです。関数は戻り値を一つしか返せないため、ポインタを使わなければまともなコードは書けません。関数に配列を受け渡すときはポインタの仕組みを利用することが必須です。

まず、配列の全要素をaaa関数で使いたい場合、

void aaa(int *x){  
}
int main(void){
  int x[3] = {1,2,3};   
  add(x);   //add(&x[0])でも同じ意味
}

のように書きます。(説明に必要な最低限のものしか書いてません) xの先頭アドレスをaaa関数へ渡しています。 aaa関数の中で何かを計算したい場合は、例えばこの関数の中に

int k;
k=x[2]; //k=*(x+2)と同じ意味

と書くことで、kにx[2]の値が代入できます。

次に、一つの要素のみを関数へ渡したい場合、

void aaa(int x){ // x=3
}
int main(void){
int x[3] = {1,2,3};
add(x[2]);
}

のように書きます。一つの数字を渡すだけなのでポインタを使う必要はありません!