TL;DR
ポインタは変数や関数などを保存しているメモリの場所を指してものです。C言語にはガーベージコレクションという機能がないのでこれを扱う必要があるので概念として軽く知っておこうという話です。
始まり
大学の講義で多くの学生がC言語を学ぶ中で以下の表記に疑問を持った方は多いのではないでしょうか?
#include<stdio.h>
void main(){
int a;
scanf("%d", &d);
printf("input Num : %d", d);
}
このような表記に圧倒されてプログラミングをあきらめた学生も多くいるのではないでしょうか。大学のカリキュラムではこの辺りは最初に行うので先生方もいちいちポインタの概念を説明することはせずに「こういう書き方です」といった説明をする方が多いです。
また、文字を受け取る際は
#include<stdio.h>
void main(){
char s[256];
scanf("%s", s);
printf("%s", s);
}
のように書き「&を入れるのか入れないのかはっきりしろや!」と思った方も多いと思います。私もCのこのあたりの話に挫折してpythonに逃げた者なので今回はその辺を調べたので備忘録として共有しておきます。
アドレス
大前提としてプログラム内で宣言される変数や関数などはパソコン上のどこかしらのメモリに保存されます。ここでいうメモリというのはSDカードのようなものです。SDカードにあるデータを保存する時に直下に置くのかフォルダを作成しておくのかなど様々あります。C言語ではSDカード内のどこに置いたかを表す変数があります。それがアドレスです。実際に確認していきましょう。
#include<stdio.h>
void main(){
int a;
printf("address 0x%x\n", &a);
a = 1;
printf("num %d", a);
}
//output
//address 0x61ff1c
//num 1
上記のコードを実装するとアドレスが出てくるのが分かります。すなわちint変数aを入れる場所を確保しそこに1という値を入れた状態
です。ここから分かるようにa, &a
はそれぞれ値とアドレスを表現していることが分かります。
ポインタ
ポインタは以下のように定義されています。
ポインタ (英: pointer) とは、コンピュータプログラミングにおいて、変数や関数などが置かれたメインメモリ上の番地(メモリアドレス)などを格納する特殊な変数のこと(wikipedia)
言葉で説明するより例を見た方が早いので早速見ていきたいと思います。
#include<stdio.h>
void main(){
int *p = NULL;
int a = 100;
p = &a;
printf("a: 0x%x b: 0x%x", &a, p);
}
//output
//a: 0x61ff18 b: 0x61ff18
このようにポインタ変数を*p
のように宣言することでアドレスを示すことができるポインタ変数が使えます。ここまでをまとめると
なんかしらの値 | アドレス | |
---|---|---|
変数 int data | data | &data |
ポインタ変数 int *data | *data | data |
のような関係が見ます。
結局ポインタは何に必要なのか
ポインタの役割にはいくつかあり
- 参照渡し
- 配列の処理
- メモリの動的処理
などが挙げられます。一番最初に挙げた文字列の例も配列の処理とみなすことができるのであのような書き方になります。最後に配列の例と文字列の例をみてましょう。
#include<stdio.h>
void main(){
char s[256] = "neko";
int nums[] = {1, 2, 3, 4, 5};
char *sp = NULL;
int *ip = NULL;
int i;
sp = s;
ip = nums;
for(i = 0; i<5; i++){
printf("%d %d \n", *(ip+i), nums[i]);
}
for(i = 0; i<5; i++){
printf("%c %c \n", s[i], *(sp+i));
}
}
//output
//1 1
//2 2
//3 3
//4 4
//5 5
//n n
//e e
//k k
//o o
配列はポインタ変数としてもとらえることができるので上記のような書き方ができます。また、C言語では文字列は配列として捉えることができるので最初の入力のようにscanf("%s", s)
のような書き方ができるということです。
参考文献