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

C 为什么我可以在字符的内存地址中存储字符串?,c,string,pointers,char,memory-address,C,String,Pointers,Char,Memory Address,我开始理解指针以及如何去引用它们等等。我一直在练习ints,但我认为char也会有类似的行为。使用*解除引用,使用&访问内存地址 但在我下面的示例中,相同的语法用于设置char的地址,并将字符串保存到相同的变量。这是怎么回事?我想我只是普遍感到困惑,也许我想得太多了 int main() { char *myCharPointer; char charMemoryHolder = 'G'; myCharPointer = &charMemoryHolder;

我开始理解指针以及如何去引用它们等等。我一直在练习
int
s,但我认为
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”本质上是一个字符*到
    97980
    的内存块。(97为“a”,98为“b”,0为空终止。)
  • 您的代码
    myCharPointer=&charMemoryHolder
    后跟
    printf(“%s\n”,myCharPointer)
    不安全。printf应该被传递一个以null结尾的字符串,并且不能保证内存中的值0紧跟在字符charMemoryHolder之后

  • 首先,您需要了解“字符串”在C中是如何工作的

    “字符串”作为字符数组存储在内存中。由于无法确定字符串的长度,因此在字符串后面追加一个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'
    ),但一般来说,您不应该这样做。

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

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

    “这是一个字符串。”
    是一个存储在内存中的字符串常量,并且还有一个地址

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

    如果是
    printf(“%s\n”,myCharPointer)
    ,指针将被取消引用并显示字符,然后指针将递增。它会重复此操作,直到找到空(值为零)字符并停止

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