首页 文章

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

提问于
浏览
1077

我总是搞砸如何正确使用 const int*const int * constint const * . 是否有一套规则定义了您能做什么和不能做什么?

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

14 回答

  • 16
    • Constant reference:

    对变量(此处为int)的引用,它是常量 . 我们主要将变量作为引用传递,因为引用的大小小于实际值,但是存在副作用,这是因为它就像实际变量的别名 . 我们可能会通过完全访问别名来意外更改主变量,因此我们将其设置为常量以防止此副作用 .

    int var0 = 0;
    const int &ptr1 = var0;
    ptr1 = 8; // Error
    var0 = 6; // OK
    
    • Constant pointers

    一旦常量指针指向变量,它就不能指向任何其他变量 .

    int var1 = 1;
    int var2 = 0;
    
    int *const ptr2 = &var1;
    ptr2 = &var2; // Error
    
    • Pointer to constant

    一个指针,通过它可以不改变它指向的变量的值,称为指向常量的指针 .

    int const * ptr3 = &var2;
    *ptr3 = 4; // Error
    
    • Constant pointer to a constant

    指向常量的常量指针是一个指针,既不能改变它指向的地址,也不能改变保存在该地址的值 .

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

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

    这是一个演示:

    pointer to int

    const pointer to int const

    pointer to int const

    pointer to const int

    const pointer to int

  • 12

    任何一方都带有int的const将生成 pointer to constant int .

    const int *ptr=&i;
    

    要么

    int const *ptr=&i;
    

    ' * '之后的const将使 constant pointer to int .

    int *const ptr=&i;
    

    在这种情况下,所有这些都是 pointer to constant integer ,但这些都不是常量指针 .

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

    在这种情况下,所有都是 pointer to constant integer ,ptr2是 constant pointer to constant integer . 但是ptr1不是常量指针 .

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

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

    • int* - 指向int的指针

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

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

    • 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 指针 .

  • 261

    我和你有同样的疑问,直到我被C大师斯科特迈耶斯看到这个book . 请参阅本书中的第三个项目,其中详细介绍了如何使用 const .

    请遵循这个建议

    • 如果单词 const 出现在星号的左侧,则指向的是常量

    • 如果单词 const 出现在星号的右侧,则指针本身是常量

    • 如果双方都出现 const ,则两者都是不变的

  • 5

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

    我们来看下面的例子 .


    const int *p ==> *p 是只读的[ p 是一个指向常量整数的指针]

    int const *p ==> *p 是只读的[ p 是一个指向常量整数的指针]


    int *p const ==> Wrong 声明 . 编译器抛出语法错误 .

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


    const int *p const ==> Wrong 声明 . 编译器抛出语法错误 .

    const int const *p ==> *p 是只读的

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


    int const *p const ==> Wrong 声明 . 编译器抛出语法错误 .

    int const int *p ==> Wrong 声明 . 编译器抛出语法错误 .

    int const const *p ==> *p 是只读的,相当于 int const *p

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

  • 1

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

    • const int*int const* 相同,表示 "pointer to constant int" .

    • const int* constint const* const 相同,表示 "constant pointer to constant int" .

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

  • 47

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

    相反,我们将类型命名为“指向 Type 的指针”;我叫它 Ptr_

    template< class Type >
    using Ptr_ = Type*;
    

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

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

    const Ptr_<const char> 是指向 const charconst 指针 .

    那里 .

  • 5

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

    例如:

    typedef char *ASTRING;
    const ASTRING astring;
    

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

  • 40

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

    简而言之,我发现记住规则的最简单方法是"const"追求它应用的东西 . 所以在你的问题中,"int const *"意味着int是常量,而"int * const"意味着指针是常量 .

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

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

  • 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 & 参考也可能见证它在其他地方被改变的 Value .

  • 1855

    几乎所有人都指出:

    What’s the difference between const X* p, X* const p and const X* const p?

    你必须从右到左阅读指针声明 . const X * p表示“p指向一个X为const”:X对象不能通过p改变 . X * const p表示“p是指向非const的X的const指针”:您不能更改指针p本身,但可以通过p更改X对象 . const X * const p表示“p是一个指向X的const指针”:你不能改变指针p本身,也不能通过p改变X对象 .

  • 128

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

    一般做法 . 尝试尽你所能 const . 或者换句话说,首先让所有内容 const 开始,然后准确删除允许程序运行所需的最小 const 集 . 这对于获得const正确性将是一个很大的帮助,并将有助于确保不应该修改微妙的错误 .

    避免像瘟疫那样的const_cast <> . 它有一两个合法的用例,但它们很少,而且很少 . 如果你想要改变一个 const 对象,那么你可以更好地找到第一步宣称它的人,并与他们讨论这个问题,以便就应该发生什么达成共识 .

    这非常巧妙地导致了作业 . 只有在非const的情况下才可以分配 . 如果要分配到const的内容,请参阅上文 . 请记住,在声明 int const *foo;int * const bar; 不同的事情是 const - 这里的其他答案令人钦佩地涵盖了这个问题,所以我不会进入它 .

    功能参数:

    通过 Value :例如 void func(int param) 你在调用网站上并不关心这种或那种方式 . 可以认为有一些用例将函数声明为 void func(int const param) ,但这对调用者没有影响,仅在函数本身上,因为在调用期间函数无法更改传递的任何值 .

    通过引用传递:例如 void func(int &param) 现在确实有所作为 . 刚刚宣布 func 被允许更改 param ,任何调用站点都应该准备好应对后果 . 将声明更改为 void func(int const &param) 会更改 Contract ,并保证 func 现在无法更改 param ,这意味着传入的内容将会返回 . 正如其他人所说,这对于廉价传递一个你不想改变的大型物体非常有用 . 传递引用比按值传递大对象要便宜得多 .

    通过指针:例如 void func(int *param)void func(int const *param) 这两个几乎是他们的参考对应物的同义词,但需要注意的是,被叫函数现在需要检查 nullptr ,除非其他 Contract 保证确保 funcparam 中永远不会收到 nullptr .

    关于该主题的意见 . 在这样的情况下证明正确性是非常困难的,它有机会,并且总是检查 nullptr 的指针参数 . 从长远来看,你将拯救自己的痛苦和苦难 . 至于检查的成本,它会使程序范围广泛,即使在跨越源代码模块边界的函数调用中也是如此 .

    在一天结束时,以上所有内容都是一个非常可靠的案例,总是更喜欢对指针的引用 . 它们全面安全 .

  • 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

相关问题