こんにちはhiroです!今回はc言語におけるポインタと配列の関係について紹介します。センサーなどのデータを取得する際に配列を用いることが多くあります。その時にとても必要な知識なので、ぜひみてみてください。
また、この記事は"通常の変数のポインタ"、"値渡しと参照渡し"についての理解がある前提で書かれています。これらがまだあまりわからないよーという方はこちらの記事をご覧ください。
配列とポインタの密接な関係
配列を関数の引数に入れる
配列を関数の引数にするとき、下のような書き方があります。
#include <stdio.h>
void swap(double array[], x, y){//配列の要素を入れ替える関数
int tmp = array[x];
array[x] = array[y];
array[y] = tmp;
}
int main(){
double acc[3];
acc[0] = 0.0;
acc[1] = 1.0;
acc[2] = 2.0;
swap(a, 0, 1);
printf("%d, %d\n", acc[0], acc[1]);
return 0;
}
この時、標準出力には1, 0と出力されます。
しかし、値渡しと参照渡しを学習したみなさんなら、array[]は仮の配列なんだからreturnでこの配列を返さないと要素は入れ替わったことにならないぞ!(0, 1と表示されるぞ!)と思うわけです。
そう思うのも無理はありません!実はこのarray[]はポインタなのです。
しっかり書くと上のコードはこのようになります。これならしっくりくるのではないでしょうか。
#include <stdio.h>
void swap(double* array, x, y){//配列の要素を入れ替える関数
int tmp = array[x];
array[x] = array[y];
array[y] = tmp;
}
int main(){
double acc[2];
double *p = acc; //pは&a[0]を指す: int *p = &a[0];と書いても良い
acc[0] = 0.0;
acc[1] = 1.0;
acc[2] = 2.0
swap(p, 0, 1);
printf("%d, %d\n", a[0], a[1]);
return 0;
}
しかし、このように書くと配列を扱う関数に配列を入れるためにわざわざその配列を指すポインタを作らなければなりません。だから、そんなめんどくさいことをしなくて良いように関数の引数にint array[]と書くだけで array[]を指すポインタを勝手に引数として受け取るようになっています。
関数の引数の配列は勝手にポインタとして受け取る
動的メモリ確保
ポインタ変数に配列の0番目のアドレスを代入すると、その変数は配列のように扱うことができました。
ここでは、ポインタ変数に配列分のメモリを割り当てることで、配列を動的に作ることを紹介します。
配列のポインタを作りたいときに、わざわざ配列を宣言してからその配列を指すポインタ変数を作るのは大変です。配列をポインタだけで扱うコードはこちらです。
#include <stdio.h>
#include <stdlib.h>
int* alloc(int n){//n個の配列を動的に作る関数
int *p = (int*)malloc(sizeof(int)*n);
if(p == NULL){
fprintf(stderr, "alloc: Cannot allocate memory\n");
exit(1);
}
return p;
}
int main(){
int n = 2;
int *array = alloc(n);
array[0] = 0;
array[1] = 1;
printf("%d, %d\n", array[0], array[1]);
free(array);//メモリを解放する必要あり
return 0;
}
malloc関数はstdlib.hで定義されている関数で、引数の分だけメモリを確保します。int型の配列を作るので、sizeof演算子でint型のメモリの大きさを取得し、作りたい配列の長さ(n)をかけることで、作りたい配列分のメモリを確保します。
メモリ確保に失敗すると、pにはNULL(何もないの意味)が入ります。そこで、もしメモリ確保に失敗したらエラーを出力してプログラムを強制終了させることにしています。
malloc関数でメモリを動的に確保することでポインタに動的に配列を作ることができる
おわりに
配列とポインタの関係が大体わかったと思います。配列は要素順に順番にメモリが割り当てられているので、ポインタは配列の0番目の要素のアドレスがわかるとその配列の他の要素に簡単にアクセスできます。その関係で、配列とポインタの密接な関係が生まれているのでした。
配列は組み込みなどでもデータの扱いで非常に重要な要素です。基本的なことを押さえて正しいコードをかけるようにしましょう!