【问题标题】:Explanation for assigning a string to a character pointer in C在 C 中将字符串分配给字符指针的说明
【发布时间】:2014-07-14 18:38:02
【问题描述】:

我对指针非常困惑。如果我们创建一个 'char' 类型的指针变量,类似于char *ch; 并为其分配一个字符数组。然后我们可以通过增加指针(++ch)来访问字符串中的每个字母。

char *ch;
char a[5]="hello";
*ch=a;
while(*ch) {
  printf("%c",*ch);
  ++ch;
}

这工作得很好。但是我看到很多例子,例如,

struct example {
  char *ch;
};

int main() {
  struct example ex={"hello"};
  printf("%s",ex.ch);
}

我对这个例子很困惑,比如直接将字符串分配给字符指针(而不是将字符串分配给变量然后将其分配给字符指针)可以使其可访问。在前面的例子中,*ch 指向数组“a”的起始内存。但在第二种情况下,指针 ch 指向哪个内存?谁能给我一个明确的解释?

【问题讨论】:

  • 相反,字符串字面量是一个字符数组,在必要的时候会衰减为指针。
  • *ch=a 应该是ch=a,对吧?
  • @SteveCox:不,不是。字符串文字对应于 char[N] 类型的对象,其中 N 比长度大一(以允许终止 '\0' 空字符)。像任何数组类型的表达式一样,在大多数但不是所有上下文中,它都隐式转换为指向其第一个元素的指针。请参阅comp.lang.c FAQ 的第 6 节。
  • @SteveCox,肯定是 12 岁。
  • char a[5]="hello";。您没有为空终止符留出空间。

标签: c string pointers


【解决方案1】:

当你做这个任务时

ch=a;

您将指针 ch 设置为字符数组 a[] 的开头(注意:数组保持以空结尾的事实纯属巧合 - 您的代码具有未定义的行为,因为第六个字符 @987654324 "hello" 末尾的 @ 不会复制到五字符数组中)。在赋值 ch 成为存储在数组 a[] 中的 C 字符串的“别名”之后,这意味着您可以将它与字符串操作和格式化例程一起使用。

你的第二个例子不是赋值,它是初始化:

struct example ex={"hello"};

用大括号括起来的是一个初始化器。 C 编译器将获取每个元素(您只有一个,但可以有很多)并将其分配给struct 的相应字段。在这种情况下,字符串文字 "hello" 被分配给 ch 成员。

初始化器的规则是按声明顺序分配花括号中的值。如果您愿意,您可以使用 C99 的指定初始化程序功能来覆盖它:

struct example ex={ .ch = "hello"};

【讨论】:

    【解决方案2】:

    这段代码sn-p

    char *ch;
    char a[5]="hello";
    *ch=a;
    while(*ch)
    {
    printf("%c",*ch);
    ++ch;
    
    }
    

    具有未定义的行为。它可以正常工作,您必须将字符数组声明为

    char a[6]="hello";
    

    或 char a[]="你好";

    在这种情况下,数组确实会有终止零。

    至于这段代码sn-p

    struct example
    {
    char *ch;
    };
    int main()
    {
    struct example ex={"hello"};
    printf("%s",ex.ch);
    }
    

    然后在这个语句中

    struct example ex={"hello"};
    

    编译器首先将字符串文字“hello”作为类型为char[6]的字符数组放在内存中,然后将指向数组第一个元素的指针分配给结构的数据成员ch。

    这两种声明的区别

    char ch[] = "hello";
    

    char *ch = "hello";
    

    是在第一种情况下创建一个字符数组,其中每个元素都由字符串文字的相应字符初始化,该字符本身不会存储在内存中。 在第二种情况下,字符串文字将存储在内存中,指针 ch 将包含其第一个字符的地址。

    【讨论】:

      【解决方案3】:
      char a[] = "hi";
      char *ch = "hello";
      

      这里的a 是一个要存储的大小为 3 个字节的 char 数组,“h”、“i”和“\0”。此内存的 3 个字节在堆栈中分配以保存字符串。

      这里ch是一个指针变量,它存储一个char的地址,ch的大小是4个字节来存储地址(指针的大小是编译器特定的)。那么“hello”是一个常量字符串文字,它将作为只读数据存在于进程内存的文本段中。并将第一个字节的地址分配给ch 变量。为 ch 变量分配了 4 字节的内存来将地址存储在堆栈中,并且在文本段中需要 5 字节的内存来保存字符串文字“hello”。

      有关其他一些观点的解释,请阅读here

      【讨论】:

      • 假设指针总是四个或八个字节不是一个安全的假设。您可能想查看一些示例here
      • 你确定。我刚刚提到了大多数编译器中常见的信息。在 Windows 32 位机器上的 Turbo C 编译器中,指针和 int 的大小为 2 个字节。无论如何,我更新了我的答案。
      猜你喜欢
      • 1970-01-01
      • 2021-01-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多