TIL

Today I Leaned. 仕事で知ったことや、つまづいたことを時間のある時にメモしておく

ポインタとは - C言語

わかりやすいC 入門編の「17.2 ポインタとは」を読んでのメモみたいなもの

アドレスを格納するためのもの。

  • ポインタにはアドレスのみ格納可能
  • 間接参照という機能を持つ
  • 変数宣言時には*を使う
  • 間接参照(*)によって、格納しているアドレスの変数とみなすことができる

変数にはそれぞれ、メモリ上でのアドレスがある。そのアドレスをにアクセスすれば、その変数の値を取得したり設定したりできる。

そのアドレスの特性を活かしたポインタという機能がある

ポインタはアドレスだけを入れることができる変数(※値は代入することができない)。間接参照という機能を持つ。

間接参照を使うことによって、格納しているアドレスの変数の値を取得したり、設定したりすることができる。

ポインタを使ったプログラム

ポインタとして変数を宣言するときには、*をつける

#include <stdio.h>

int main(int argc, char *argv[]){
    int *p;     // int型のポインタを宣言

    int a = 25;

    p = &a;     // 変数aのアドレスを格納
}

pというint型のポインタを宣言している。

p = &aで ポインタのpに変数aのアドレスを格納している。こうすることで*paと同じように扱うことができる

printf("%d\n", *p);

また、*のことを間接参照演算子という 

ポインタ型 と ポインタ変数

ポインタ型

アドレスを格納することができる型のこと

ポインタ型は他の型と合体しないと実現できない。

例:intのポインタ型

なぜ、他の型と合体しないといけないのか

もし、そのポインタが何の型のアドレスかわからないと、値を取得しようとしたときに何バイト分取得していいのかわからないため

型はそれぞれバイト数が決まっているため、何バイト取得するのかわかる

ポインタ変数

ポインタ型で宣言された変数のこと

ポインタ変数の目的は「格納されているアドレスの変数の値を計算に使うこと」となっている

ポインタ変数には2つの機能がある

  1. 格納しているアドレスを取得、設定する
  2. 格納しているアドレスの変数の値を使用する

1では、格納したい変数のアドレスを扱い、2では他の変数と同じように値を計算に使うことができる

メモ

*pは、格納しているアドレスの変数の値を表す。pは、格納しているアドレスそのものを表す。

以下、躓いたときの現象


このソースはコンパイルが通った

printf("p  --  %p\n", p);

しかし、次のソースはコンパイルエラーになってしまった

printf("p  --  %p\n", *p);
warning: format specifies type 'void *' but the argument has type 'int' [-Wformat]
    printf("p  --  %p\n", *p);
                    ~~     ^~
                    %d
1 warning generated.

*をつけると、アドレスの変数の値にアクセスしているということ

宣言と同じ型の変数のアドレスしか格納できない

格納できる変数のアドレスは宣言時に指定しているため以下のコードではコンパイルエラーになってしまう。、cpはchar型のポインタでaはint型なので、int型へのポインタは格納できない

#include <stdio.h>

int main(int argc, char *argv[]){
    char *cp;   // char型のポインタを宣言
    int a = 25;

    cp = &a;    // 型が違うため、コンパイルエラーになる
}
warning: incompatible pointer types assigning to 'char *' from 'int *' [-Wincompatible-pointer-types]
    cp = &a;
       ^ ~~

参考文献

わかりやすいC入門編

わかりやすいC入門編