const int *、const int * const、およびint const *の違いは何ですか?


1356

使用方法まで私はいつも混乱const int*const int * constint const *正しく。できることとできないことを定義する一連のルールはありますか?

割り当て、関数への受け渡しなど、すべてのすべきこととすべきでないことを知りたい


175
「Clockwise / Spiral Rule」を使用して、ほとんどのCおよびC ++宣言を解読できます。
James McNellis、2013年

52
cdecl.orgは、C宣言を自動翻訳する優れたWebサイトです。
Dave Gallagher

6
@Calmarius:type-nameが/であるところから開始し、可能な場合は右に、必要な場合は左に移動しますint *(*)(char const * const)。括弧の右側から始めて、*左に移動する必要がありますpointer。括弧の外では、右に移動できますpointer to function of ...。次に、左に移動する必要がありますpointer to function of ... that returns pointer to int。を繰り返して、パラメータ(...)を展開しますpointer to function of (constant pointer to constant char) that returns pointer to int。Pascalのような読みやすい言語では、同等の1行の宣言は何でしょうか?
Mark K Cowan

1
@MarkKCowan Pascalでは、次のようになりfunction(x:^char):^intます。関数のタイプは関数へのポインタを意味するため、指定する必要はありません。Pascalはconstの正確さを強制しません。左から右に読むことができます。
カルマリウス2015

5
「const」の左側の最初のものは定数です。「const」が最も左にあるものである場合、その右にある最初のものが定数です。
カップケーキ

回答:


2208

時計回り/スパイラルルールによって駆動されるように)逆に読みます:

  • int* -intへのポインタ
  • int const * -const intへのポインタ
  • int * const -intへのconstポインター
  • int const * const -const intへのconstポインタ

これで、最初constのものは型のどちら側にも置くことができます。

  • const int * == int const *
  • const int * const == int const * const

あなたが本当に夢中になりたいなら、あなたはこのようなことをすることができます:

  • int ** -intへのポインターへのポインター
  • int ** const -intへのポインタへのconstポインタ
  • int * const * -intへのconstポインタへのポインタ
  • int const ** -const intへのポインタへのポインタ
  • int * const * const -intへのconstポインタへのconstポインタ
  • ...

そして、私たちが以下の意味を明確にするためにconst

int a = 5, b = 10, c = 15;

const int* foo;     // pointer to constant int.
foo = &a;           // assignment to where foo points to.

/* dummy statement*/
*foo = 6;           // the value of a can´t get changed through the pointer.

foo = &b;           // the pointer foo can be changed.



int *const bar = &c;  // constant pointer to int 
                      // note, you actually need to set the pointer 
                      // here because you can't change it later ;)

*bar = 16;            // the value of c can be changed through the pointer.    

/* dummy statement*/
bar = &a;             // not possible because bar is a constant pointer.           

foo定数整数への変数ポインターです。これにより、ポイントする値を変更できますが、ポイントする値は変更できません。ほとんどの場合、これはCスタイルの文字列で見られ、へのポインタがありconst charます。指し示す文字列は変更できますが、これらの文字列の内容を変更することはできません。これは、文字列自体がプログラムのデータセグメント内にあり、変更してはならない場合に重要です。

bar変更可能な値への定数または固定ポインターです。これは、余分な構文糖がない参照のようなものです。このため、T* constポインタを許可する必要がない限り、通常はポインタを使用する参照を使用しNULLます。


482
「const」がポインターまたはポイントされたデータに適用されるかどうかを見つける方法を覚えておくのに役立つ経験則を追加したいと思います。次に、ステートメントをアスタリスク記号で分割し、次にconstキーワードが左側にある場合( 'const int * foo')-それが正しい部分にある場合( 'int * const bar')-ポインターに関するものです。
マイケル、

14
@Michael:constルールを記憶/理解するためのこのような単純なルールについてMichaelに称賛
sivabudh 2010

10
@Jeffrey:括弧がない限り、逆方向に読むとうまくいきます。次に、
typedefsを

12
+1、ただしより良い要約は次のようになります:ポインター宣言を逆方向読み取ります。つまり、@ Michaelのステートメントに近くなります。最初のアスタリスクで通常の​​左から右への読み取りを停止します。
ウルフ

3
@gedamialは動作しますが、正常に動作しますが、宣言と同時に割り当てる必要があります(「constポインタ」を再割り当てできないため)。const int x = 0; const int *const px = &x; const int *const *const p = &px;正常に動作します。
ラスタジェダイ2016

356

時計回り/スパイラルルールについて知らない場合:変数の名前から始めて、時計回りに(この場合は後方に)移動し、次のポインターに移動するか、を入力します。式が終了するまで繰り返します。

ここにデモがあります:

intへのポインタ

int constへのconstポインタ

int constへのポインタ

const intへのポインタ

intへのconstポインタ


8
@Jan複雑な例のリンクには権限がありません。ここに直接投稿できますか、それとも閲覧制限を解除できますか?
R71

8
@Rogには以前はすべてのオープンアクセス許可がありました...残念ながら、私は記事を書きませんでしたし、自分でもアクセス許可を持っていませんでした。しかし、ここではまだ動作します記事のアーカイブされたバージョンは、次のとおりです。archive.is/SsfMX
月Rüegg

8
複雑な例はまだ右から左ですが、通常の方法で括弧を解決することが含まれています。時計回りのらせん状のもの全体は、それを容易にしません。
Matthewが

4
究極の例:void (*signal(int, void (*fp)(int)))(int);archive.is/SsfMXから
naXa

3
このルールに依存しないでください。これは普遍的ではありません。失敗する場合があります。
2017年

150

私はすべてここですでに回答されていると思いますが、あなたがtypedefsに注意する必要があることを付け加えておきます!それらは単なるテキスト置換ではありません。

例えば:

typedef char *ASTRING;
const ASTRING astring;

のタイプはでastringchar * constなくconst char *です。これは、私が常にconst型の右側に置く傾向がある1つの理由であり、最初は決してしません。


20
そして私にとって、これがtypedefポインターを決してしない理由です。私はのようなものでは利益が表示されていないtypedef int* PINT(私はそれをやってCにおける慣行や多くの開発者から来たその何かを続けたと仮定します)。すごい、私はそれ*をに置き換えましたP、それはタイピングをスピードアップしません、そしてあなたが言及する問題を紹介します。
Mephane、2011年

1
@メファン-私はそれを見ることができます。ただし、この言語機能を安全に使用できるように例外的な構文規則の使用を回避するのではなく、例外的な構文規則(「const」配置について)を使用し続けるために、優れた言語機能を回避することは、私にとっては少し逆のように見えます。
TEDの

6
@Mephane PINTは確かに、typedefのかなり馬鹿げた使用法です。特に、システムストアはメモリにビールを使用していると思います。ただし、typedefは、関数へのポインターを処理するのに非常に役立ちます。
へのアプローチ

5
@KazDragonありがとうございます!それがなければ、私はこれらすべてのtypedefedで台無しただろうPVOIDLPTSTRWin32 APIの中のもの!
デビッドリー

2
@Mephane:タイプを受け入れるように作成された特定のレガシーマクロを使用する場合、pSomethingを数回使用する必要がありましたが、タイプが単一の英数字識別子でない場合は壊れます。:)
Groo

56

ほとんどの人が指摘したように:

何の違いだconst X* pX* const pconst X* const p

ポインタ宣言は右から左に読む必要があります。

  • const X* p 「pはconstであるXを指す」を意味します。Xオブジェクトはpを介して変更できません。

  • X* const p 「pは非constであるXへのconstポインターです」:ポインターp自体を変更することはできませんが、pを介してXオブジェクトを変更できます。

  • const X* const p 「pはconstであるXへのconstポインターです」:ポインターp自体を変更することも、pを介してXオブジェクトを変更することもできません。


3
ことを忘れないでくださいconst X* p;== X const * p;のように"p points to an X that is const": the X object can't be changed via p.
ジェシー・チザム

シンプルでいい説明!
Edison Lo

50
  1. 定数参照:

    定数である変数(ここではint)への参照。参照は実際の値よりもサイズが小さいため、主に変数を参照として渡しますが、副作用があり、それは実際の変数のエイリアスのようなものであるためです。エイリアスへのフルアクセスを通じて誤ってメイン変数を変更する可能性があるため、この副作用を防ぐために定数を一定にします。

    int var0 = 0;
    const int &ptr1 = var0;
    ptr1 = 8; // Error
    var0 = 6; // OK
  2. 定数ポインター

    定数ポインタが変数を指すと、他の変数を指すことはできません。

    int var1 = 1;
    int var2 = 0;
    
    int *const ptr2 = &var1;
    ptr2 = &var2; // Error
  3. 定数へのポインタ

    それが指す変数の値を変更できないポインターは、定数へのポインターと呼ばれます。

    int const * ptr3 = &var2;
    *ptr3 = 4; // Error
  4. 定数への定数ポインター

    定数への定数ポインターは、それが指しているアドレスを変更できず、そのアドレスに保持されている値も変更できないポインターです。

    int var3 = 0;
    int var4 = 0;
    const int * const ptr4 = &var3;
    *ptr4 = 1;     // Error
     ptr4 = &var4; // Error

20

一般的なルールは、constキーワードはその直前にあるものに適用されるということです。例外として、開始constは次のものに適用されます。

  • const int*はと同じでint const*「定数intへのポインタ」を意味します
  • const int* constと同じでint const* const「定数intへの定数ポインタ」を意味します

編集: すべきこととすべきでないことについて、この答えが十分でない場合は、あなたが望むものについてより正確にすることができますか?


19

この質問は、質問で述べたように、タイプIDが受け入れられた後のconstを行うのが好きな理由を正確に示しています。

要するに、ルールを覚える最も簡単な方法は、「c​​onst」が適用されるものの後に来るということです。したがって、あなたの質問では、「int const *」はintが定数であることを意味し、「int * const」はポインタが定数であることを意味します。

誰かが最前線に置くことを決定した場合(例: "const int *")、その場合の特別な例外として、それはその後のものに適用されます。

多くの人々は、この特別な例外をより見栄えが良いと思うので、使用したいと考えています。例外なので混乱するので嫌いです。


2
私はこの問題で引き裂かれました。論理的には理にかなっています。ただし、ほとんどのC ++開発者が作成しconst T*、より自然になりました。T* constとにかくどれほど頻繁に使用しますか。通常、参照で十分です。私が欲しいときにこのすべてに一度遭遇しboost::shared_ptr<const T>、代わりに書いたconst boost::shared_ptr<T>。わずかに異なるコンテキストで同じ問題。
マット価格

実際、私は定数を使用するよりも定数ポインタを使用しています。また、ポインタへのポインタ(など)が存在する場合にどのように反応するかについて考える必要があります。確かにそれはまれですが、これらの状況をApplombで処理できるように考えることは良いことです。
TED

1
型の右側にconstを配置することのもう1つの優れた利点は、左側のすべてconstがconstである型であり、右側のすべてが実際にconstである型であることです。int const * const * p;例として考えてみましょう。いいえ、通常はそのように記述しません。これは単なる例です。まずconst、intと入力します。また、constであるintは、の内容であるconstポインターの内容ですp。2番目のconst:タイプはconstint へのポインター、const oblectの内容p
dgnuff '15年

18

の簡単な使用const

最も簡単な使い方は、名前付き定数を宣言することです。これを行うには、定数を変数のように宣言しますが、そのconst前に追加します。もちろん、値を変更するため、後で値を設定することはできないため、コンストラクタですぐに初期化する必要があります。例えば:

const int Constant1=96; 

想像を絶すると呼ばれるConstant1、値96の整数定数を作成します。

このような定数は、プログラムで使用されるパラメーターに役立ちますが、プログラムのコンパイル後に変更する必要はありません。#defineメインコンパイラに到達する前にプリプロセッサによってプログラムテキストに代入されるだけでなく、コンパイラ自体によって理解および使用されるという点で、Cプリプロセッサコマンドよりもプログラマにとって利点があります。そのため、エラーメッセージははるかに役立ちます。

ポインターでも機能しますがconst、ポインターまたはポインターが指すものが定数であるか、またはその両方であるかを判断する場所に注意する必要があります。例えば:

const int * Constant2 

それConstant2が定数整数への可変ポインタであることを宣言し、そして:

int const * Constant2

同じことをする代替構文ですが、

int * const Constant3

それConstant3が可変整数への定数ポインタであることを宣言し、

int const * const Constant4

Constant4定数整数への定数ポインタであることを宣言します。基本的に 'const'はそのすぐ左にあるものすべてに適用されます(そこに何もない場合を除いて、そのすぐ右にあるものに適用されます)。

ref:http : //duramecho.com/ComputerInformation/WhyHowCppConst.html


9

C ++の教祖スコットマイヤーズによってこの本に出会うまで、私はあなたと同じ疑問を抱きました。この本の3番目の項目を参照してください。彼はの使用について詳しく説明していconstます。

このアドバイスに従ってください

  1. 単語constがアスタリスクの左側にある場合、指し示されているのは定数です
  2. 単語constがアスタリスクの右側にある場合、ポインタ自体は定数です
  3. const両側に現れる場合、両方が一定です

7

シンプルですがトリッキーです。我々は入れ替えることができますのでご注意くださいconst任意のデータ型(と修飾子をintcharfloat、など)。

以下の例を見てみましょう。


const int *p==> *pは読み取り専用です[ pは定数整数へのポインタです]

int const *p==> *pは読み取り専用です[ pは定数整数へのポインタです]


int *p const==> 誤った声明。コンパイラーは構文エラーをスローします。

int *const p==> pは読み取り専用です[ pは整数への定数ポインタです]。ここでのポインターpは読み取り専用であるため、宣言と定義は同じ場所になければなりません。


const int *p const ==> 誤った声明。コンパイラーは構文エラーをスローします。

const int const *p ==> *pは読み取り専用です

const int *const p1 ==> *pおよびp読み取り専用です[ pは定数整数への定数ポインター]。ここでのポインターpは読み取り専用であるため、宣言と定義は同じ場所になければなりません。


int const *p const ==> 誤った声明。コンパイラーは構文エラーをスローします。

int const int *p ==> 誤った声明。コンパイラーは構文エラーをスローします。

int const const *p ==> *pは読み取り専用で、以下と同等ですint const *p

int const *const p ==> *pおよびp読み取り専用です[ pは定数整数への定数ポインター]。ここでのポインターpは読み取り専用であるため、宣言と定義は同じ場所になければなりません。


6

C ++のconstの正確性には、他にも多くの微妙な点があります。ここでの質問は単にCに関するものだと思いますが、タグがC ++であるため、関連する例をいくつか示します。

  • 文字列などの大きな引数を渡すとTYPE const &、オブジェクトが変更またはコピーされるのを防ぐことができます。例:

    TYPE& TYPE::operator=(const TYPE &rhs) { ... return *this; }

    ただしTYPE & const、参照は常にconstであるため、意味がありません。

  • クラスを変更しないクラスメソッドには常にラベルを付けるconst必要があります。そうしないと、TYPE const &参照からメソッドを呼び出すことができません。例:

    bool TYPE::operator==(const TYPE &rhs) const { ... }

  • 戻り値とメソッドの両方がconstでなければならない一般的な状況があります。例:

    const TYPE TYPE::operator+(const TYPE &rhs) const { ... }

    実際、constメソッドは、constへの参照として内部クラスデータを返してはなりません。

  • その結果、constオーバーロードを使用して、constメソッドとnon-constメソッドの両方を作成する必要があることがよくあります。たとえば、を定義するT const& operator[] (unsigned i) const;場合は、おそらく次のようにして、非constバージョンも必要になります。

    inline T& operator[] (unsigned i) { return const_cast<char&>( static_cast<const TYPE&>(*this)[](i) ); }

Afaik、Cにはconst関数がないため、非メンバー関数自体をC ++でconstにすることはできません。constメソッドには副作用があり、コンパイラーはconst関数を使用して関数呼び出しの重複を回避できません。実際、単純なint const &参照でさえ、それが参照する値が他の場所で変更されるのを目撃するかもしれません。


6

CおよびC ++宣言構文は、元の設計者によって、失敗した実験として繰り返し説明されてきました。

代わりに、タイプに「ポインタ」という名前を付けましょうType。私はそれを呼びますPtr_

template< class Type >
using Ptr_ = Type*;

Ptr_<char>はへのポインタcharです。

Ptr_<const char>へのポインタconst charです。

そしてへconst Ptr_<const char>constポインタconst charです。

そこ。

ここに画像の説明を入力してください


3
最初の文の引用はありますか?
sp2danny 2016

@ sp2danny:グーグルの「C構文の失敗した実験」は、Bjarne Stroustrupとのインタビューの数だけを咳き込んで、彼はその方向で自分の意見を表明ます。したがって、Cの元の設計者の視点についての主張については言及していません。十分に強力な研究努力によって見つかるか、または単に尋ねるだけで反証できると思いますが、今の方法のほうが良いと思います。主張のその部分で、まだ決定されておらず、真実である可能性があります:)
乾杯とhth。-Alf

1
「CおよびC ++宣言構文は、元の設計者によって、失敗した実験として繰り返し説明されてきました。」Cの場合は間違っています。Cに関する文を変更するか、引用符を付けてください。
Stargateur

3
@Stargateur:どうやら前のコメントを読んで、ペダントリーに活用できる何かを見つけました。あなたの人生で頑張ってください。とにかく、私のような昔ながらの人は、非常に時間のかかる研究に従事せずには証明できないことをたくさん覚えています。あなたは私の言葉を取ることができます。
乾杯とhth。-アルフ

1
@Stargateur 「Sethi(...)は、間接演算子が接頭辞ではなく後置演算子として使用された場合、ネストされた宣言と式の多くが単純になることを観察しましたが、それまでに変更するには遅すぎました。」DMRからです。もちろん、DMRはconstおよびvolatileキーワードを発明しませんでした。それらは、そのページで証明されているように、C ++ / X3J11からのものです。
Antti Haapala

6

私にとっては、のconst相対的な位置、つまり、左または右に表示されるか、左と右の両方に表示されるか*は、実際の意味を理解するのに役立ちます。

  1. A constの左側には、*ポインタが指すオブジェクトであることを示すconstオブジェクト。

  2. const右側には、*ポインタがあることを示すconstポインタ。

次の表は、スタンフォードCS106L標準C ++プログラミングラボコースリーダーからの抜粋です。

ここに画像の説明を入力してください


3

これは主に2行目を扱います:ベストプラクティス、割り当て、関数パラメーターなど。

一般的な練習。constできることはすべて作るようにしてください。または別の言い方をすれば、すべてconstを最初から作成し、constプログラムが機能するために必要な最小限ののセットを正確に削除します。これは、const-correctnessを達成する上で大きな助けとなり、変更してはならないものに人々が割り当てようとしたときに、微妙なバグが導入されないようにするのに役立ちます。

ペストのようなconst_cast <>は避けてください。これには1つまたは2つの正当な使用例がありますが、その数は非常に少なく、はるかに異なります。constオブジェクトを変更しようとしている場合constは、最初のペースでオブジェクトを宣言した人を見つけ、何が起こるかについてコンセンサスを得るために彼らと話し合って問題を解決する方がはるかに効果的です。

これは非常にきちんと割り当てにつながります。constでない場合にのみ、何かに代入できます。constであるものに割り当てたい場合は、上記を参照してください。宣言int const *foo;int * const bar;さまざまなことで覚えておいてくださいconst-ここでの他の回答はその問題を立派にカバーしているので、ここでは触れません。

関数パラメーター:

値渡し:たとえばvoid func(int param)、呼び出し元サイトでは、どちらかを気にしません。引数は、関数を宣言するためのユースケースvoid func(int const param)があるが、渡された値は呼び出し中に関数によって変更できないという点で、関数自体にのみ影響し、呼び出し元には影響を与えないようにすることができます。

参照渡し:たとえば、void func(int &param)今では違いが出ます。宣言されたとおりfunc、変更が許可されてparamおり、呼び出し元のサイトは結果に対処する準備ができている必要があります。宣言をvoid func(int const &param)変更して契約を変更し、func変更できないことを保証しますparam。つまり、渡されたものが戻ってきます。他の人が指摘したように、これは、変更したくない大きなオブジェクトを安く渡すために非常に便利です。参照を渡す方が、値の大きいオブジェクトを渡すよりもはるかに安価です。

ポインタによる受け渡し:たとえばvoid func(int *param)およびvoid func(int const *param)これら2つは参照の対応物とほとんど同義です。nullptrただし、他の契約上の保証によってinをfunc受信しないことが保証されていない限り、呼び出された関数はチェックする必要があるという警告があります。nullptrparam

そのトピックに関する意見の一部。このようなケースで正しさを証明することは地獄のように難しいです。間違いを犯すのはあまりにも簡単です。ですから、チャンスをとらないでくださいnullptr。常にのポインタパラメータを確認してください。あなたはあなた自身の痛みと苦しみを救い、長期的にバグを見つけるのを難しくします。そして、チェックのコストに関しては、それは非常に安価であり、コンパイラに組み込まれた静的分析がそれを管理できる場合、オプティマイザはとにかくそれを排除します。MSVCのリンクタイムコード生成、またはGCCのWOPR(私は思う)をオンにすると、プログラム全体、つまり、ソースコードモジュールの境界を越える関数呼び出しでも、プログラム全体が得られます。

結局のところ、上記のすべてが常にポインタへの参照を好む非常に堅実なケースを作ります。彼らはただずっと安全です。


3

どちらかの側にintを持つconstは、定数intへのポインターを作成します

const int *ptr=&i;

または:

int const *ptr=&i;

constafter *intへの定数ポインタを作成します

int *const ptr=&i;

この場合、これらはすべて定数integerへのポインターですが、これらはどれも定数ポインターではありません。

 const int *ptr1=&i, *ptr2=&j;

この場合、すべてが定数整数へのポインターであり、ptr2は定数整数への定数ポインターです。しかし、ptr1は定数ポインタではありません。

int const *ptr1=&i, *const ptr2=&j;

3
  • 場合const左へ*、それは値を参照(だかどうかは関係ありませんconst intint const
  • の右側にある場合constは、ポインタ自体を参照します*
  • それは同時に両方にすることができます

重要なポイント:const int *p 参照している値が一定であるという意味ではありません!! 。これは、そのポインターを通じて変更できないこと意味します(つまり、$ * p = ... `を割り当てることはできません)。値自体は他の方法で変更される場合があります。例えば

int x = 5;
const int *p = &x;
x = 6; //legal
printf("%d", *p) // prints 6
*p = 7; //error 

これは、関数が誤って渡された引数を変更できないことを保証するために、主に関数シグネチャで使用されることを意図しています。


2

他の説明に続くCの完全性のために、C ++についてはわかりません。

  • pp-ポインターへのポインター
  • p-ポインター
  • データ-指摘されていること、例 x
  • 太字 -読み取り専用変数

ポインタ

  • pデータ- int *p;
  • p データ -int const *p;
  • pデータ-int * const p;
  • p データ -int const * const p;

ポインターへのポインター

  1. pp pデータ- int **pp;
  2. pp pデータ-int ** const pp;
  3. pp pデータ-int * const *pp;
  4. pp p データ -int const **pp;
  5. pp pデータ-int * const * const pp;
  6. pp p データ -int const ** const pp;
  7. pp p データ -int const * const *pp;
  8. pp p データ -int const * const * const pp;
// Example 1
int x;
x = 10;
int *p = NULL;
p = &x;
int **pp = NULL;
pp = &p;
printf("%d\n", **pp);

// Example 2
int x;
x = 10;
int *p = NULL;
p = &x;
int ** const pp = &p; // Definition must happen during declaration
printf("%d\n", **pp);

// Example 3
int x;
x = 10;
int * const p = &x; // Definition must happen during declaration
int * const *pp = NULL;
pp = &p;
printf("%d\n", **pp);

// Example 4
int const x = 10; // Definition must happen during declaration
int const * p = NULL;
p = &x;
int const **pp = NULL;
pp = &p;
printf("%d\n", **pp);

// Example 5
int x;
x = 10;
int * const p = &x; // Definition must happen during declaration
int * const * const pp = &p; // Definition must happen during declaration
printf("%d\n", **pp);

// Example 6
int const x = 10; // Definition must happen during declaration
int const *p = NULL;
p = &x;
int const ** const pp = &p; // Definition must happen during declaration
printf("%d\n", **pp);

// Example 7
int const x = 10; // Definition must happen during declaration
int const * const p = &x; // Definition must happen during declaration
int const * const *pp = NULL;
pp = &p;
printf("%d\n", **pp);

// Example 8
int const x = 10; // Definition must happen during declaration
int const * const p = &x; // Definition must happen during declaration
int const * const * const pp = &p; // Definition must happen during declaration
printf("%d\n", **pp);

逆参照のNレベル

続けるだけですが、人類があなたを破門することがあります。

int x = 10;
int *p = &x;
int **pp = &p;
int ***ppp = &pp;
int ****pppp = &ppp;

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

0
  1. const int*-定数intオブジェクトへのポインタ。

ポインタの値を変更できます。intポインタが指すオブジェクトの値を変更することはできません。


  1. const int * const-定数intオブジェクトへの定数ポインタ。

ポインターの値や、ポインターが指すintオブジェクトの値を変更することはできません。


  1. int const *-定数intオブジェクトへのポインタ。

このステートメントは1と同等const int*です。-ポインターの値は変更できますが、ポインターが指すintオブジェクトの値は変更できません。


実際には、4番目のオプションがあります。

  1. int * const- intオブジェクトへの定数ポインタ。

ポインタが指すオブジェクトの値は変更できますが、ポインタ自体の値は変更できません。ポインターは常に同じintオブジェクトを指しますが、このintオブジェクトのこの値は変更できます。


特定のタイプのCまたはC ++構成を判別したい場合は、David Andersonによって作成された時計回り/らせん規則を使用できます。ただし、Ross J. Andersonが作成したAndersonの規則と混同しないようにしてください。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.