3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

C言語のポインタ理解できた記念日

Last updated at Posted at 2022-05-20

ポインタ変数

pointer.png

char *x = "hello";

ポインタ変数*xは、hello\0が格納された場所のアドレスを持っている。

ポインタ変数*xが格納してるのは、値そのもの(ここではhello\0)ではなく、(値を格納しているメモリ上の)”アドレス”である。

アドレス演算子

&xとは、変数xのアドレスのこと。

&xは変数xのアドレスなのだから

int *x_ptr = &x;

とすると、ポインタ変数x_ptrに変数xのアドレスを直接代入できる。

これで、ポインタ変数x_ptrに変数xのアドレスを格納できた。x_ptrは変数xをポイントしてる(指し示してる)。

間接演算子

*ポインタ変数

というフォーマット。

int32_t a = 8;
int32_t *a_ptr = &a;
printf("%i", *a_ptr);  // => 8
                       // ここの *a_ptr が間接演算子

間接演算子*をポインタ変数a_ptrに適用すると、a_ptrが指し示しているアドレスにある値を取り出す。

*a_ptrとは、ポインタ変数a_ptrがポイントしてるとこにある値なのだから、

*a_ptr = 99;
printf("%i", a);  // =>99

のように、代入(上書き)ができる。

ちなみに、最後のprintfは間接演算子を使って

printf("%i", *a_ptr);

でも同じ結果。

int32_t *a_ptr = &a;を省略することもできる:

int32_t a = 8;
printf("%i", *&a);

&aに対して直接、間接演算子*を適用してる)

配列とポインタ

#include <stdio.h>

int main()
{
	int32_t a[] = {123, 4545, 999};
	int32_t *a_ptr = a;  // 配列名を直接ポインタ変数に与えると、その配列の先頭要素のアドレスが得られる(アドレス演算子は不要)
	printf("%i\n", *a_ptr);  // 間接演算子

	a_ptr = &a[1];  // 配列中の個々の要素に対しては、アドレス演算子が必要
	printf("%i", *a_ptr);  // 間接演算子
}
$ ./a.out
123
4545

ポインタとインデックス

ポインタ変数pに対して、p[i]は間接演算子*(p + i)に等しい。

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>

int main()
{
	int32_t array[] = {1, 2, 3, 4};
	int32_t *p = array;

	for (size_t i = 0; i < sizeof array / sizeof(int32_t); i++) {
		printf("%i\n", p[i]);  // p[i] is *(p + i)
	}
}

実行すると

$ ./a.out
1
2
3
4

関数ポインタ

関数のアドレスを格納したポインタ変数が「関数ポインタ」。

関数ポインタ変数の宣言

返り値の型 (*ポインタ変数名)(パラメータリスト)

compare関数へのポインタ変数pを定義するには

int compare(int x, int y);

int (*p)(int, int) = compre;  // 「*p = &x」と対応

最後の行にあるように、関数のアドレスを渡す際は関数名を与える。&compareとかcompare()じゃない。

&compareでも可ということでした(コメントより)。

パラメータリストの部分は型だけでよい(つまり(*p)(int x, int y)と書かなくても大丈夫)。

関数ポインタの間接演算子

(*ポインタ変数名)(パラメータリスト)

または

ポインタ変数名(パラメータリスト)

compare関数のポインタ変数を定義して、間接演算子で関数を呼び出す例:

int compare(int x, int y);
int (*p)(int, int) = compare;  // 関数compareへのポインタ変数p

// 下の二行は同じ結果になる
printf("func result: %i", (*p)(3, 4));
printf("func result: %i", p(3, 4));  

typedefと関数ポインタ

int (*fptr1)(int);

int square(int num) {
  return num * num;
}

int n = 5;
fptr1 = square;
printf("squared: %d", fptr1(n));

typedefを使って書くと

typedef int (*funcptr)(int);  // funcptr型が使えるようになる
funcptr ftp2;
ftpr2 = square;
printf("squared: %d", fptr2(n));
3
1
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?