const char * const与const char *?

时间:2011-02-09 19:02:20

标签: c++ c

我正在运行一些示例程序来重新熟悉C ++,我遇到了以下问题。首先,这是示例代码:

void print_string(const char * the_string)
{
    cout << the_string << endl;
}

int main () {
    print_string("What's up?");
}

在上面的代码中,print_string的参数可能改为const char * const the_string。哪个更合适呢?

我理解不同之处在于,一个是指向常量字符的指针,而另一个是指向常量字符的常量指针。但为什么这两个都有效呢?它何时相关?

12 个答案:

答案 0 :(得分:224)

后者阻止您修改the_string内的print_string。它实际上在这里是合适的,但也许冗长会使开发人员失望。

char* the_string :我可以将char更改为the_string点,我可以修改它所指向的char。< / p>

const char* the_string :我可以将char更改为the_string点,但我无法修改它所指向的char。< / p>

char* const the_string :我无法更改char指向的the_string,但我可以修改它指向的char。< / p>

const char* const the_string :我无法更改char指向的the_string,也无法修改指向的char。< / p>

答案 1 :(得分:129)

  1. 指向可变字符的可变指针

    char *p;
    
  2. 指向常量字符的可变指针

    const char *p;
    
  3. 指向可变字符的常量指针

    char * const p; 
    
  4. 指向常量字符的常量指针

    const char * const p;
    

答案 2 :(得分:26)

const char * const表示指针以及指针指向的数据,都是 const!

const char *表示指针指向的数据是const。然而,指针本身不是常量。

实施例

const char *p = "Nawaz";
p[2] = 'S'; //error, changing the const data!
p="Sarfaraz"; //okay, changing the non-const pointer. 

const char * const p = "Nawaz";
p[2] = 'S'; //error, changing the const data!
p="Sarfaraz"; //error, changing the const pointer. 

答案 3 :(得分:17)

(我知道这已经过时但我想分享。)

只是想详细说明Thomas Matthews&#39;回答。 C类型声明的左右规则几乎说:当读取C类型声明时,从标识符开始,然后在可以的时候向右移动,在可以的时候离开。

最好用几个例子来解释:

示例1

  • 从标识符开始,我们无法向右移动

    const char* const foo
                ^^^^^
    

    foo是常量 ......

  • 继续左转

    const char* const foo
              ^
    

    foo是指向的常量指针...

  • 继续左转

    const char* const foo
          ^^^^
    

    foo是指向 char 的常量指针...

  • 继续左转

    const char* const foo
    ^^^^^
    

    foo是一个常量指针,指向char 常量(完成!)

示例2

  • 从标识符开始,我们无法向右移动

    char* const foo
          ^^^^^
    

    foo是常量 ......

  • 继续左转

    char* const foo
        ^
    

    foo是指向的常量指针...

  • 继续左转

    char* const foo
    ^^^^
    

    foo是指向 char 的常量指针(完成!)

实施例1337

  • 从标识符开始,但现在我们可以走了!

    const char* const* (*foo[8])()
                            ^^^
    

    foo是 8的数组 ...

  • 点击括号,这样就不能再向左走,

    const char* const* (*foo[8])()
                        ^
    

    foo是一个8 指针的数组 ...

  • 在括号内完成,现在可以正确

    const char* const* (*foo[8])()
                                ^^
    

    foo是一个指向函数的8指针数组,返回 ...

  • 没有更多的东西,向左走

    const char* const* (*foo[8])()
                     ^
    

    foo是一个8指向函数的数组,它返回指向的指针......

  • 继续左转

    const char* const* (*foo[8])()
                ^^^^^
    

    foo是一个8指向函数的数组,它返回一个指向常量的指针 ......

  • 继续左转

    const char* const* (*foo[8])()
              ^
    

    foo是一个8指向函数的数组,它返回一个指向指针的常量的指针...

  • 继续左转

    const char* const* (*foo[8])()
          ^^^^
    

    foo是一个8指向函数的数组,它返回一个指向 char 的常量指针的指针......

  • 继续左转

    const char* const* (*foo[8])()
    ^^^^^
    

    foo是一个8指向函数的数组,它返回一个指向char 常量的常量指针的指针(完成!)

进一步说明:http://www.unixwiz.net/techtips/reading-cdecl.html

答案 4 :(得分:12)

许多人建议从右到左阅读类型说明符。

const char * // Pointer to a `char` that is constant, it can't be changed.
const char * const // A const pointer to const data.

在两种形式中,指针指向常量或只读数据。

在第二种形式中,指针不能改变;指针总是指向同一个地方。

答案 5 :(得分:3)

不同之处在于,如果没有额外的const,程序员可以在方法内部改变指针所指向的位置;例如:

 void print_string(const char * the_string)
 {
    cout << the_string << endl;
    //....
    the_string = another_string();
    //....

 }

如果签名为void print_string(const char * const the_string)

,那将是非法的

许多程序员在额外的const关键字中感觉过于冗长(在大多数情况下)并省略它,即使它在语义上是正确的。

答案 6 :(得分:2)

在后者中,您保证不会在第一个中修改指针和字符,只保证内容不会改变,但您可以移动指针

答案 7 :(得分:2)

没有理由说任何一个人都行不通。所有print_string()都会打印该值。它不会尝试修改它。

最好不要将标记参数修改为const的函数。优点是无法更改(或者您不想更改)的变量可以毫无错误地传递给这些函数。

就确切的语法而言,您希望指出哪种类型的参数是“安全的”传递给函数。

答案 8 :(得分:2)

我认为它的变化很少相关,因为你的函数不会被调用像&amp; * the_string或** the_string这样的参数。指针本身是一个值类型参数,因此即使您修改它,也不会更改用于调用函数的副本。您显示的版本确保字符串不会更改,我认为在这种情况下就足够了。

答案 9 :(得分:2)

const char *表示您无法使用指针来更改指向的内容。但是,您可以将指针更改为指向其他内容。

考虑:

const char * promptTextWithDefault(const char * text)
{
    if ((text == NULL) || (*text == '\0'))
        text = "C>";
    return text;
}

该参数是一个指向const char的非const指针,因此它可以更改为另一个const char *值(如常量字符串)。但是,如果我们错误地写了*text = '\0',那么我们就会收到编译错误。

可以说,如果您不打算更改参数指向的内容,您可以创建参数const char * const text,但这样做并不常见。我们通常允许函数更改传递给参数的值(因为我们按值传递参数,任何更改都不会影响调用者)。

顺便说一句:优良作法是避免使用char const *,因为它经常被误读 - 这意味着与const char *相同,但有太多人将其视为含义char * const

答案 10 :(得分:1)

几乎所有其他答案都是正确的,但是他们错过了这方面的一个方面:当你在函数声明中对参数使用额外的const时,编译器基本上会忽略它。暂时,让我们忽略您的示例作为指针的复杂性,并使用int

void foo(const int x);

声明与

相同的功能
void foo(int x);

仅在函数的定义中,额外const有意义:

void foo(const int x) {
    // do something with x here, but you cannot change it
}

此定义与上述任一声明兼容。来电者并不关心xconst - 这是与呼叫网站无关的实施细节。

如果您有const指向const数据的指针,则适用相同的规则:

// these declarations are equivalent
void print_string(const char * const the_string);
void print_string(const char * the_string);

// In this definition, you cannot change the value of the pointer within the
// body of the function.  It's essentially a const local variable.
void print_string(const char * const the_string) {
    cout << the_string << endl;
    the_string = nullptr;  // COMPILER ERROR HERE
}

// In this definition, you can change the value of the pointer (but you 
// still can't change the data it's pointed to).  And even if you change
// the_string, that has no effect outside this function.
void print_string(const char * the_string) {
    cout << the_string << endl;
    the_string = nullptr;  // OK, but not observable outside this func
}

很少有C ++程序员费心去做参数const,即使它们可能也是如此,无论这些参数是否都是指针。

答案 11 :(得分:-1)

两者之间的区别在于char *可以指向任意指针。相反,Const char *指向可执行文件的DATA部分中定义的常量。因此,您无法修改const char * string的字符值。