C言語のポインタについて 3.宣言する型が違う場合どうなっているのか?
C言語のポインタについて3
1.そもそもポインタとは何か?
2.ポインタで出てくる&と*はなに?
3.宣言する型が違う場合どうなっているのか?
4.ポインタのポインタとは?
今回はポインタ変数の型について考えていこうと思います。
正直、ポインタ変数に入る値はアドレスという数字と文字の羅列(16進表記のメモリアドレス)なので、変数の型なんてポインタ変数であれば、どうでもいいように感じますが一応意味があります。
それは、ポインタ変数からの代入ができないことと、アドレス操作時のバイト数の違いです。
①ポインタ変数からの代入ができない
1つ目のポインタ変数から代入できないとは、
int A;
A=1;
char *Ap = &A;
*Ap = 123;
printf(" A = %d\n", A);
上記のプログラムだと、文字通り普通に値を代入ではなくポインタ変数経由で値を入れるとき(4行目)、型が一致していないとうまくいかない。逆に型を一致させていれば、
int A;
A=1;
int *Ap = &A;
*Ap = 123;
printf(" A = %d\n", A);
代入ができます。(これだけです。)
②アドレス操作時のバイト数の違い
2つ目にアドレス操作時のバイト数の違いは、型によってバイト数が決められています。
そのバイト数分を利用してアドレス操作をする必要があるため、そのときに型を意識する必要が出てきます。
【型サイズ一覧表】
型名 | サイズ (32 ビット) | サイズ (64 ビット) |
---|---|---|
char | 1 バイト | 1 バイト |
short int | 2 バイト | 2 バイト |
int | 4 バイト | 4 バイト |
long int | 4 バイト | 8 バイト |
float | 4 バイト | 4 バイト |
double | - | 8 バイト |
long | - | 8 バイト |
※32bitのdoubleとlongはどのような扱いになるかわからなかったので記載しまていません。
試しに、まず私の開発環境は何bitどうなっているのか確認してみようと思います。
やり方は簡単で、ポインタ変数のサイズを測ればわかります。
測った際のサイズが8の時は64bit、4の時は32bitとなります。
ポインタ変数のサイズが8なので、私の開発環境は64bitとなります。
次は、型のサイズが上記通りか確認してみます。
3行目~9行目は変数の宣言
11行目~17行目は変数に対応したポインタ変数の代入
を行っています。
型 | 変数名 | 値 |
---|---|---|
char | sizeof A | 1 |
Ap | 0x7ffcba727ca5 | |
Ap+1 | 0x7ffcba727ca6 | |
short int | sizeof B | 2 |
Bp | 0x7ffcba727ca6 | |
Bp+1 | 0x7ffcba727ca8 | |
int | sizeof C | 4 |
Cp | 0x7ffcba727cac | |
Cp+1 | 0x7ffcba727cb0 | |
long int | sizeof D | 8 |
Dp | 0x7ffcba727cc0 | |
Dp+1 | 0x7ffcba727cc8 | |
float | sizeof E | 4 |
Ep | 0x7ffcba727ca8 | |
Ep+1 | 0x7ffcba727cac | |
double | sizeof F | 8 |
Fp | 0x7ffcba727cb8 | |
Fp+1 | 0x7ffcba727cc0 | |
long | sizeof G | 8 |
Gp | 0x7ffcba727cb0 | |
Gp+1 | 0x7ffcba727cb8 |
出力結果をわかりやすく表にしてみました。
ひとつづつ見ていきます。
①.char型
char型のサイズは1バイトです。なので、アドレス操作(+1の奴)をした際にアドレスは1だけ値がずれます。
Ap:0x7ffcba727ca5
↓アドレス操作で+1したらアドレスの値が1バイト増える。
Ap+1:0x7ffcba727ca6
②short int型
short int型のサイズは2バイトです。なので、アドレス操作(+1の奴)をした際にアドレスは2だけ値がずれます。
Bp:0x7ffcba727ca6
↓アドレス操作で+1したらアドレスの値が2バイト増える。
Bp+1:0x7ffcba727ca8
③int型
int型のサイズは4バイトです。なので、アドレス操作(+1の奴)をした際にアドレスは4だけ値がずれます。
Cp:0x7ffcba727cac
↓アドレス操作で+1したらアドレスの値が4バイト増える。
Cp+1:0x7ffcba727cb0
※アドレスは16進数で決められているから0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f,まで行くと桁が繰り上がる。今回だと
0x7ffcba727cac
↓+1バイト(計1バイト)
0x7ffcba727cad
↓+1バイト(計2バイト)
0x7ffcba727cae
↓+1バイト(計3バイト)
0x7ffcba727caf
↓+1バイト(計4バイト)
0x7ffcba727cb0
となるから4バイト上がっていることがわかる。
④long int型
long int型のサイズは8バイトです。なので、アドレス操作(+1の奴)をした際にアドレスは8だけ値がずれます。
Dp:0x7ffcba727cc0
↓アドレス操作で+1したらアドレスの値が8バイト増える。
Dp+1:0x7ffcba727cc8
⑤float型
float型のサイズは4バイトです。なので、アドレス操作(+1の奴)をした際にアドレスは4だけ値がずれます。
Ep:0x7ffcba727ca8
↓アドレス操作で+1したらアドレスの値が4バイト増える。
Ep+1:0x7ffcba727cac
これも先程の16進数の考え通りすれば、
0x7ffcba727ca8
↓+1バイト(計1バイト)
0x7ffcba727ca9
↓+1バイト(計2バイト)
0x7ffcba727caa
↓+1バイト(計3バイト)
0x7ffcba727cab
↓+1バイト(計4バイト)
0x7ffcba727cac
4バイト分増えていることがわかる。
⑥double型
double型のサイズは8バイトです。なので、アドレス操作(+1の奴)をした際にアドレスは8だけ値がずれます。
Fp:0x7ffcba727cb8
↓アドレス操作で+1したらアドレスの値が8バイト増える。
Fp+1:0x7ffcba727cc0
これも16進数の考え通りで、
0x7ffcba727cb8
↓+1バイト(計1バイト)
0x7ffcba727ca9
↓+1バイト(計2バイト)
0x7ffcba727caa
↓+1バイト(計3バイト)
0x7ffcba727cab
↓+1バイト(計4バイト)
0x7ffcba727cac
↓+1バイト(計5バイト)
0x7ffcba727cad
↓+1バイト(計6バイト)
0x7ffcba727cae
↓+1バイト(計7バイト)
0x7ffcba727caf
↓+1バイト(計8バイト)
0x7ffcba727cc0
8バイト分増えていることがわかる。
⑦long型
long型のサイズは8バイトです。なので、アドレス操作(+1の奴)をした際にアドレスは8だけ値がずれます。
Gp:0x7ffcba727cb0
↓アドレス操作で+1したらアドレスの値が8バイト増える。
Gp+1:0x7ffcba727cb8
このように型自体にバイト数が決められていることが分かった。
※今回は+1を指定したが
char型で+2を指定すれば2バイトのアドレスの値が増える
char型で+3を指定すれば3バイトのアドレスの値が増える
char型で+4を指定すれば4バイトのアドレスの値が増える
int型で+2を指定すれば8バイトのアドレスの値が増える
int型で+3を指定すれば12バイトのアドレスの値が増える
int型で+4を指定すれば16バイトのアドレスの値が増える
double型で+2を指定すれば16バイトのアドレスの値が増える
double型で+3を指定すれば24バイトのアドレスの値が増える
double型で+4を指定すれば32バイトのアドレスの値が増える
一応、計算式を作るとすれば
【型のバイト数】×【+の数字】= アドレス操作時のバイト数
となります。
これで、型ごとのバイト数の増え方が表どおりであることが分かりました。
じゃあ、この型のバイトを利用してアドレス操作ってなにするのかというと、
文字列や数列などから目的の値をとる時などに使います。
例)
char A[]=”ABCDEFGH”
ここからDEFGHだけを取り出して別の変数に入れる。
int B=123456789
ここから56だけを取り出して別の変数に入れる。
このようなときにこの型を意識して使う必要が出てきます。
③まとめ
ポインタ変数で型を意識する理由
長ったらしくいろいろ書きましたが、要は3点です。
1.ポインタ変数からの代入ができないこと
※正直、ポインタ変数から代入をする機会はそこまでないと思うので、あまり気にしなくていい。
2.アドレス操作時のバイト数の違い
アドレス操作時に+1した際、型ごとに増え方が違う。
→使い道は、文字列や数列から目的の値をとる時などに意識する。
型名 | サイズ (32 ビット) | サイズ (64 ビット) |
---|---|---|
char | 1 バイト | 1 バイト |
short int | 2 バイト | 2 バイト |
int | 4 バイト | 4 バイト |
long int | 4 バイト | 8 バイト |
float | 4 バイト | 4 バイト |
double | - | 8 バイト |
long | - | 8 バイト |
3.特に型に思い入れがないなら、とりあえず変数と同じ型にしておけばいい
追記
2021年1月29日リンク先を追加しました。