我开始理解指针以及如何取消引用它们等等。我一直在练习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;
}
答案 0 :(得分:6)
首先,您需要了解“字符串”在C中的工作原理。
“Strings”作为字符数组存储在内存中。由于无法确定字符串的长度,因此在字符串后面附加NUL字符'\0'
,以便我们知道字符串的结束位置。
因此,例如,如果你有一个字符串“foo”,它在内存中可能看起来像这样:
--------------------------------------------
| 'f' | 'o' | 'o' | '\0' | 'k' | 'b' | 'x' | ...
--------------------------------------------
'\0'
之后的东西只是碰巧放在字符串后面的东西,可能会也可能不会被初始化。
当您为类型char *
的变量分配“字符串”时,会发生变量将指向字符串的开头,因此在上面的示例中它将指向'f'
。 (换句话说,如果您有一个字符串str
,那么str == &str[0]
始终为真。)当您将字符串分配给char *
类型的变量时,您实际上正在分配字符串的第0个字符到变量的地址。
当你将这个变量传递给printf()
时,它从指向的地址开始,然后逐个遍历每个字符,直到它看到'\0'
并停止。例如,如果我们有:
char *str = "foo";
并将其传递给printf()
,它将执行以下操作:
str
(提供'f'
)(str+1)
(提供'o'
)(str+2)
(提供另一个'o'
)(str+3)
(提供'\0'
以便流程停止)。这也可以得出结论,你目前所做的事实上是错误的。在您的代码中,您有:
char charMemoryHolder = 'G';
myCharPointer = &charMemoryHolder;
printf("%s\n", myCharPointer);
当printf()
看到%s
说明符时,它会转到myCharPointer
指向的地址,在这种情况下它包含'G'
。然后它将尝试在'G'
之后获取下一个字符,这是未定义的行为。它可能偶尔给你正确的结果(如果下一个内存位置碰巧包含'\0'
),但一般情况下你永远不应该这样做。
答案 1 :(得分:2)
几条评论
97 98 0
的内存块的char *。 (97是'a',98是'b',0是空终止。)myCharPointer = &charMemoryHolder;
后跟printf("%s\n", myCharPointer)
不安全。 printf应该传递一个以null结尾的字符串,并且不能保证内存中包含值0,紧跟在你的字符charMemoryHolder之后。答案 2 :(得分:0)
在C中,字符串文字计算为指向只读的字符数组的指针(用于初始化char
数组时除外)。这是C语言中的特殊情况,不会推广到其他指针类型。 char *
变量可以保存单个char
变量的地址或字符数组的起始地址。在这种情况下,数组是一串字符,存储在内存的静态区域中。
答案 3 :(得分:0)
charMemoryHolder
是一个在内存中有地址的变量。
"This is a string."
是一个字符串常量,存储在内存中并且还有一个地址。
这两个地址都可以存储在myCharPointer
中并取消引用以访问第一个字符。
在printf("%s\n", myCharPointer)
的情况下,指针将被取消引用并显示字符,然后指针递增。它重复此操作直到找到null(值为零)字符并停止。
希望您现在想知道当您指向单个'G'
字符时会发生什么,该字符不像字符串常量那样以空值终止。答案是"未定义的行为"并且很可能会打印随机垃圾,直到它在内存中找到零值,但可以打印出正确的值,因此"未定义的行为"。使用%c
打印单个字符。