【问题标题】:Reassigning string literals重新分配字符串文字
【发布时间】:2015-07-29 17:43:45
【问题描述】:

这是一个非常基本的问题,但我没有找到明确的答案。我试图了解C 中的字符串文字是如何工作的。

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void)
{
        char *str = "Hello World!";
        str = "Reassign str.";

        char *str2 = "Something.";

        str = strdup(str2);

        free(str);

        exit(EXIT_SUCCESS);
}

当我对字符串文字执行str = "Reassign str."str = strdup(str2) 时,Hello World 字符串会发生什么情况?它是否是可执行文件的一部分,是否超出范围,是否在我重新分配 str 后释放了内存?

【问题讨论】:

    标签: c string pointers


    【解决方案1】:

    字符串字面量具有静态存储持续时间。它们在程序执行过程中不会被破坏并且具有相同的地址。

    在这些陈述中

        str = "Reassign str.";
        //...
        str = strdup(str2);
    

    指针str 刚刚被其他一些地址重新分配。在第一个语句中,它获取字符串文字“Reassign str”的第一个字符的地址。在第二条语句中,它获取为字符数组动态分配内存的地址,该数组包含 str2 指向的字符串文本的副本。

    根据 C 标准(6.4.5 字符串文字)

    6 在翻译阶段 7 中,将一个字节或零值代码附加到 由字符串文字产生的每个多字节字符序列 或文字。78) 然后使用多字节字符序列 初始化一组静态存储持续时间和长度 足以包含序列。对于字符串文字, 数组元素具有 char 类型,并使用单个初始化 多字节字符序列的字节数。

    和(6.2.4 对象的存储时长)

    3 对象...具有静态存储持续时间。 它的寿命是 程序的整个执行过程及其存储的值被初始化 只有一次,在程序启动之前

    至于字符串文字本身,您可能不会更改它们。任何更改字符串文字的尝试都会导致程序的未定义行为。

    来自 C 标准(6.4.5 字符串文字)

    7 不确定这些数组是否不同,前提是它们的 元素具有适当的值。 如果程序试图 修改这样的数组,行为未定义。

    比如你可以不写

        char *str = "Hello World!";
        *str = 'h';
    

    【讨论】:

    • 可以按照我的方式重新分配字符串文字吗?
    • @brauner 您没有重新分配字符串文字。您正在重新分配以前指向字符串文字的第一个字符的指针。
    • 您没有重新分配字符串文字。文字是"" 标记内的位。您重新分配了str,它是一个指针。它最初将 指向 字面量,然后您将其指向一些动态分配的内存。
    • @brauner 字符串文字在程序执行期间具有相同的存储时间。
    • 感谢您的澄清。我的不精确!
    【解决方案2】:

    您的代码一切正常。

        char *str = "Hello World!"; 
    

    好的,你声明一个指向字符串litteral 的char *。正确地说,你应该写const char *str =,因为字符串litteral 是不可修改的字符串(str[4] = 'u'; 不正确)

        str = "Reassign str.";
    

    好的,指针 str 现在指向另一个字符串字面量。同上,应该还是const。

        char *str2 = "Something.";
    

    还是一样

        str = strdup(str2);
    

    现在 str 指向一个 malloc 的字符串。 str 不是 const 第一次是正确的。 str[0] = 's'; 在这里是正确的。

        free(str);
    

    好的,你释放strdup分配的字符串。

        exit(EXIT_SUCCESS);
    

    您很好地将定义的值 (0) 返回给环境。

    【讨论】:

    • 从技术上讲,字符串文字没有const 类型。不过你不应该写信给它。
    【解决方案3】:

    当你这样做时

    char *str = "Hello World!";  
    

    编译器为该字符串文字留出字节 strlen(str) + 1 的内存。当指针 str 被重新分配时,分配给字符串字面量 "Hello World!" 的内存不会被销毁/释放,而是保留在其范围内。

    【讨论】:

      【解决方案4】:

      好像已经没有足够的答案了,但我觉得有一个方面还是值得一提的:

      是的,您的代码中的字符串文字具有静态存储是正确的,因此在整个程序执行期间它将活着。从这个角度来说,它永远不会发生(你甚至不能改变它)。从技术上讲,这通常意味着字符串是您程序的 part 并放入只读的 data 段中。

      但是,在您的情况下,优化编译器会检测到 "Hello World!" 从未实际使用过,因此它将从您编译的程序中消失。这对优化器来说是合法的,因为它不会改变程序的可观察行为

      > gcc -ostrlit strlit.c
      > strings strlit | grep Hello
      Hello World!
      > gcc -O3 -ostrlit strlit.c
      > strings strlit | grep Hello
      >
      

      【讨论】:

        【解决方案5】:

        通常静态字符串位于静态数据部分中。在这种情况下,因为您的程序没有做任何事情,所以我不太确定;您所有的静态字符串都可能被优化掉。

        在实际使用这些静态字符串的实际程序中,它们将具有固定地址。

        str = strdup(str2); 绝不会释放任何内存。在 C 中,内存永远不会自行释放。

        【讨论】:

        • 哦,对不起,我把strdup() 弄错了,没有free()
        • 您现在添加的free() 只是简单地释放了strdup() 分配的内存;之前分配的静态字符串没有任何反应。
        • 是的,我知道我只是认为那里没有free() 是不好的形式。
        • 啊,我明白了。不用担心。
        【解决方案6】:

        让我们分解一下:

        char *str = "Hello World!";
        

        声明一个名为str指向char的指针

        char *str
        

        并且声明了一个字符串字面量

                    "Hello World!";
        

        并且设置str指向文字的第一个字符。

        文字具有静态存储持续时间 - 它被编译到您的可执行文件中,始终存在,并且无法移动或更改。

        指针只是一个指针,你可以随时把它指向其他东西。

        【讨论】:

          【解决方案7】:

          当声明这样的字符串字面量时:

          char *str = "Hello World!";
          

          "Hello World!" 字符串存储在内存的只读部分中。因此,如果您是其中之一:

          str[1] = 'i';
          strcpy(str, "Goodbye!");
          

          您很可能会进行核心转储。另一方面,如果您这样做:

          str = malloc(10);
          strcpy(str, "Goodbye!");
          

          你会没事的,尽管你会失去指向原始字符串的指针。

          【讨论】:

            猜你喜欢
            • 2012-11-10
            • 1970-01-01
            • 2017-08-03
            • 2012-01-11
            • 2013-03-26
            • 2016-07-31
            • 1970-01-01
            相关资源
            最近更新 更多