参考書でconstポインタなるものを見てどのような仕組み
なんだと手当たり探ってみましたが、いまいち理解できません
わかる方いましたら、constポインタの使用理由・方法教えてほしいです
よろしくお願いします
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

退会済みユーザー
2018/08/20 09:41
2018/08/20 09:46

退会済みユーザー
2018/08/20 09:47

回答3件
0
ベストアンサー
constポインタなるものを見てどのような仕組みなんだと
ポインタ自体、或いは生成された機械語自体に、特別な「仕組み」があるのではなく、書き変えてはいけない・書き変えられない場所、READ-ONLYな場所を、プログラムが書き変えようとしていたら、コンパイルエラーとして検出できる事が仕組みに相当すると思います。コンパイルが通らなければ、やっちゃいけないこと・危険なことを実行しないで済みますから。
なので、プログラムのミスを減らし、安全性を担保することが存在理由だと思います。const が適切に使われているプログラムは信頼性が高いだろう、というわけです。
そのためには、書き変えてはいけない・READ-ONLYな場所を、適切に指定することが肝心です。cateyeさんのお答えと同じですが、書き変えられない場所に注目して書き直すと
- const char *ptr; は、ポインタが指すメモリを書き変えない ←最もよく使う形
- char * const ptr; は、ポインタ自体を変更しない。一箇所を指したまま
- const char * const ptr; は、ポインタが指す先も、ポインタも変更しない
- ただの char *ptr; なら、ポインタが指す先も、ポインタ自体も変更できる
ダブルポインタ(ポインタへのポインタ)の場合、const を考えなければ
C
1 char **ptr = ???;
ですが、この場合 const を書ける場所が3箇所あります。普通こんな書き方しないけど、3箇所全てに const を書くとこんな感じ。
C
1 const char * const * const ptr = ???;
どの const が、どこをREAD-ONLYにするか、手を動かして調べてみたら良いと思います。
投稿2018/08/21 05:21
編集2018/08/21 05:26総合スコア1382
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

退会済みユーザー
2018/08/21 12:20

0
const ポインタの存在理由
ポインタというのは「メモリ上のデータがある位置」を差し示すものですが、これを教えるというのはそれなりのリスクを伴います。というのは、原理的に、この情報を使えばデータそのものを書き換えられてしまうからです。つまりポインタを使うときは、ポインタを渡す関数がデータを破壊しないと信用するか、あるいは「このポインタ経由ではデータを書き換えられない」ようにする仕組みが必要です。後者の仕組みが const ポインタです。 const 修飾されたポインタは、そのポインタを経由して、指し示す先のデータを書き換えることはできません。しようとしたときにコンパイラが怒ってくれます。
まあ const ポインタを強引に突破することもできてしまうので、どちらかというと関数が引数でポインタを必要とするときに「私はこのポインタの指し示す先を書き換えませんよ」ということをアピールする意味合いが強いです。
const ポインタの使い方
(変な例ですが) たとえば次のような関数を考えてみます。引数として与えられたポインタ a
, b
の指し示す先の値を足す関数 add()
です。
c
1int add(int *a, int *b) { 2 return *a + *b; 3} 4 5int main(void) { 6 int a = 3, b = 4; 7 printf("%d\n", add(&a, &b)); // 3 + 4 を計算して 7 を表示してほしい。 8 return 0; 9}
さて、この関数はポインタを受け取っているので、その気になれば値を書き換えられてしまいます。
ただ足し算をするだけの関数のフリをして、渡された値を変えてしまうことができます。
c
1int add(int *a, int *b) { 2 *a = 10; // 書き換えられてしまう 3 return *a + *b; 4} 5 6int main(void) { 7 int a = 3, b = 4; 8 printf("%d\n", add(&a, &b)); // 3 + 4 を計算して 7 を表示してほしい。 9 // しかし add() の中で a の中身を書き換えられてしまったので変な答え (14) が表示される。 10 // しかもこれ以降 a の値が 10 になっている! 11 if (a == 3) { 12 // 結果として a != 3 なので、この非常に大事な処理は実行されない。 13 very_important_work(); 14 } 15 return 0; 16}
結果として、本来実行されるべき very_important_work()
が実行されなくなりました。バグの完成です。ポインタを要求されると使う側はこんなことをされないか心配しないといけません (そしてデバッグが面倒になります) 。逆に真っ当な add()
関数を作る側からしても、使う人に余計な心配をさせてしまうのは本意ではありません。
ということで、この関数はそういう書き換えをしませんよというアピールとして、 const をつけるのです。
c
1int add(int const *a, int const *b) { 2 // *a = 10; // 今度は書き換えようとするとエラーになる。 3 return *a + *b; 4} 5 6int main(void) { 7 int a = 3, b = 4; 8 printf("%d\n", add(&a, &b)); // 3 + 4 を計算して 7 を表示してほしい。 9 if (a == 3) { 10 // a は書き換えられないので、最初の値を保っているはず。 11 very_important_work(); 12 } 13 return 0; 14}
ちなみに、 const ポインタを通常のポインタに渡すことはできません (書き換えない!と宣言して受け取ったポインタを、書き換え可能なポインタとして渡すことは当然できません) 。ということは、中身を書き換えない関数なのに const を付けなかったせいで、 const ポインタを受け取っている他の関数から呼び出せなくなったりします。
c
1// a をただ表示するだけの、書き換えない関数。 2// 書き換えないけど a は const ポインタになっていない 3void do_subtask(int *a) { 4 printf("%d\n", *a); 5} 6 7// 書き換えられない a を受け取る関数 8void do_task(int const *a) { 9 // do_subtask() は「結果的に」内容を書き換えないが、 10 // 引数が const になっていないので渡せない。 11 // do_subtask(a); // ← コンパイルエラー 12} 13 14int main(void) { 15 int a = 3; 16 do_task(&a); 17 return 0; 18}
自分の作った関数が他の関数から呼び出される可能性を考えても、指し示す先を書き換えないポインタ引数には常に const をつけるべきです。
投稿2018/08/20 10:28
総合スコア429
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

退会済みユーザー
2018/08/21 12:21

0
ちょっと難しいですよね・・・合ってるかなぁ^^;
const char * ptr; // ポインタの変更が可能
char * const ptr; // ポインタの変更が不可
const char * const ptr; // すべて変更不可
投稿2018/08/20 10:10
総合スコア6851
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

退会済みユーザー
2018/08/21 12:21

あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。