【问题标题】:Why can I store a string in the memory address of a char?为什么我可以将字符串存储在 char 的内存地址中?
【发布时间】:2015-11-22 07:11:57
【问题描述】:

我开始了解指针以及如何取消引用它们等。我一直在使用ints 进行练习,但我认为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 string pointers char memory-address


    【解决方案1】:

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

    “字符串”作为字符数组存储在内存中。由于无法确定字符串的长度,因此在字符串后面附加一个 NUL 字符 '\0',以便我们知道它的结束位置。

    例如,如果你有一个字符串“foo”,它在内存中可能看起来像这样:

    --------------------------------------------
    | 'f' | 'o' | 'o' | '\0' | 'k' | 'b' | 'x' | ...
    --------------------------------------------
    

    '\0' 之后的东西只是碰巧放在字符串之后的东西,可能会也可能不会初始化。

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

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

    char *str = "foo";
    

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

    1. 取消引用str(这会给出'f'
    2. 取消引用(str+1)(这会给出'o'
    3. 取消引用(str+2)(这会给出另一个'o'
    4. 取消引用(str+3)(提供'\0',因此进程停止)。

    这也导致您当前所做的事情实际上是错误的结论。在您的代码中,您有:

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

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

    【讨论】:

      【解决方案2】:

      几个cmets

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

      【讨论】:

        【解决方案3】:

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

        【讨论】:

          【解决方案4】:

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

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

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

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

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

          【讨论】:

            猜你喜欢
            • 2012-04-22
            • 1970-01-01
            • 2021-11-02
            • 2015-12-05
            • 2018-07-15
            • 1970-01-01
            • 1970-01-01
            • 2016-04-13
            • 1970-01-01
            相关资源
            最近更新 更多