3

代码:

    #include <stdio.h>
    int main() {
        char *str;
        char i = 'a';
        str = &i;
        str = "Hello";
        printf("%s, %c, %x, %x", str, i, str, &i);
        return 0;
    }

我得到这个输出:

Hello, a, 403064, 28ff0b

我有以下两个疑问:

  1. 如何在不为其分配任何内存的情况下存储字符串。str是一个字符指针,指向 char 变量所在的位置i。当我添加时,我str = "Hello";不是使用未分配的5那个位置的字节吗?4

  2. 因为,当我打印它们时,我的代码str = &i;不应该str并且具有相同的价值?&i当我删除str = "Hello";声明str并且相&i同时。如果str&i相同,那么我相信当我说它str = "Hello"应该覆盖'a''H',其余部分'ello\0'进入后续字节。

    我相信整个问题在于str = "Hello"陈述。它似乎不像我想的那样工作。

请有人解释它是如何工作的?

4

7 回答 7

7

当编译器遇到字符串文字时,在这种情况下"Hello",内存分配在静态(全局)内存区域中。这个“分配”是在你的程序执行之前完成的。

当您的程序在 开始执行时main,会分配一个堆栈帧来存储main:str和的局部变量i。请注意,这str是一个仅存储地址的简单变量。它不存储任何字符。它只存储一个指针。

该语句将的地址str = &i;写入变量。stri

该语句将编译器预先分配的字符串文字的地址写入str = "Hello"变量。这是与 的地址完全不同的地址。该分配根本不会将单词“Hello”中的任何字符移动到任何地方。str"Hello"i

TL;DR C 中“字符串”变量的值只是一个指针。分配给字符串变量就是分配一个数字,即一个地址。

于 2013-11-01T04:42:07.583 回答
2

编译器将字节序列 { 'H', 'E', 'L', 'L', 'O', '\0' } 写入可执行文件的一个称为数据段的部分中。

当应用程序运行时,它获取这些字节的地址并将它们存储在表示“str”的变量中。

它不必“分配”内存,因为在运行时,程序不必向操作系统请求内存来存储文本。

您应该尽量避免将这样的字符串文字视为非常量。GCC 的“-Wall”选项将字符串字面量分配给“char*”指针作为

warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]

许多编译器在进行优化编译时,会执行一种称为“字符串池”的操作,从而避免重复字符串。

const char* str1 = "hello";
const char* str2 = "hello";

如果使用字符串池编译,可执行文件可能只包含一个“hello”实例。

于 2013-11-01T04:50:20.633 回答
1

当我说 str = "Hello" 时,我不是在使用来自该位置的 5 个字节,其中 4 个未分配吗?

不。编译器在内存的不同部分(只读部分,但这是对不同问题的答案)留出 6 个字节(记住空终止符)。那作业:

str = "Hello";

导致str指向这 6 个字节中第一个字节的位置,即H.

因为,我说 str=&i; 当我 printf 时 str 和 &i 不应该具有相同的值吗?

是的,但是str在打印任何内容之前,您要在下一行指向其他内容。

于 2013-11-01T04:40:42.093 回答
0

文字字符串"Hello"在某个地方占用了 6 个字节的内存,可能在程序空间中。将指针分配给它只是将指针设置到字符串已经存在的位置。它根本不复制字符。

如果您想复制需要使用的字符strcpy,但由于您没有将指针设置为足够大小的可写缓冲区,如果这样做会导致未定义的行为。

于 2013-11-01T04:40:11.807 回答
0
  1. str是一个指向字符的指针。当你说str = &i;你将它指向一个int时。当您说str = "Hello";要更改 str 以指向存储字符序列 'H'、'e'、'l'、'l'、'o'、0 的位置时。

  2. 但是你说完str = something else就说str = &i

看起来你还没有完全掌握指针......

于 2013-11-01T04:40:24.347 回答
0

好吧,简单地说,每个字符串都是 C 中的一个指针。

如果我们这样运行:

int main() {
    char *str;
    char i='a';
    str = &i;
    str = "Hello";
    printf("%s, %c, %x, %x", str, i, str, &i);
    return 0;
}

当你设置的时候str = &i,你就是在做str 指向i。因此,i == *str&i == str成立。

当您调用 时str = "Hello";str现在指向一个大小为 6 的静态分配数组(这通常直接驻留在您的程序代码中)。因为str是一个指针,所以当您将它重置为指向新数组时,它不会更改i. 现在,如果我们没有设置str为 ,而是设置了,那么现在将具有 'Z' 的值,而仍然指向。"Hello"*str = 'Z';istri

于 2013-11-01T04:40:26.473 回答
0

首先,如何在不为其分配任何内存的情况下存储字符串。str 是一个字符指针,指向 char i 的存储位置。当我说 str = "Hello" 时,我不是在使用来自该位置的 5 个字节,其中 4 个未分配吗?

字符串的内存由编译器分配。我认为该标准并没有确切说明编译器必须如何执行此操作。如果你对你的可执行文件运行'strings',你应该在那里的某个地方找到“Hello”。

因为,我说 str=&i; 当我 printf 时 str 和 &i 不应该具有相同的值吗?当我删除 str = "Hello" 语句时 str 和 &i 是相同的。如果 str 和 &i 相同,那么我相信当我说 str="Hello" 时,它应该用 'H' 覆盖 'a' ,其余的 'ello\0' 进入后续字节。

我认为您在这里缺少的是 str = "Hello" 不会将字符串复制到 str 指向的位置。它改变了 str 指向的内容。“你好”在内存中,您正在将该内存位置分配给指针。如果要将内存复制到指针,则需要使用 memcpy() 或类似的东西。

于 2013-11-01T04:41:54.557 回答