What is the difference between const int*, const int * const, and int const *?
我总是搞砸如何正确使用
我想知道在分配、传递函数等方面的所有应做和不应做的事情。
向后读(由顺时针/螺旋法则驱动):
int* —指向int的指针int const * —指向const int的指针int * const —指向int的常量指针int const * const const指向const int的指针
现在,第一个
const int * ==int const * 。const int * const ==int const * const 。
如果你想发疯,你可以这样做:
int ** —指向指向int的指针int ** const —指向指向int的指针的常量指针。int * const * —指向常量指针的指针,指向intint const ** —指向常量int指针的指针。int * const * const —指向int的const指针的const指针- …
确保我们对const的含义有明确的认识
1 2 3 | const int* foo; int *const bar; //note, you actually need to set the pointer //here because you can't change it later ;) |
对于那些不知道顺时针/螺旋法则的人:从变量名开始,按顺序移动(在本例中,向后移动)到下一个指针或类型。重复,直到表达式结束。
这是一个演示:
我想这里已经回答了所有问题,但我想补充一点,你应该小心以东十一〔28〕号!它们不仅仅是文本替换。
例如:
1 2 | typedef char *ASTRING; const ASTRING astring; |
就像几乎所有人都指出的那样:
You have to read pointer declarations
right-to-left.
const X* p means"p points to an X that is const": the X object can't be changed via p.
X* const p means"p is a const pointer to an X that is non-const": you can't change the pointer p itself, but you can change the X object via p.
const X* const p means"p is a const pointer to an X that is const": you can't change the pointer p itself, nor can you change the X object via p.
常量引用:
对变量(这里是int)的引用,它是常量。我们主要将变量作为引用传递,因为引用的大小比实际值小,但有一个副作用,这是因为它就像是实际变量的别名。我们可能会通过对别名的完全访问意外地更改主变量,因此我们将其设置为常量以防止这种副作用。
1 2 3 4 | int var0 = 0; const int &ptr1 = var0; ptr1 = 8; // Error var0 = 6; // OK |
常量指针
一旦常量指针指向一个变量,那么它就不能指向任何其他变量。
1 2 3 4 5 | int var1 = 1; int var2 = 0; int *const ptr2 = &var1; ptr2 = &var2; // Error |
指向常量的指针
一个指针,通过它不能改变它所指向的变量的值,称为指向常量的指针。
1 2 | int const * ptr3 = &var2; *ptr3 = 4; // Error |
常量指针指向常量
指向常量的常量指针是既不能更改其指向的地址,也不能更改保存在该地址的值的指针。
1 2 3 4 5 | int var3 = 0; int var4 = 0; const int * const ptr4 = &var3; *ptr4 = 1; // Error ptr4 = &var4; // Error |
一般规则是,
const int* 与int const* 相同,意思是"指向常量int的指针"。const int* const 与int const* const 相同,表示"常数指针指向常数int"。
编辑:对于应该做和不应该做的,如果这个答案不够,你能更准确地说出你想要什么吗?
这个问题确切地说明了为什么我喜欢按照我在问题中提到的方法来做,即类型ID之后的const是可接受的?
简而言之,我发现记住规则的最简单方法是"const"跟踪它适用的对象。所以在您的问题中,"int const*"表示int是常量,"int*const"表示指针是常量。
如果有人决定把它放在最前面(例如:"const int*"),作为一个特殊的例外,它适用于后面的事情。
许多人喜欢使用这个特殊的例外,因为他们认为它看起来更好。我不喜欢它,因为它是一个例外,因此混淆了事情。
"const"的简单用法
最简单的用法是声明一个命名常量。为此,我们声明一个常量,就像它是一个变量一样,但在它前面添加"const"。必须在构造函数中立即初始化它,因为当然,以后不能设置值,因为这样会改变它。例如,
1 | const int Constant1=96; |
将创建一个整型常量,不可想象地称为"Constant1",值为96。
这些常量对于程序中使用的参数很有用,但在程序编译后不需要更改。对于程序员来说,它比C预处理器"define"命令有一个优势,因为它被编译器本身理解和使用,而不仅仅是在到达主编译器之前被预处理器替换成程序文本,因此错误消息更有用。
它也适用于指针,但必须注意"const"的位置,以确定指针或它指向的对象是常量还是两者都是常量。例如,
1 | const int * Constant2 |
声明Constant2是指向常量整数的变量指针,并且
1 | int const * Constant2 |
是执行相同操作的可选语法,而
1 | int * const Constant3 |
声明constant3是指向变量integer的常量指针,并且
1 | int const * const Constant4 |
声明Constant4是指向常量整数的常量指针。基本上,"const"适用于其左上角的任何部分(如果没有任何部分,在这种情况下,它适用于其右上角的任何部分)。
参考:http://duramecho.com/computerinformation/whyhowcpconst.html
我遇到了同样的疑问,直到我遇到这本书的C++大师Scott Meyers。参考这本书中的第三项,他详细讨论了使用
照这个建议去做
这很简单,但很棘手。请注意,我们可以用任何数据类型(
让我们看看下面的例子。
C和C++声明语法反复被原始设计者描述为失败的实验。
相反,让我们将类型命名为“指向
1 2 | template< class Type > using Ptr_ = Type*; |
现在,
那里。
C++中有许多其他的关于const正确性的微妙点。我想这里的问题仅仅是关于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 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(
static_cast(*this)[](i)
);
}
另外,C中没有const函数,非成员函数本身不能在C++中被const,const方法可能会有副作用,编译器不能使用const函数来避免重复函数调用。事实上,即使是一个简单的
对我来说,
下表由斯坦福大学CS106L标准C++编程实验室课程阅读器获取。
两边都有int的const将成为指向常量int的指针。
1 | const int *ptr=&i; |
或
1 | int const *ptr=&i; |
"*"后面的常量将成为指向int的常量指针。
1 | int *const ptr=&i; |
在这种情况下,所有这些都是指向常量整数的指针,但没有一个是常量指针。
1 | const int *ptr1=&i, *ptr2=&j; |
在这种情况下,都是指向常量整数的指针,ptr2是指向常量整数的常量指针。但是ptr1不是常量指针。
1 | int const *ptr1=&i, *const ptr2=&j; |
为了满足C的完整性,遵循其他解释,不确定C++。
- pp-指向指针的指针
- P指针
- 数据-在示例
x 中指出的事情 - 粗体-只读变量
指针
- P数据-
int *p; 。 - P数据-
int const *p; 。 - P数据-
int * const p; 。 - P数据-
int const * const p; 。
指向指针的指针
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | // Example 1 int x; x = 10; int *p = NULL; p = &x; int **pp = NULL; pp = &p; printf("%d ", **pp); // Example 2 int x; x = 10; int *p = NULL; p = &x; int ** const pp = &p; // Definition must happen during declaration printf("%d ", **pp); // Example 3 int x; x = 10; int * const p = &x; // Definition must happen during declaration int * const *pp = NULL; pp = &p; printf("%d ", **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 ", **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 ", **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 ", **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 ", **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 ", **pp); |
n-取消引用的级别
继续前进,但希望人类将你逐出教会。
1 2 3 4 5 6 7 8 | int x = 10; int *p = &x; int **pp = &p; int ***ppp = &pp; int ****pppp = &ppp; printf("%d ", ****pppp); |
这主要涉及第二行:最佳实践、分配、函数参数等。
一般做法。尽量把你能做的一切都做出来。或者换一种方式,使所有的
避免像瘟疫一样施法。它有一个或两个合法的用例,但它们非常少,而且相距甚远。如果你试图改变一个
这很容易导致作业。只有当某事物是非常量时,才能将其赋值。如果您想分配给常量,请参见上面的。记住,在声明中,
功能参数:
传递值:例如,
通过引用:例如,
传递指针:例如,
关于那个话题的意见。在这种情况下证明正确是非常困难的,犯错误太容易了。所以不要冒险,总是检查
在一天结束的时候,上面的所有内容都是非常可靠的,总是倾向于引用指针。它们只是更安全而已。