
C言語勉強ノート;【C言語】ポインタ変数に「const」を付けよう!
ポインタ変数についてのまとめです。
kznさんの記事を契機に、姉弟子のAyumiさん、いつも天の声を授けてくださる遊月さんから、多くのことを学ぶことができました。
話の発端
発端となった記事はこちら。
この記事に対して、Ayumiさんと以下のようなやりとりをしました。
Akio van der Meer
(中略)初歩的な質問で恐縮です。get_count()の中のループ処理で、const Node* p;と定義しておられますが、これがよくわかりません。constなので値の変更は禁止かと思いきや、p = p->nextで値を変更してますよね?宜しければこの辺りの考え方のヒントをください。宜しくお願いします。
AyumiKatayama
(中略)ポインタ変数は間接参照なので「const」の対象が2種類あるんです。「const Node* p;」と書いた場合、「p->next = 1;」はダメだけど「p = p->next;」はOK。
という記事を書きました!
https://note.com/ayumi_kat/n/n26301e372a1d
ネタの提供もありがとうございます(笑)
このやりとりがきっかけでAyumiさんが発表された記事がこちら。
以下、(私的に)ディープなやりとりが続きます。
遊月
(中略)constとポインタの掛け合わせは悩めば悩むほどハマりますよねw
const char * だけ知ってるほうが幸せなくらい。
わたくしの解釈としては「constは直前の型に作用する」ですが、* で理解するのもありですねw
でも先頭のconstだけは例外で右に作用とかは「え〜っ」て思いますが…
char const * const
が正しいけど分かりやすいのか分かりにくいのか…
const char * const
の方が見慣れてますよねw
constも意外と厄介ですね💦
さっぱりわからない、、、
上記の遊月さんからのコメントを受けて、Ayumiさんが追記されました。
[2023/4/16 追記]
遊月さんの次のコメントを受けて考えてみました。
「constは直前の型に作用する」
ダブルポインタになると更にややこしい。
「直前の型に作用する」と考えるとすっきりするだろうか。
ということで、書いてみた。
int main()
{
char x;
char * px = &x;
char const** px1 = &px;
char *const* px2 = &px;
char **const px3 = &px;
px1 = 0; // char const** px1
*px1 = 0; // char const** px1
**px1 = 0; // char const** px1 --- NG
px2 = 0; // char *const* px2
*px2 = 0; // char *const* px2 --- NG
**px2 = 0; // char *const* px2
px3 = 0; // char **const px3 --- NG
*px3 = 0; // char **const px3
**px3 = 0; // char **const px3
return 0;
}
どうでしょう。
どうって言われても、、、
、、、さっぱりわかりません!
ということで、実際に動かしてみた
まずは、最初にchar xに'a'をセットして、他の変数への影響を確認します。
#include <stdio.h>
#include <stdlib.h>
int main() {
char x = 'a';
char * px = &x;
char const** px1 = &px;
char *const* px2 = &px;
char **const px3 = &px;
char **px4 = &px;
printf("x = %c\n", x);
printf("&x = %p\n\n", &x);
printf("px = %p\n", px);
printf("&px = %p\n", &px);
printf("*px = %c\n\n", *px);
printf("px1 = %p\n", px1);
printf("&px1 = %p\n", &px1);
printf("*px1 = %p\n", *px1);
printf("**px1 = %c\n\n", **px1);
printf("px2 = %p\n", px2);
printf("&px2 = %p\n", &px2);
printf("*px2 = %p\n", *px2);
printf("**px2 = %c\n\n", **px2);
printf("px3 = %p\n", px3);
printf("&px3 = %p\n", &px3);
printf("*px3 = %p\n", *px3);
printf("**px3 = %c\n\n", **px3);
return 0;
}
x = a
&x = 0x16fd3f72b
px = 0x16fd3f72b
&px = 0x16fd3f720
*px = a
px1 = 0x16fd3f720
&px1 = 0x16fd3f718
*px1 = 0x16fd3f72b
**px1 = a
px2 = 0x16fd3f720
&px2 = 0x16fd3f710
*px2 = 0x16fd3f72b
**px2 = a
px3 = 0x16fd3f720
&px3 = 0x16fd3f708
*px3 = 0x16fd3f72b
**px3 = a
エクセルでまとめてみた
これで各変数の相関関係がわかりました。

つまり、
「 char const **px1 = &px;」と定義したとき、 **px1に値をセットしようとするとコンパイルエラーとなる。
「 char *const *px2 = &px;」と定義したとき、*px2に値をセットしようとするとコンパイルエラーとなる。
同様に、「char **const px3 = &px;」と定義したとき、px3に値をセットしようとするとコンパイルエラーとなる。
即ち、
「constは直前の型(今回の場合は、char型)の(**px1, *px2, px3)に作用する」ってことになります。
(追記:22:43 2023/4/16)下記のAyumiさんのコメントを参照ください。
、、、多分、あってると思う(苦笑
一つの質問からいろんな話につながっていく、、、だからこのC言語教室、楽しい!
最初の課題提出のときは、Macのキーボードから'\'(バックスラッシュ)を入力する方法すらわからず、kznさんの記事からコピペしてコーディングするところから始まりました。あの時は、いつもコメントをくださるMOHさんから、Macでのキー入力方法をわざわざご連絡いただきました。いろんな方に助けられながらここまでやってこれました。有り難うございます!これからも宜しくお願いします!
ここまで読んでいただき、有り難うございました。
いいなと思ったら応援しよう!
