为什么我可以在一个char的内存地址中存储一个字符串?

Why can I store a string in the memory address of a char?

我开始理解指针以及如何取消对它们的引用等。我一直在练习 int,但我认为 char 的行为类似。使用*解引用,使用&访问内存地址。

但在我下面的示例中,相同的语法用于设置 char 的地址并将字符串保存到同一变量。这是如何运作的?我想我只是普遍感到困惑,也许我想多了。

int main()
{
    char *myCharPointer;
    char charMemoryHolder = 'G';
    myCharPointer = &charMemoryHolder;
    printf("%s\n", myCharPointer);
    myCharPointer = "This is a string.";
    printf("%s\n", myCharPointer);

    return 0;
}

多条评论

  1. c 中的静态字符串被视为以 null 结尾的 (char *) 字符数组。例如。 "ab" 本质上是一个 char * 到具有 97 98 0 的内存块。 (97 是 'a',98 是 'b',0 是空终止。)
  2. 您的代码 myCharPointer = &charMemoryHolder; 后跟 printf("%s\n", myCharPointer) 安全。 printf 应该传递一个空终止字符串,并且不能保证内存包含值 0 紧跟在您的字符 charMemoryHolder 之后。

首先,您需要了解 "strings" 在 C 中是如何工作的。

"Strings"在内存中以字符数组形式存储。由于无法确定字符串的长度,因此在字符串后附加一个 NUL 字符 '[=13=]',以便我们知道它在哪里结束。

例如,如果您有一个字符串 "foo",它在内存中可能如下所示:

--------------------------------------------
| 'f' | 'o' | 'o' | '[=10=]' | 'k' | 'b' | 'x' | ...
--------------------------------------------

'[=13=]'后面的东西只是刚好放在字符串后面的东西,可以初始化也可以不初始化。

当您将 "string" 分配给 char * 类型的变量时,发生的情况是该变量将指向字符串的开头,因此在上面的示例中它将指向 'f'。 (换句话说,如果您有一个字符串 str,那么 str == &str[0] 始终为真。) 当您将一个字符串分配给 char * 类型的变量时,您是实际上是将字符串的第零个字符的地址赋值给变量。

当您将此变量传递给 printf() 时,它从指向的地址开始,然后一个一个地遍历每个字符,直到它看到 '[=13=]' 并停止。例如,如果我们有:

char *str = "foo";

然后你将它传递给 printf(),它会执行以下操作:

  1. 取消引用 str(给出 'f'
  2. 取消引用 (str+1)(给出 'o'
  3. 取消引用 (str+2)(这给出另一个 'o'
  4. 取消引用 (str+3)(给出 '[=13=]' 因此进程停止)。

这也得出结论,您目前所做的实际上是错误的。在你的代码中你有:

char charMemoryHolder = 'G';
myCharPointer = &charMemoryHolder;
printf("%s\n", myCharPointer);

printf() 看到 %s 说明符时,它会转到 myCharPointer 指向的地址,在本例中它包含 'G'。然后它将尝试获取 'G' 之后的下一个字符,这是未定义的行为。它可能时不时地给你正确的结果(如果下一个内存位置恰好包含'[=13=]'),但通常你不应该这样做。

在 C 语言中,字符串文字计算为指向只读字符数组的指针(除非用于初始化 char 数组)。这是C语言中的特例,不泛化到其他指针类型。 char * 变量可以保存单个 char 变量的地址或字符数组的起始地址。在这种情况下,数组是存储在静态内存区域中的字符串。

charMemoryHolder是一个在内存中有地址的变量。

"This is a string."是一个字符串常量,存放在内存中,也有地址。

这两个地址都可以存储在 myCharPointer 中并取消引用以访问第一个字符。

printf("%s\n", myCharPointer)的情况下,指针将被取消引用并显示字符,然后指针递增。它重复这个直到找到一个空(零值)字符并停止。

希望您现在想知道当您指向单个 'G' 字符时会发生什么,它不像字符串常量那样以 null 结尾。答案是 "undefined behavior" 并且很可能会打印随机垃圾,直到它在内存中找到零值,但可以打印出正确的值,因此 "undefined behavior"。使用 %c 打印单个字符。