const int*
私はいつも、、、const int * const
そしてint const *
正しく使用する方法を台無しにします。できることとできないことを定義する一連のルールはありますか?
割り当て、関数への受け渡しなどに関して、すべてのすべきこととすべきでないことを知りたいです。
逆方向に読んでください(時計回り/スパイラルルールによって駆動されます):
int*
--intへのポインタint const *
--constintへのポインタint * const
--intへのconstポインタint const * const
--constintへのconstポインタこれで、最初const
はタイプのいずれかの側に配置できるため、次のようになります。
const int *
==int const *
const int * const
==int const * const
あなたが本当に夢中になりたいなら、あなたはこのようなことをすることができます:
int **
--intへのポインタへのポインタint ** const
-intへのポインタへのconstポインタint * const *
--constへのポインタintへのポインタint const **
-constintへのポインタへのポインタ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
ます。
時計回り/スパイラルルールについて知らない人のために:変数の名前から始めて、時計回りに移動し(この場合は後方に移動します)、次のポインターに移動するか、と入力します。式が終了するまで繰り返します。
これがデモです:
ここですべてがすでに答えられていると思いますが、私はあなたがtypedef
sに注意する必要があることを付け加えたいと思います!それらは単なるテキスト置換ではありません。
例えば:
typedef char *ASTRING;
const ASTRING astring;
のタイプastring
はchar * const
、ではありませんconst char *
。const
これが、私が常にタイプの右側に配置する傾向があり、最初は決して配置しない理由の1つです。
ほとんどの人が指摘したように:
const X* p
、X* const p
との違いは何const 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オブジェクトを変更することもできません。
一定の参照:
定数である変数(ここではint)への参照。参照は実際の値よりもサイズが小さいため、主に変数を参照として渡しますが、副作用があり、それは実際の変数のエイリアスのようなものであるためです。エイリアスへのフルアクセスによって誤ってメイン変数を変更する可能性があるため、この副作用を防ぐために一定にしています。
int var0 = 0;
const int &ptr1 = var0;
ptr1 = 8; // Error
var0 = 6; // OK
定数ポインタ
定数ポインタが変数を指すと、他の変数を指すことはできません。
int var1 = 1;
int var2 = 0;
int *const ptr2 = &var1;
ptr2 = &var2; // Error
定数へのポインタ
指す変数の値を変更できないポインターは、定数へのポインターと呼ばれます。
int const * ptr3 = &var2;
*ptr3 = 4; // Error
定数への定数ポインタ
定数への定数ポインターは、それが指しているアドレスを変更することも、そのアドレスに保持されている値を変更することもできないポインターです。
int var3 = 0;
int var4 = 0;
const int * const ptr4 = &var3;
*ptr4 = 1; // Error
ptr4 = &var4; // Error
原則として、const
キーワードはその直前に適用されます。例外として、開始const
は次のものに適用されます。
const int*
「定数intへのポインタ」と同じでint const*
あり、それを意味します。const int* const
は「定数intへの定数ポインタ」と同じでint const* const
あり、それを意味します。編集: すべきこととすべきでないことについて、この答えが十分でない場合、あなたはあなたが望むものについてより正確にできますか?
この質問は、私の質問で述べた方法がタイプIDの後にconstである理由を正確に示していますか?
要するに、ルールを覚える最も簡単な方法は、「const」が適用されるものの後に続くということです。したがって、あなたの質問では、「int const *」はintが定数であることを意味し、「int*const」はポインタが定数であることを意味します。
誰かがそれを一番前に置くことにした場合(例: "const int *")、その場合の特別な例外として、それはその後のものに適用されます。
多くの人は、見栄えが良いと思うので、その特別な例外を使用するのが好きです。それは例外であり、物事を混乱させるので、私はそれが嫌いです。
の簡単な使用const
。
最も簡単な使用法は、名前付き定数を宣言することです。これを行うには、定数を変数であるかのように宣言しますが、そのconst
前に追加します。もちろん、値を変更するため、後で値を設定することはできないため、コンストラクターですぐに初期化する必要があります。例えば:
const int Constant1=96;
Constant1
は、想像を絶するほどと呼ばれる、値96の整数定数を作成します。
このような定数は、プログラムで使用されるパラメーターに役立ちますが、プログラムのコンパイル後に変更する必要はありません。これは、Cプリプロセッサコマンドよりもプログラマーにとって利点があり#define
、メインコンパイラに到達する前にプリプロセッサによってプログラムテキストに置き換えられるだけでなく、コンパイラ自体によって理解および使用されるため、エラーメッセージがはるかに役立ちます。
const
ポインタでも機能しますが、ポインタまたはポインタが指すものが一定であるか、あるいはその両方であるかを判断する場所に注意する必要があります。例えば:
const int * Constant2
Constant2
それが定数整数への変数ポインタであることを宣言し、次のようにします。
int const * Constant2
は同じことを行う代替構文ですが、
int * const Constant3
Constant3
それが可変整数への定数ポインタであることを宣言し、
int const * const Constant4
Constant4
それが定数整数への定数ポインタであることを宣言します。基本的に、「const」はそのすぐ左にあるものすべてに適用されます(そこに何もない場合を除いて、そのすぐ右にあるものすべてに適用されます)。
参照:http ://duramecho.com/ComputerInformation/WhyHowCppConst.html
シンプルですが注意が必要です。const
修飾子は任意のデータ型(、、、int
など)char
に適用できることに注意してくださいfloat
。
以下の例を見てみましょう。
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 p
==>*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
は読み取り専用であるため、宣言と定義は同じ場所にある必要があります。
C++の第一人者であるScottMeyersがこの本に出くわすまで、私はあなたと同じ疑問を抱いていました。彼が使用について詳細に話しているこの本の3番目の項目を参照してくださいconst
。
このアドバイスに従ってください
const
が表示されている場合、ポイントされているのは一定ですconst
がアスタリスクの右側に表示されている場合、ポインター自体は一定ですconst
両側に表示される場合、両方が一定ですCおよびC++宣言構文は、元の設計者によって、失敗した実験として繰り返し説明されてきました。
代わりに、タイプに「pointerto」という名前を付けましょうType
。私はそれを呼びますPtr_
:
template< class Type >
using Ptr_ = Type*;
今Ptr_<char>
はへのポインタchar
です。
Ptr_<const char>
へのポインタconst char
です。
そしてconst Ptr_<const char>
、へのconst
ポインタconst char
です。
C++の定数の正確さを取り巻く他の多くの微妙な点があります。ここでの質問は単にCに関するものだと思いますが、タグがC ++であるため、関連する例をいくつか示します。
文字列のような大きな引数を渡すことがよくTYPE const &
あります。これにより、オブジェクトが変更またはコピーされるのを防ぎます。例 :
TYPE& TYPE::operator=(const TYPE &rhs) { ... return *this; }
しかしTYPE & 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;
、次の式で指定された非定数バージョンも必要になる可能性があります。
inline T& operator[] (unsigned i) {
return const_cast<char&>(
static_cast<const TYPE&>(*this)[](i)
);
}
Afaik、Cにはconst関数はなく、非メンバー関数自体をC ++でconstにすることはできません。また、constメソッドには副作用がある可能性があり、コンパイラーはconst関数を使用して重複する関数呼び出しを回避できません。実際、単純なint const &
参照でさえ、それが参照する値が他の場所で変更されるのを目撃する可能性があります。
constが*の前にある場合、値は定数です。
constが*の後にある場合、アドレスは一定です。
constが*の前後の両方で使用可能な場合、値とアドレスの両方が一定です。
例えば
int * const var; //ここでアドレスは定数です。
int const * var; //ここで値は定数です。
int const * const var; //値とアドレスの両方が一定です。
いずれかの側にintがあるconstは、定数intへのポインターを作成します。
const int *ptr=&i;
また:
int const *ptr=&i;
const
afterはintへの定数ポインタを*
作成します:
int *const ptr=&i;
この場合、これらはすべて定数整数へのポインターですが、これらはいずれも定数ポインターではありません。
const int *ptr1=&i, *ptr2=&j;
この場合、すべてが定数整数へのポインターであり、ptr2は定数整数への定数ポインターです。ただし、ptr1は定数ポインタではありません。
int const *ptr1=&i, *const ptr2=&j;
const
場合、それは値を参照します(それがであるかどうかは関係ありません)*
const int
int 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行目(ベストプラクティス、割り当て、関数パラメーターなど)に対応しています。
一般診療。あなたができるすべてを作るようにしconst
てください。または、別の言い方をすれば、最初にすべてを作成してから、プログラムを機能させるために必要なconst
最小限のセットを正確に削除します。const
これは、const-correctnessを達成する上で大きな助けとなり、人々が変更するはずのないものに割り当てようとしたときに微妙なバグが発生しないようにするのに役立ちます。
疫病のようにconst_cast<>は避けてください。正当なユースケースは1つか2つありますが、それらはごくわずかであり、その間にあります。オブジェクトを変更しようとしている場合は、最初のペースconst
でそれを宣言した人を見つけてconst
、何が起こるべきかについて合意に達するために彼らと問題について話し合う方がはるかに良いでしょう。
これは非常にきちんと割り当てにつながります。非定数の場合にのみ、何かに割り当てることができます。constであるものに割り当てる場合は、上記を参照してください。int const *foo;
宣言にint * const bar;
はさまざまなことが含まれていることを忘れないでください。const
ここでの他の回答はその問題を立派にカバーしているので、ここでは取り上げません。
関数パラメーター:
値渡し:たとえばvoid func(int param)
、呼び出し元のサイトでどちらの方法でもかまいません。関数をとして宣言するユースケースがありますがvoid func(int const param)
、呼び出し中に関数が渡す値は変更できないという点で、呼び出し元には影響せず、関数自体にのみ影響するという議論をすることができます。
参照渡し:たとえばvoid func(int ¶m)
、今では違いが生じます。宣言されたばかりのfunc
ように、変更が許可されてparam
おり、呼び出し元のサイトはその結果に対処する準備ができている必要があります。宣言を変更して契約を変更し、変更できないことvoid func(int const ¶m)
を保証します。つまり、渡されたものが返されるものです。他の人が指摘しているように、これは変更したくない大きなオブジェクトを安価に渡すのに非常に便利です。参照を渡すことは、大きなオブジェクトを値で渡すよりもはるかに安価です。func
param
ポインタを渡す:egvoid func(int *param)
とvoid func(int const *param)
これら2つは、対応する参照とほぼ同義ですが、nullptr
他の契約上の保証でinfunc
を受け取らないことが保証されていない限り、呼び出された関数がチェックする必要があるという警告があります。nullptr
param
そのトピックに関する意見記事。このような場合に正しさを証明することは非常に困難であり、間違いを犯すのは非常に簡単です。したがって、チャンスを逃さず、常にポインタパラメータをチェックしてくださいnullptr
。あなたは自分自身の痛みと苦しみを救い、長期的にはバグを見つけるのが難しいでしょう。そして、チェックのコストに関しては、それはかなり安いです、そしてコンパイラーに組み込まれた静的分析がそれを管理することができる場合、オプティマイザーはとにかくそれを排除します。MSVCの場合はリンク時コード生成、GCCの場合はWOPR(私は思う)をオンにすると、プログラム全体で、つまりソースコードモジュールの境界を越える関数呼び出しでも使用できるようになります。
結局のところ、上記のすべては、常にポインタへの参照を好むという非常に堅実なケースになります。彼らはすべてのラウンドでより安全です。
他の説明に従ったCの完全性のために、C++についてはわかりません。
x
int *p;
int const *p;
int * const p;
int const * const p;
int **pp;
int ** const pp;
int * const *pp;
int const **pp;
int * const * const pp;
int const ** const pp;
int const * const *pp;
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);
続けてください、しかし人類があなたを破門するかもしれません。
int x = 10;
int *p = &x;
int **pp = &p;
int ***ppp = &pp;
int ****pppp = &ppp;
printf("%d \n", ****pppp);
const int*
-定数int
オブジェクトへのポインタ。ポインタの値を変更できます。オブジェクトの値を変更することはできませんint
。ポインタが指します。
const int * const
-定数int
オブジェクトへの定数ポインタ。int
ポインタの値やポインタが指すオブジェクトの値を変更することはできません。
int const *
-定数int
オブジェクトへのポインタ。このステートメントは1と同等です。-ポインターの値を変更することはできますが、ポインターが指すオブジェクトconst int*
の値を変更することはできません。int
実際には、4番目のオプションがあります。
int * const
int
-オブジェクトへの定数ポインタ。ポインタが指すオブジェクトの値を変更することはできますが、ポインタ自体の値を変更することはできません。ポインタは常に同じint
オブジェクトを指しますが、このオブジェクトのこの値はint
変更できます。
特定のタイプのCまたはC++構造を判別する場合は、DavidAndersonによって作成された時計回り/スパイラルルールを使用できます。しかし、ロス・J・アンダーソンによって作成されたアンダーソンの規則と混同しないでください。これはまったく異なるものです。
単純なニーモニック:
type
ポインタ<-- *
>ポインタname
私は「の間接参照は」int *i
を宣言することと考えるのが好きです。この意味で、は「のderefは」を意味し、「のderefは」を意味します。i
int
const int *i
i
const int
int *const i
const i
int
int const *i
(このように考えることの1つの危険は、人々が嫌い/禁止するかもしれない宣言のスタイルを支持することにつながるかもしれないということです)
多くの人が正解しました。ここでうまく整理し、与えられた回答に欠けている追加情報をいくつか入れます。
Constは、修飾子とも呼ばれるC言語のキーワードです。Constを任意の変数の宣言に適用して、その値が変更されないことを指定できます
const int a=3,b;
a=4; // give error
b=5; // give error as b is also const int
you have to intialize while declaring itself as no way to assign
it afterwards.
読み方 ?
右から左に読むだけで、すべてのステートメントがスムーズに機能します
3つの主なもの
type a. p is ptr to const int
type b. p is const ptr to int
type c. p is const ptr to const int
[エラー]
if * comes before int
2種類
1. const int *
2. const const int *
私たちは最初に見る
メジャータイプ1。constint *
3つの場所に3つのものを配置する方法3!= 6
私。*開始時
*const int p [Error]
*int const p [Error]
ii。開始時の定数
const int *p type a. p is ptr to const int
const *int p [Error]
iii。開始時のint
int const *p type a.
int * const p type b. p is const ptr to int
メジャータイプ2。constconstint *
2が似ている4つの場所に4つのものを配置する方法4!/ 2!= 12
私。*開始時
* int const const p [Error]
* const int const p [Error]
* const const int p [Error]
ii。開始時のint
int const const *p type a. p is ptr to const int
int const * const p type c. p is const ptr to const int
int * const const p type b. p is const ptr to int
iii。開始時の定数
const const int *p type a.
const const * int p [Error]
const int const *p type a.
const int * const p type c.
const * int const p [Error]
const * const int p [Error]
オールインワンで絞る
aと入力します。pはptrからconstint(5)
const int *p
int const *p
int const const *p
const const int *p
const int const *p
タイプb。pはint(2)へのconstptrです
int * const p
int * const const p;
タイプc。pはconstptrto const int(2)
int const * const p
const int * const p
ほんの少しの計算
1. const int * p total arrangemets (6) [Errors] (3)
2. const const int * p total arrangemets (12) [Errors] (6)
少し余分
int const * p、p2;
here p is ptr to const int (type a.)
but p2 is just const int please note that it is not ptr
int * const p、p2;
similarly
here p is const ptr to int (type b.)
but p2 is just int not even cost int
int const * const p、p2;
here p is const ptr to const int (type c.)
but p2 is just const int.
終了した