const int *,const int * const和int const *之间有什么区别?

时间:2009-07-17 13:28:09

标签: c++ c pointers int const

我总是弄清楚如何正确使用const int*const int * constint const *。是否有一套规则来定义您能做什么和不能做什么?

我想知道在任务,传递给职能等方面所做的所有事情和所有事情。

21 个答案:

答案 0 :(得分:1982)

向后阅读(由Clockwise/Spiral Rule驱动):

  • int* - 指向int
  • 的指针
  • int const * - 指向const int的指针
  • int * const - const指向int
  • 的指针
  • int const * const - const指向const int的指针

现在第一个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 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是指向可以更改的值的常量或固定指针。这就像没有额外语法糖的参考。由于这个事实,通常你会使用一个引用,你将使用T* const指针,除非你需要允许NULL指针。

答案 1 :(得分:293)

对于那些不了解顺时针/螺旋规则的人: 从变量名称开始,顺时针移动(在这种情况下,向后移动)到下一个指针类型。重复直到表达结束。

这是一个演示:

pointer to int

const pointer to int const

pointer to int const

pointer to const int

const pointer to int

答案 2 :(得分:134)

我认为这里已经解决了所有问题,但我只想补充一点,你应该提防typedef!它们不仅仅是文本替换。

例如:

typedef char *ASTRING;
const ASTRING astring;

astring的类型为char * const,而不是const char *。这是我总是倾向于将const放在类型右侧的原因之一,而不是从一开始。

答案 3 :(得分:48)

几乎所有人都指出:

What’s the difference between const X* p, X* const p and 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的常量指针”:您不能更改指针p本身,也不能通过p更改X对象。

  •   

答案 4 :(得分:42)

  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
    

答案 5 :(得分:17)

一般规则是const关键字立即适用于它之前的内容。例外,起始const适用于以下内容。

  • const int*int const*相同,表示“指向常量int的指针
  • const int* constint const* const相同,表示“指向常量int的常量指针

修改 对于Dos和Don'ts,如果this answer还不够,你能更准确地了解你的想法吗?

答案 6 :(得分:16)

这个问题显示正是为什么我喜欢按照我在问题中提到的方式做事is const after type id acceptable?

简而言之,我发现记住规则的最简单方法是“const”在之后应用于。所以在你的问题中,“int const *”意味着int是常量,而“int * const”意味着指针是常量。

如果有人决定把它放在最前面(例如:“const int *”),作为一种特殊的例外情况,它适用于它后面的东西。

许多人喜欢使用这个特殊的例外,因为他们认为它看起来更好。我不喜欢它,因为它是一个例外,因而混淆了事情。

答案 7 :(得分:14)

简单使用'const'

最简单的用法是声明一个命名常量。为此,我们声明一个常量,好像它是一个变量,但在它之前加上'const'。必须立即在构造函数中初始化它,因为当然,之后无法设置值,因为这会改变它。例如,

const int Constant1=96; 

将创建一个整数常量,无法想象地称为“Constant1”,值为96.

这些常量对于程序中使用的参数很有用,但在编译程序后不需要更改。对于程序员而言,它优于C预处理器'#define'命令,因为它被理解为&由编译器本身使用,而不是在到达主编译器之前由预处理器替换为程序文本,因此错误消息更有帮助。

它也适用于指针但是必须要小心“const”,以确定指针或指向的指针是否为常量或两者。例如,

const int * Constant2 

声明Constant2是指向常量整数和

的变量指针
int const * Constant2

是另一种语法,它可以做同样的事情,而

int * const Constant3

声明Constant3是指向变量integer和

的常量指针
int const * const Constant4

声明Constant4是指向常量整数的常量指针。基本上'const'适用于它的直接左边的任何东西(除非没有任何东西,在这种情况下它适用于它的直接权利)。

参考:http://duramecho.com/ComputerInformation/WhyHowCppConst.html

答案 8 :(得分:7)

在我遇到C ++大师Scott Meyers的book之前,我有同样的疑问。请参阅本书中的第三个项目,其中详细介绍了如何使用const

请遵循此建议

  1. 如果单词const出现在星号的左侧,那么指向的是
  2. 如果单词const出现在星号右侧,则指针本身是常量
  3. 如果双方都出现const,则两者都是常数

答案 9 :(得分:5)

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和非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 &引用也可能见证它在其他地方引用的值。

答案 10 :(得分:5)

这很简单但很棘手。请注意,我们可以将const限定符与任何数据类型(intcharfloat等进行交换。)

让我们看看下面的例子。


const int *p ==&gt; *p是只读的[p是指向常量整数的指针]

int const *p ==&gt; *p是只读的[p是指向常量整数的指针]


int *p const ==&gt; 错误声明。编译器抛出语法错误。

int *const p ==&gt; p是只读的[p是指向整数的常量指针]。 由于这里的指针p是只读的,因此声明和定义应该在同一个地方。


const int *p const ==&gt; 错误声明。编译器抛出语法错误。

const int const *p ==&gt; *p是只读的

const int *const p1 ==&gt; *pp是只读的[p是指向常量整数的常量指针]。由于这里的指针p是只读的,因此声明和定义应该在同一个地方。


int const *p const ==&gt; 错误声明。编译器抛出语法错误。

int const int *p ==&gt; 错误声明。编译器抛出语法错误。

int const const *p ==&gt; *p是只读的,相当于int const *p

int const *const p ==&gt; *pp是只读的[p是指向常量整数的常量指针]。由于这里的指针p是只读的,因此声明和定义应该在同一个地方。

答案 11 :(得分:5)

C和C ++声明语法一再被原始设计者描述为失败的实验。

相反,让命名类型为“Type的指针”;我称之为Ptr_

template< class Type >
using Ptr_ = Type*;

现在Ptr_<char>是指向char的指针。

Ptr_<const char>是指向const char的指针。

const Ptr_<const char>是指向const的{​​{1}}指针。

enter image description here

答案 12 :(得分:3)

对我来说,const的位置,即相对于*出现在左边还是右边,或者在左边和右边都可以帮助我弄清实际含义。

  1. const左边的*表示指针所指向的对象是const对象。

  2. const右边的*表示该指针是const指针。

下表摘自Stanford CS106L标准C ++编程实验室课程阅读器。

enter image description here

答案 13 :(得分:3)

  • 如果const位于*的左侧中,则表示值(const int或{{1}都无关紧要})
  • 如果int const位于const右侧 ,则表示指针本身
  • 可以同时使用

要点:* 并不意味着您所指的值是恒定的!。这意味着您不能通过该指针对其进行更改(这意味着您无法分配$ * p = ...`)。该值本身可以以其他方式更改。例如

const int *p

这主要用于函数签名中,以确保函数不会意外更改传递的参数。

答案 14 :(得分:2)

在两侧都带有int的const将使指向常量int

const int *ptr=&i;

int const *ptr=&i;
'*'之后的

const将使常量指针指向int

int *const ptr=&i;

在这种情况下,所有这些都是指向常量整数的指针,但是这些都不是常量指针。

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

在这种情况下,所有都是指向常量整数的指针,而ptr2是指向常量整数的常量指针。但是ptr1不是常量指针。

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

答案 15 :(得分:1)

这主要涉及第二行:最佳实践,作业,功能参数等。

一般做法。尝试尽可能地制作所有const。或者换一种方式,让所有内容const开始,然后删除确保程序运行所需的最小const集合。这对于获得正确性是一个很大的帮助,并且有助于确保当人们尝试分配他们不应该修改的东西时,不会引入微妙的错误。

避免使用const_cast&lt;&gt;像瘟疫一样。它有一两个合法用例,但它们很少,而且很少。如果您正在尝试更改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)这两个几乎与他们的参考对应词同义,但需要注意的是被叫函数现在需要检查nullptr,除非其他合同保证确保func它永远不会在nullptr中收到param

关于该主题的意见。在这种情况下证明正确性是非常困难的,它太容易犯错误了。所以不要冒险,并且总是检查nullptr的指针参数。从长远来看,你将拯救自己的痛苦和痛苦,很难找到虫子。至于检查的成本,它很便宜,而且在编译器内置的静态分析可以管理它的情况下,优化器无论如何都会忽略它。打开MSVC的链接时间代码生成,或GCC的WOPR(我认为),你可以在程序范围内获得它,即使在跨越源代码模块边界的函数调用中也是如此。

在一天结束时,上述所有内容都非常可靠,总是更喜欢对指针的引用。他们全面安全。

答案 16 :(得分:1)

仅出于完整性考虑,请遵循其他说明,不能确定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 个数据-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);

答案 17 :(得分:1)

简单的助记符:

type 指针 <- * -> 指针 name


我喜欢将 int *i 视为声明“i 的取消引用是 int”;在这个意义上,const int *i 表示“i 的解引用为 const int”,而 int *const i 表示“const i 的解引用为 int”。

(这样思考的一个危险是它可能导致偏爱int const *i 风格的声明,人们可能会讨厌/不允许)

答案 18 :(得分:1)

以简单的方式记住:

如果 const 在 * 之前,则值为常量。

如果 const 在 * 之后,则地址是常量。

如果 const 在 * 之前和之后都可用,则 value 和 address 都是常量。

例如

  1. int * const var; //这里地址是常量。

  2. int const * var; //这里的值是常量。

  3. int const * const var; // 值和地址都是常量。

答案 19 :(得分:0)

  1. const int*-指向常量int对象的指针。

您可以更改指针的值;您不能更改指针指向的int对象的值。


  1. const int * const-指向常量int对象的常量指针。

您不能更改指针的值或指针指向的int对象的值。


  1. int const *-指向常量int对象的指针。

此语句等效于1。const int*-您可以更改指针的值,但不能更改指针指向的int对象的值。


实际上,有第四个选择:

  1. int * const-指向int对象的常量指针。

您可以更改指针指向的对象的值,但是不能更改指针本身的值。指针将始终指向相同的int对象,但是可以更改此int对象的值。


如果要确定某种类型的C或C ++构造,可以使用David Anderson制作的Clockwise/Spiral Rule。但不要与Ross J. Anderson的Anderson`s Rule混淆,这是很不一样的。

答案 20 :(得分:-1)

很多人回答正确,我会在这里组织好并添加一些在给定答案中缺少的额外信息。

<块引用>

Const 是 C 语言中的关键字,也称为限定符。常量可以 应用于任何变量的声明以指定它的值 不会改变

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 

两种

1. const int *

2. const const int *

我们先看

主要类型 1. const int*

<块引用>

在 3 个地方安排 3 件事的方法 3!=6

我。 * 开始时

*const int p      [Error]
*int const p      [Error]

ii. const 开始时

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.const const int*

<块引用>

在 4 个地方排列 4 个东西的方法,其中 2 个相似 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 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]

合二为一

输入一个。 p 是 ptr 到 const int (5)

const int *p
int const *p

int const const *p
const const int  *p
const int  const *p

输入 b。 p 是 const ptr 到 int (2)

int * const p
int * const const p;

输入 c。 p 是 const ptr 到 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. 

完成