为什么我可以在一个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;
}
多条评论
- c 中的静态字符串被视为以 null 结尾的 (char *)
字符数组。例如。 "ab" 本质上是一个 char * 到具有
97 98 0
的内存块。 (97 是 'a',98 是 'b',0 是空终止。)
- 您的代码
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()
,它会执行以下操作:
- 取消引用
str
(给出 'f'
)
- 取消引用
(str+1)
(给出 'o'
)
- 取消引用
(str+2)
(这给出另一个 'o'
)
- 取消引用
(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
打印单个字符。
我开始理解指针以及如何取消对它们的引用等。我一直在练习 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;
}
多条评论
- c 中的静态字符串被视为以 null 结尾的 (char *)
字符数组。例如。 "ab" 本质上是一个 char * 到具有
97 98 0
的内存块。 (97 是 'a',98 是 'b',0 是空终止。) - 您的代码
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()
,它会执行以下操作:
- 取消引用
str
(给出'f'
) - 取消引用
(str+1)
(给出'o'
) - 取消引用
(str+2)
(这给出另一个'o'
) - 取消引用
(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
打印单个字符。