【问题标题】:Modifying a char *const string修改 char *const 字符串
【发布时间】:2013-10-22 18:27:43
【问题描述】:

我知道const char * 是一个指向常量字符的指针,而char *const 是一个指向字符的常量指针。 我正在以下代码中对此进行测试:

const char *s = "hello";    // Not permitted to modify the string "hello"
char *const t = "world";    // Not permitted to modify the pointer t

s = "hello2";   // Valid
// t = "world2";   // Invalid, gives compilation error

// *(s + 1) = 'a';    // Invalid, gives compilation error
*(t + 1) = 'a';       // Why does this not work?    

最后一行没有给出任何错误,但会导致程序意外终止。为什么不允许修改t指向的字符串?

【问题讨论】:

    标签: c++ c string pointers runtime-error


    【解决方案1】:

    t 指向一个字符串文字,修改字符串文字是未定义的行为。 C++ 草案标准部分 2.14.5 字符串文字12 段说(强调我的):

    是否所有字符串文字都是不同的(即存储在不重叠的对象中)是由实现定义的。 尝试修改字符串文字的效果未定义

    C99 标准草案的相关部分是 6.4.5 字符串文字 段落 6 说(强调我的):

    如果这些数组的元素具有 适当的值。 如果程序试图修改这样的数组,行为是 未定义。

    在典型的现代 Unix 平台上,您会在只读段中找到 字符串文字,如果我们尝试修改它会导致访问冲突。我们可以使用 objdump 来检查只读部分,如下所示:

    objdump -s -j .rodata
    

    我们可以在下面的live example 中看到字符串文字确实会在 只读 部分中找到。请注意,我必须添加 printf 否则编译器会优化字符串文字。示例 `objdump 输出:

    Contents of section .rodata:
     400668 01000200 776f726c 64002573 0a00      ....world.%s..
    

    另一种方法是让t 指向一个带有字符串文字副本的数组,如下所示:

    char r[] = "world";    
    char *const t = r ;
    

    【讨论】:

    • 您陈述了标准,但实际上并没有说明程序为何(如何)以错误终止...只是说... Elchonon Edelson 给出了实际原因,我认为这是正确的回答。
    • @AlexisWilke 该标准旨在独立于平台,并且此类细节取决于平台,这就是为什么该标准使用诸如未定义行为之类的语言来涵盖整个范围的行为,包括工作正常但它可以不可依赖。我为典型的现代 unix 平台添加了更多细节。
    【解决方案2】:

    虽然 C 中的字符串字面量正式具有 char[] 类型(char 的数组,而不是 const),但 C 标准明确规定它们必须被视为不可修改。编译器倾向于将字符串文字放在只读段中,因此尝试修改它们会导致访问冲突。

    C11 标准 (ISO/IEC 9899:2011) 的 6.4.5 部分描述了字符串文字。

    【讨论】:

      【解决方案3】:

      您可以通过将其重铸为char* 来绕过编译器错误,就像在*((char*)s + 1) = 'a'; 中一样,但由于它已经存在于其他答案中,因此这是未定义的行为,并且可能会导致分段错误,因为您正在编辑字符串文字.

      【讨论】:

        【解决方案4】:

        如果您想正确测试它,请在函数中初始化字符串,以便初始化可以是动态的,并为此使用strdup()

        int
        main(int argc, char **argv)
        {
            char *d1 = strdup("hello");
            char *d2 = strdup("world");
        
            const char *s = d1;
            char *const t = d2;
        
            ...
        
            free(d1);
            free(d2);
        }
        

        主要使用 d1 和 d2 变量,以便可以在最后使用 free() 正确释放动态分配。此外,正如其他答案所建议的那样,始终将字符串文字视为const char *

        【讨论】:

          猜你喜欢
          • 2022-08-12
          • 1970-01-01
          • 2010-09-21
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-07-12
          相关资源
          最近更新 更多