代码之家  ›  专栏  ›  技术社区  ›  Andrew-Dufresne

为什么我可以更改const char*ptr的内容?

  •  9
  • Andrew-Dufresne  · 技术社区  · 16 年前

    我传递了一个指针 ptr 一个函数的原型把它当作 const .

    foo( const char  *str );
    

    据我所知,这意味着它将无法改变 ptr公司 通过。比如说 foo( const int i ) foo() 试图改变 i
    但在这里我看到它可以改变 ptr公司
    请看下面的代码

    foo( const char  *str )
    {
            strcpy( str, "ABC" ) ;
            printf( "%s(): %s\n" , __func__ , str ) ;
    }
    
    main()
    {
            char ptr[  ] = "Its just to fill the space" ;
            printf( "%s(): %s\n" , __func__ , ptr ) ;
            foo( const ptr ) ;
            printf( "%s(): %s\n" , __func__ , ptr ) ;
            return;
    }
    

    在编译时,我只得到一个警告,没有错误:

    warning: passing argument 1 of ‘strcpy’ discards qualifiers from pointer target type

    当我运行它时,我得到的是一个输出,而不是 Segmentation Fault

    main():它只是用来填充空间
    foo():ABC


    1- const char *str
    这是否意味着函数不能更改 str ? 如果是这样的话,那么上面的程序怎么会改变这个值呢?
    如何确保我传递的指针的内容不会更改?

    从上述问题中的“指针内容”来看,我指的是“指针指向的内存内容”,而不是“指针包含的地址”。

    strcpy C隐式类型转换。但现在我试过了

    foo( const char  *str )
    {
            str = "Tim" ;
    //      strcpy( str, "ABC" ) ;
            printf( "%s(): %s\n" , __func__ , str ) ;
    }
    

    这一次输出是,编译器没有警告

    main():它只是用来填充空间

    main():它只是用来填充空间

    str公司 更改为包含 "Tim" foo() strcpy()
    常数 你要阻止这一切吗?还是我的理解错了?

    在我看来,即使 常数

    你能给我一个例子,编译器会给我一个错误,我试图改变常量指针?

    5 回复  |  直到 16 年前
        1
  •  17
  •   Alex B    16 年前

    你的理解是正确的, const char* 是一个契约,意味着不能通过这个特定指针更改内存。

    问题是C是 strcpy 将指针指向 非常量 含蓄地 转换自 常量字符* char* (正如编译器告诉您的那样)。您可以轻松地传递整数而不是指针。因此,函数不能更改 ptr 拷贝字符串 可以,因为它看到一个非常量指针。不会发生崩溃,因为在本例中,指针指向的是足够大小的实际缓冲区,而不是只读字符串文本。

    -Wall -Werror (如果您使用的是gcc)。

    这种行为是C。例如,C++不允许这样做,需要显式强制转换(C样式的CAST或 const_cast )剥去 const

    将字符串文字赋给非常量字符, 不幸地 字符* ,即使通过此指针写入将导致未定义的行为。这是一个贬低的特点,只有C++ 0x到目前为止不允许这种情况发生。

    话虽如此,为了停止改变指针 它本身 ,必须将其声明为指向char的const指针( char *const ). 或者,如果您想使它所指向的内容和指针本身都不改变,请使用指向constchar的const指针( const char * const ).

    void foo (
            char *a,
            const char *b,
            char *const c,
            const char *const d)
        {
        char buf[10];
        a = buf; /* OK, changing the pointer */
        *a = 'a'; /* OK, changing contents pointed by pointer */
    
        b = buf; /* OK, changing the pointer */
        *b = 'b'; /* error, changing contents pointed by pointer */
    
        c = buf; /* error, changing pointer */
        *c = 'c'; /* OK, changing contents pointed by pointer */
    
        d = buf; /* error, changing pointer */
        *d = 'd'; /* error, changing contents pointed by pointer */
    }
    

    对于所有错误行,GCC都给出“error:assignment of read-only location”。

        2
  •  3
  •   atis    16 年前

    “const”实际上是编译时的东西,所以除非指针指向某个无效内存,否则不要期望出现segfault。当使用const指针的方式可能会改变它们指向的任何对象时(在本例中,将其传递给接受非const的strcpy),将生成一个警告。

        3
  •  1
  •   Prasoon Saurav    16 年前

    1-原型中的const char*str实际上是什么意思? 这是否意味着函数不能更改str的内容?

    对!这意味着我们不能改变 某物 char 或者一个 array of chars

    如果是这样的话,那么上面的程序怎么会改变这个值呢?

    那是因为 strcpy() 的原型是 char * strcpy ( char * destination, const char * source );

    const char* 到 char* 键入原因 strcpy() 字符*

    从技术上讲,你的代码是不正确的,相当危险。如果你在C++中尝试相同的代码,你肯定会得到一个错误。C++不允许这种隐式转换,但是C确实如此。

        4
  •  1
  •   Thorsten Dittmar    16 年前

    IIRC公司 const 表示参数的值不能更改。在你的例子中,这个值是指针指向的地址。 strcpy

    使用 这里确保内存引用(地址)没有改变。但是,引用的内存可能会更改。这就是这里发生的事情。将新地址分配给指针将导致错误。

    旁注
    foo str 以及执行长度检查,否则将打开缓冲区溢出。

    编辑
    我把下面的从 this site :

    这个 const char *Str 告诉编译器 是常量。这意味着, Str 可以是 在Func中更改,但是 *Str 作为指针的副本传递给 Func,对 Str公司 不是 由主。。。。

        5
  •  1
  •   Jens Gustedt    16 年前

    const char* 与相同 char const* 而不是 char* const . 所以这意味着一个指向你不能改变的东西的指针。

    在编辑的版本中,您要做的是更改指针。这是合法的。如果你两个都不写,你就得写 char const* const .