C - 为啥 strcpy() 是必要的

Posted

技术标签:

【中文标题】C - 为啥 strcpy() 是必要的【英文标题】:C - why is strcpy() necessaryC - 为什么 strcpy() 是必要的 【发布时间】:2011-10-17 13:59:27 【问题描述】:

谁能给我解释一下为什么 strcpy() 必须将字符串分配给字符数组,例如在下面的代码 sn-p 中。

int main(void) 

char s[4];

s = "abc"; //Fails
strcpy(s, "abc"); //Succeeds

return 0;

s = "abc" 失败的原因是什么?为什么 strcpy() 是在声明字符串后将字符串分配给 char 数组的唯一方法?对我来说,您必须使用函数来执行基本任务似乎很奇怪。

【问题讨论】:

【参考方案1】:

C 中的数组是不可赋值和不可复制初始化的。这就是数组在 C 中的样子。从历史上看,在值上下文中(在赋值的 RHS 上)数组衰减为指针,这就是正式阻止赋值和复制初始化的原因。这适用于所有数组,而不仅仅是char 数组。

C 语言从其前身——B 和 BCPL 语言继承了这种数组行为。在那些语言中,数组由物理指针表示。 (显然,当您将一个数组分配给另一个数组时,指针的重新分配并不是您想要发生的事情。)在 C 语言中,数组不是指针,但它们确实通过衰减来“模拟”B 和 BCPL 数组的历史行为在大多数情况下指向指针。这一历史遗产使 C 数组至今仍不可复制。

上面的一个例外是使用字符串文字进行初始化。 IE。你可以做

char c[] = "abc";

在这种情况下,从概念上讲,我们将复制字符串文字"abc" 到数组c。另一个例外是数组包装成一个结构类型,它在整个结构对象被复制时被复制。就是这样。

这意味着无论何时你想复制一个裸(非包装)数组,你都必须使用库级别的内存复制函数,比如memcpystrcpy 只是专门为处理字符串而设计的一种风格。

【讨论】:

澄清一下,所有数组类型都可以使用 val0, val1, ... 形式的适当初始化程序进行初始化。 你没有使用库函数;您可以分配单个字符,例如for (char *dst = s, *src = "abc"; *dst++ = *src++;) ;。库函数是一个更好的选择,因为它更易于阅读并且可以针对系统进行优化。 是的,要详细了解@AnT 所说的,strcpy() 几乎与memcpy() 完全相同,只是它包含空字节。【参考方案2】:

这就是 C 中的数组。您不能分配给它们。如果您愿意,可以使用指针:

char *p;
p = "abc";

顺便说一句,有一个C FAQ。

数组是 C 中的“二等公民”;结果之一 偏见是你不能分配给他们

【讨论】:

是的,我确实使用了指针,但我只是不明白为什么 s = "abc" 在我的示例中不起作用。 s 是一个 char 数组,“abc”也是如此...... @C_p678 - 不,s 是一个字符数组,“abc”是一个指向常量字符串的指针。 @MByD:不完全正确。 "abc" 不是指针。 "abc" 类型为char[4] 的数组,在此上下文中衰减为char * 类型的指针。请注意,在 C 中,字符串不是常量。它是不可修改的,但是类型本身不包含const 限定符。 @AndryT:为了更加挑剔,“const”和“constant”是两个非常不同的东西。 “const”可能应该被称为“readonly”。常量或常量表达式是可以在编译时计算的; const 对象是不能在运行时修改的对象。考虑const int r = rand();【参考方案3】:

简短回答:历史原因。 C 从来没有内置的字符串类型。直到 C++ 出现,std::string 才出现,甚至在第一个实现中也没有出现

长答案:“abc”的类型不是char[],而是char *strcpy 是一种机制,您可以使用它复制指针指向的数据(在本例中为 ABC)。

strcpy 不是初始化数组的唯一方法,但是,它足够聪明,可以检测并尊重字符串末尾的终止 0。您也可以使用memcpy 将字符串复制到s,但这需要您传入要复制的数据的长度,并确保s 中存在终止0(NULL)

【讨论】:

"abc" 的类型是char[4] strcpy 不是初始化而是赋值。字符数组可以初始化为所有其他数组,请参阅 AndreyT 的回答。【参考方案4】:

C 语言缺乏任何方便的语法来获取指向字符串文字的指针以及其长度的指示。包括许多 Pascal 方言在内的一些语言在每个字符串前面加上一个字节来报告其长度;这适用于许多目的,但将字符串文字限制为 255 个字符。 C 的方法允许容纳任何长度的字符串文字,但无论长度如何,都只会增加一个字节的开销。

在几乎所有用途other中,零结尾的字符串都不如字符串文字,但文字是许多程序必须处理的最常见的字符串形式,因此,让库函数有效地处理它们具有相当大的优势;然后,在它们不太理想的情况下使用以零结尾的字符串比为其他类型使用一组单独的库例程变得更容易。

【讨论】:

以上是关于C - 为啥 strcpy() 是必要的的主要内容,如果未能解决你的问题,请参考以下文章

memcpy函数strcpy函数strncpy函数

我在linux中编译C语言为啥提示“隐式声明与内建函数‘strcpy’不兼容 ”?

为啥 strcpy 会触发全局变量的分段错误?

vs2008中为啥使用strcpy不安全而用strcpy_s替换(尽量详细点)

为啥要使用 strncpy 而不是 strcpy?

为啥 std::strcpy 仍然适用于 char copyTo[0] 之类的目的地?