2011-08-01 206 views
20

有人可以向我解释为什么需要strcpy()将字符串分配给字符数组,例如下面的代码片段。C - 为什么需要strcpy()

int main(void) { 

char s[4]; 

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

return 0; 
} 

s = "abc"失败的原因是什么?为什么strcpy()是在声明后将字符串分配给char数组的唯一方法?我觉得你不得不使用一个函数来执行基本任务。

回答

12

这就是C中的数组。你不能指定给它们。如果你喜欢,你可以使用指针:

char *p; 
p = "abc"; 

顺便说一下,有一个C FAQ

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

+0

是的,我使用指针,我只是不明白为什么s =“abc”在我的例子中不起作用。 s是一个char数组,“abc”也是...... –

+4

@ C_p678 - 不,s是一个char数组,“abc”是一个指向常量字符串的指针。 – MByD

+3

@MByD:不完全正确。 ''abc“'不是一个指针。 ''abc''是一个'char [4]'类型的数组,在这种情况下,它会衰减到一个'char *'类型的指针。请注意,在C中,字符串不是常量。它是不可修改的,但类型本身不包含'const'限定符。 – AnT

24

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

C语言从它的前辈-B和BCPL语言中继承了这种数组行为。在这些语言中,数组由物理指针表示。 (显然,当你将一个数组分配给另一个数组时,指针的重新赋值并不是你想要发生的。)在C语言中,数组不是指针,但它们通过衰减“模拟”B和BCPL数​​组的历史行为指针在大多数情况下。这个历史遗产是让C阵列不可复制到今天。

从上面的一个例外是用字符串文字初始化。即你可以做

char c[] = "abc"; 

但就是这样。

这意味着无论何时要复制数组,都必须使用库级复制功能,如memcpystrcpy只是专门为字符串工作而设计的。

+1

为了澄清,所有的数组类型都可以用'{val0,val1,...}'形式的适当的初始化方法初始化。 –

+0

你不*有*使用库函数;您可以分配单个字符,例如'for(char * dst = s,* src =“abc”; * dst ++ = * srC++;);'。尽管库函数是一个更好的选择,因为它更易于阅读,并且可以针对系统进行优化。 –

+1

是的,要更多地了解@AnT所说的内容,'strcpy()'几乎和'memcpy()'完全一样,只是它包含空字节。 – RastaJedi

1

简答:历史原因。 C从来没有内置的字符串类型。直到C++出现,std :: string应运而生,甚至在第一次实现时没有到达。

长答案:“abc”的类型不是char[],而是char *strcpy是一个可以复制指针指向的数据的机制(在这种情况下,这是ABC)。

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

+3

''abc“'的类型是'char [4]'。 –

+3

而'strcpy'不是一个初始化,而是一个赋值。字符数组可以初始化为所有其他数组,请参阅AndreyT的答案。 –

0

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

零结尾的字符串逊色于其他形式的几乎每一个目的其他不是字符串文字,但文字是如此远和字符串的最常见的形式,许多项目将需要处理,因此存在具有图书馆职能有效处理这些功能的相当大的优势那么在不太理想的情况下使用零终止字符串比为其他类型创建单独的一组库例程变得更容易。