const int *,const int * const和int const *有什么区别?
我总是搞砸了如何正确使用<code>const int* , const int * const
和int const *
。 是否有一组规则定义您可以做什么和不能做什么?
我想知道在分配,传递给函数等方面所有需要做的事情。
#1楼
向后读取(受“ 顺时针/螺旋规则”驱动):
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指针的const指针- ...
并确保我们清楚const的含义
const int* foo;
int *const bar; //note, you actually need to set the pointer //here because you can't change it later ;)
foo
是指向常量整数的变量指针。 这使您可以更改指向的内容,但不能更改指向的值。 最常见的情况是使用C样式的字符串,其中有指向const char
的指针。 您可以更改指向的字符串,但是不能更改这些字符串的内容。 当字符串本身位于程序的数据段中并且不应更改时,这一点很重要。
bar
是指向可以更改的值的常量或固定指针。 这就像没有多余语法糖的参考。 由于这个事实,除非需要允许使用NULL
指针,否则通常会在使用T* const
指针的地方使用引用。
#2楼
一般规则是const
关键字适用于紧随其后的内容。 例外,起始const
适用于以下内容。
const int*
与int const*
相同,表示“指向常量int的指针” 。const int* const
与int const* const
相同,表示“指向常量int的常量指针” 。
编辑:对于该做什么和不该做什么,如果这个答案还不够,您能否更精确地知道自己想要什么?
#3楼
简单使用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
#4楼
几乎每个人都指出:
const X* p
, X* const p
和const X* const p
什么区别?
您必须从右到左读取指针声明。
const X* p
表示“ p指向X是const”:不能通过p更改X对象。
X* const p
意思是“ p是指向非const X的const指针”:您不能更改指针p本身,但是可以通过p更改X对象。
const X* const p
意思是“ p是指向X的const指针,它是const”:您不能更改指针p本身,也不能通过p更改X对象。
#5楼
我认为这里已经回答了所有问题,但是我想补充一下,您应该提防typedef
! 它们不只是文本替换。
例如:
typedef char *ASTRING;
const ASTRING astring;
astring
的类型是char * const
,而不是const char *
。 这就是为什么我总是倾向于将const
放在类型的右边,而不是从一开始就这样做。
#6楼
这个问题正好说明了为什么我喜欢以我在问题中提到的方式在类型ID可接受之后以const的方式进行操作?
简而言之,我发现记住规则的最简单方法是,将“ const”放在要应用的内容之后 。 因此,在您的问题中,“ int const *”表示int是常量,而“ int * const”将表示指针是常量。
如果有人决定将其放在最前面(例如:“ const int *”),则在这种情况下,它是一个特殊的例外,适用于其后的事物。
许多人喜欢使用该特殊异常,因为他们认为它看起来更好。 我不喜欢它,因为这是一个例外,因此使事情变得混乱。
#7楼
常数参考:
对常量的变量(此处为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
#8楼
简单但棘手。 请注意,我们可以用任何数据类型( int
, char
, float
等)交换const
限定符。
让我们看下面的例子。
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
是只读的,因此声明和定义应位于同一位置。
#9楼
在您遇到C ++专家Scott Meyers的这本书之前,我一直和您有同样的疑问。 请参考本书的第三项,他在其中详细介绍了有关使用const
。
只要遵循这个建议
- 如果
const
单词出现在星号的左侧,则指向的是常量 - 如果单词
const
出现在星号的右边,则指针本身是常量 - 如果
const
出现在两边,则两者都是常数
#10楼
对于那些不了解顺时针/螺旋规则的人:从变量名开始,顺时针移动(在这种情况下,向后移动)到下一个指针或键入 。 重复直到表达式结束。
这是一个演示:
#11楼
最初的设计者多次将C和C ++声明语法描述为失败的实验。
相反,让我们将类型命名为“ Type
指针”。 我称它为Ptr_
:
template< class Type >
using Ptr_ = Type*;
现在Ptr_<char>
是一个指向char
。
Ptr_<const char>
是指向const char
的指针。
const Ptr_<const char>
是指向const char
的const
指针。
那里。
#12楼
这主要涉及第二行:最佳实践,分配,功能参数等。
一般惯例。 尝试使所有内容都成为const
。 或者换种说法,使所有const
都以const
开头,然后准确删除允许程序运行所需的最少const
集。 这将对实现const正确性有很大帮助,并且将有助于确保当人们尝试分配不应修改的内容时,不会引入细微的错误。
避免像瘟疫一样使用const_cast <>。 有一个或两个合法的用例,但它们之间相差无几。 如果您尝试更改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
,这意味着传入的内容将返回。 正如其他人指出的那样,这对于廉价传递不想更改的大对象非常有用。 传递引用比按值传递大对象便宜得多。
通过指针传递:例如void func(int *param)
和void func(int const *param)
这两个对象与它们的引用对象几乎是同义的,需要注意的是,除非有其他契约保证,否则被调用函数现在需要检查nullptr
确保func
它永远不会在param
收到nullptr
。
关于该主题的观点。 在这样的情况下证明正确性是非常困难的,这太容易出错了。 因此,不要冒险,请始终检查nullptr
指针参数。 从长远来看,您将避免痛苦和痛苦,并且难以发现错误。 至于检查的成本,它非常便宜,并且在编译器中内置的静态分析可以管理它的情况下,优化器仍然会忽略它。 打开MSVC的链接时间代码生成功能,或者打开GCC的WOPR(我认为)功能,您将在程序范围内实现它,即,即使在跨越源代码模块边界的函数调用中也是如此。
归根结底,上述所有情况都是一个非常可靠的案例,总是喜欢引用指针。 他们只是更安全。
#13楼
两侧都带有int的const将使指向常量int的指针 :
const int *ptr=&i;
要么:
int const *ptr=&i;
*
之后的const
将使常量指针指向int :
int *const ptr=&i;
在这种情况下,所有这些都是指向常量integer的指针 ,但是这些都不是常量指针:
const int *ptr1=&i, *ptr2=&j;
在这种情况下,所有都是指向常量整数的指针,而ptr2是指向常量整数的常量指针 。 但是ptr1不是常量指针:
int const *ptr1=&i, *const ptr2=&j;
#14楼
对我来说, const
的位置(即相对于*
出现在LEFT或RIGHT还是同时出现在LEFT和RIGHT上)有助于我弄清实际含义。
指向
*
的LEFT的const
表示指针所指向的对象是const
对象。*
的RIGHTconst
表示该指针是const
指针。
下表摘自Stanford CS106L标准C ++编程实验室课程阅读器。
#15楼
只是为了完整起见,请遵循其他说明,对于C ++并不确定。
- pp-指向指针的指针
- p-指针
- 数据-实例中指出的事物
x
- 粗体 -只读变量
指针
- p数据
int *p;
- p data -
int const *p;
- p数据
int * const p;
- p 数据
int const * const p;
指针指向
- pp p数据
int **pp;
- pp p数据
int ** const pp;
- pp p数据
int * const *pp;
- pp p 数据
int const **pp;
- pp p数据
int * const * const pp;
- pp p 数据
int const ** const pp;
- pp p 数据
int const * const *pp;
- 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);
#16楼
- 如果
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
这主要用于函数签名中,以确保函数不会意外更改传递的参数。
#17楼
关于C ++中的const正确性,还有许多其他的细微之处。 我想这里的问题只是关于C的,但是由于标签是C ++,我将给出一些相关的示例:
您通常将诸如字符串之类的大参数作为
TYPE const &
传递TYPE const &
这会阻止对象被修改或复制。 范例:TYPE& TYPE::operator=(const TYPE &rhs) { ... return *this; }
但是
TYPE & const
是没有意义的,因为引用始终是const。您应该始终将不会将类修改为
const
类方法标记为标签,否则您将无法从TYPE const &
reference中调用该方法。 范例:bool TYPE::operator==(const TYPE &rhs) const { ... }
在通常情况下,返回值和方法都应为const。 范例:
const TYPE TYPE::operator+(const TYPE &rhs) const { ... }
实际上,const方法一定不能将内部类数据作为对非const的引用返回。
结果,必须经常使用const重载来创建const和非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 int *,const int * const和int const *有什么区别?相关推荐
- const volatile同时限定一个类型int a = 10
const和volatile放在一起的意义在于: (1)本程序段中不能对a作修改,任何修改都是非法的,或者至少是粗心,编译器应该报错,防止这种粗心: (2)另一个程序段则完全有可能修改,因此编译器最好 ...
- const int是什么类型_C++的const语义
背景 我们都知道,const作为修饰符的时候,用来表明这个变量所代表的内存不可修改.因此,const修饰的变量必须在定义的时候就完成初始化,不然以后也没有机会了: const 但是请注意,这个不可修改 ...
- c语言const 修饰二级指针,C++中const修饰二级指针(从类型‘int**’到类型‘const int**’的转换无效)...
先上代码: void func(const int ** arg) { } int main(int argc, char **argv) { int **p; func(p); return 0; ...
- 错误 LNK2019 无法解析的外部符号 “__declspec(dllimport) public: int __thiscall osg::Referenced::ref(void)const “
前言 错误 LNK2019 无法解析的外部符号 "__declspec(dllimport) public: int __thiscall osg::Referenced::ref(void ...
- c语言 define和int,C语言中define与const的用法区别分析
其实这个是困惑了我好久的问题,没想到在上机课做到的题里找到了答案--我的困惑是:#define与const到底有什么区别. 题目: 代码如下 复制代码 #define N 2 #define M N ...
- c语言const限制什么,[C语言]类型限定词const解析
标签: 作为C90增加的一个受限类型关键字,const赋予了它修饰的变量一个新属性--不变性,如果一个变量声明中带有关键字const,则无法通过赋值.增减运算来修改该变量的值. 一.指针与const结 ...
- 类与对象:类的6个默认成员函数: 构造函数、析构函数、拷贝构造函数、赋值操作符重载、默认拷贝构造与赋值运算符重载的问题、const成员函数、 取地址及const取地址操作符重载
1.类的6个默认成员函数 如果一个类中什么成员都没有,简称为空类.任何一个类在我们不写的情况下,都会自动生成下面6个默认成员函数. 构造函数 析构函数 拷贝构造函数 赋值操作符重载 const成员函数 ...
- c语言const字符串,C语言之正确使用const
一.const用途 const是一个C语言的关键字,它限定一个变量不允许被改变. 1.const与基本类型 const char m;//限定m不可变. 2.const与指针 1).const在*前面 ...
- const对象只能调用const成员函数、不能调用非const成员函数;非const对象可以调用const成员函数
引发原因: 由调用成员函数时隐式传入的当前对象的this指针引起. 1. 非const成员函数中的隐式参数:classA* this 2. const成员函数中的隐式参数:const classA* ...
- getch()与_getch()、不能将const char*类型的值分配到const* 类型的实体
参考1:getch()与_getch() 添加预处理 项目 -> 属性 -> 配置属性 -> C/C++ -> 预处理器 -> 预处理器定义 -> 编辑中添加:_C ...
最新文章
- 深度学习前人精度很高了,该怎么创新?
- Vue之axios发送Ajax请求
- 笔记 | 那些不得不掌握的卷积神经网络CNN的架构
- Recurrent Neural Network[Quasi RNN]
- 直接插入排序,折半插入排序,希尔排序,简单选择排序,冒泡排序,快速排序模板以及比较次数与移动次数的分析,折半搜索算法模板
- 表妹好奇地问的飞鸽传书
- mysql 最短路经_poj 3613 Cow Relays 经L边的最短路 | 学步园
- phpcmsV9一、二级导航栏目loop循环输出、当前高亮显示
- 基于JAVA+SpringMVC+Mybatis+MYSQL的球鞋购物系统
- linux的三大服务器,Linux三大重要事件
- {工作记录}遇到过的网络攻击合集爬虫User-Agent记录..{持续更新}
- idea 导出项目到eclipse
- 深度学习之 梯度消失与爆炸原因公式推导
- 怎么自己建网站?自己建网站要注意以下4点
- 两轮电动车越来越拥挤了
- php识别word语言,PHP读取word文档
- 判断两个单词是否互为变位词
- 计算机基础知识(基础入门小白专属)三
- python-opencv基础
- Coremail2021邮件安全竞赛正式开幕!快来报名吧!
热门文章
- Android 抓取app进程 hprof 文件
- Promise入门详解和基本用法 我来教你
- 第十、十一周项目五 - 摩托车继承自行车和机动车
- Android10.0 日志系统分析(一)-logd、logcat 指令说明、分类和属性-[Android取经之路]
- ValueTransformer
- Swift URL含有中文的处理
- animated bar chart race下载_下载腾讯会议
- Selenium-switch_to_window出现删除线
- JavaWeb--MVC案例1-------(4)删除
- replace和replacAll