const char * 与 const char ** 函数参数

const char * vs. const char ** function argument

我已经阅读了 C FAQ on const,但我仍然感到困惑。

我的印象是(显然是错误的)函数声明中的 const 本质上是一个承诺,即该函数不会修改您标记为 const 的内容。因此传入一个 const 或非 const 参数是可以的。但是这个:

#include <stdio.h>

extern void f1 ( const char * cc );
extern void f2 ( const char ** ccc );

int main ( void ) {
    char            c1[]    = "hello";
    const char *    c2      = "hello";
    char *          c3      = NULL;
    char **         v1      = NULL;
    const char **   v2      = NULL;

    f1( c1 );               /* ok */
    f1( c2 );               /* ok */
    f1( c3 );               /* ok */
    f1( "hello, world" );   /* ok */
    f2( v1 );               /* compiler warning - why? */
    f2( v2 );               /* ok */
    return 0;
}

特此警告:

$ cc -c -o sample.o sample.c sample.c: In function 'main': sample.c:17:
warning: passing argument 1 of 'f2' from incompatible pointer type
sample.c:4: note: expected 'const char **' but argument is of type 'char **'
f2( v1 );               /* compiler warning - why? */

compiler warning - why?

因为char**const char**不一样。他们的待遇不同。

char** v1 // pointer to pointer to char 

在这里您可以更改 **v1 的值。

const char** v2  //pointer to pointer to constant char 

在这里您不能更改 **v2 的值,如果您尝试编译器会发出错误。

标准禁止这样做,因为那样会违反对象的常量性。考虑:

const char ch = 'X';
char* ch_ptr;
const char** ch_pptr = &ch_ptr; // This is not allowed, because...

*ch_pptr = &ch;
*ch_ptr = 'Q'; // ...this will modify ch, which should be immutable!

这一行之后:

const char** ch_pptr = &ch_ptr;

*ch_pptrch_ptr 产生相同的值(地址),但它们的类型不同(const char*char*)。然后,您使用 ch_pptr 指向 const 对象,这会自动导致 ch_ptr 指向相同的内存位置。通过这样做,您允许对最初声明为常量的对象进行任何修改(使用 ch_ptr)。

这个错误非常微妙,但过一段时间后,您应该能够理解为什么它会很危险。这就是不允许这样做的原因。


Yes, but why is not putting the const in the function declaration the "promise" that the function does not do that sort of evil?

因为它以相反的方式工作——功能,完全合法的事情可能会引入无效行为。看这段代码:

static const char* sample_string = "String";

void f2 (const char ** ccc)
{
    *ccc = sample_string; //Perfectly valid - function does not do any "evil" things
}

int main ( void )
{
    char** v1 = NULL;

    f2(v1); // After this call, *v1 will point to sample_string

    (*v1)[0] = 'Q'; // Access violation error

    return 0;
}