【问题标题】:difference between char* and char[] with strcpy()char* 和 char[] 与 strcpy() 的区别
【发布时间】:2012-06-29 01:18:19
【问题描述】:

在过去的几个小时里,我在一个我理解的问题上遇到了麻烦。这是我的麻烦:

void cut_str(char* entry, int offset) {
    strcpy(entry, entry + offset);
}

char  works[128] = "example1\0";
char* doesnt = "example2\0";

printf("output:\n");

cut_str(works, 2);
printf("%s\n", works);

cut_str(doesnt, 2);
printf("%s\n", doesnt);

// output:
// ample1
// Segmentation: fault

我觉得关于 char*/char[] 有一些重要的东西我没有说到这里。

【问题讨论】:

标签: c string char


【解决方案1】:

区别在于doesnt指向的内存属于字符串常量,因此不可写。

当你这样做时

char  works[128] = "example1\0";

编译器将不可写字符串的内容复制到可写数组中。顺便说一句,\0 不是必需的。

然而,当你这样做时,

char* doesnt = "example2\0";

编译器使指针指向不可写的内存区域。同样,\0 将由编译器插入。

如果您使用gcc,您可以让它警告您有关使用字符串文字初始化可写char *。选项是-Wwrite-strings。您将收到如下所示的警告:

 warning: initialization discards qualifiers from pointer target type

声明doesnt指针的正确方法如下:

const char* doesnt = "example2\0";

【讨论】:

  • “编译器将不可写字符串的内容复制到可写数组中”——不完全是。 "example1\0" 这里不是一个不可写的字符串,它是字符串文字——一个纯粹的句法元素。在这种情况下,它被用作初始化程序。
  • "你应该收到关于 char *doesnt = ... 行的警告" -- 不,真的,不是。幸运的是,没有编译器会这样做。
  • @JimBalter g++ 确实:“警告:不推荐从字符串常量到‘char*’的转换”。那不是一个 C 编译器,但我没有编造它:)
  • 对,这是一个 C 问题(和答案),而不是 C++。
  • @JimBalter 我编辑了答案以解释您如何从gcc 收到警告。我想“没有编译器会那样做”就这么多了......
【解决方案2】:

char[]char * 类型非常相似,所以你是对的。不同之处在于初始化类型的对象时会发生什么。您的对象works,类型为char[],在堆栈上为其分配了128 字节的变量存储空间。您的对象doesnt,类型为char *堆栈上没有存储空间。

doesnt 字符串的确切存储位置未由 C 标准指定,但很可能它存储在加载程序以执行时加载的不可修改数据段中。这不是变量存储。因此,当您尝试改变它时会出现段错误。

【讨论】:

  • “区别在于”——数组和指针之间还有其他重要的区别。这里的问题真的不在于那个,而在于不指向字符串常量的事实,并且标准说修改它的结果是未定义的。
【解决方案3】:

这会在堆栈上分配 128 个字节,并使用名称 works 来指代其地址:

char works[128];

所以works 是一个指向可写内存的指针。

这会创建一个字符串文字,它位于只读内存中,并使用名称doesnt 来引用其地址:

char * doesnt = "example2\0";

您可以将数据写入works,因为它指向可写内存。您不能将数据写入doesnt,因为它指向只读内存。

另外,请注意,您不必以"\0" 结束字符串文字,因为所有字符串文字都会在字符串末尾隐式添加一个零字节。

【讨论】:

  • 不,works 是一个数组对象,而不是一个指针。 (在大多数情况下,它的名称衰减为指针表达式。)
  • "这在栈上分配了 128 个字节"——我们不知道存储类;它可能是外部的。正如 Keith 所说,数组不是指针。 (一个后果是sizeof(works) != sizeof((char*)works))。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-03-22
  • 2011-11-25
  • 1970-01-01
  • 2014-10-19
  • 1970-01-01
  • 2012-04-07
  • 1970-01-01
相关资源
最近更新 更多