C - why is strcpy() necessary
有人可以向我解释为什么需要strcpy()来将字符串分配给字符数组,例如下面的代码片段。
1 2 3 4 5 6 7 8 9
| int main (void) {
char s [4];
s ="abc"; //Fails
strcpy(s ,"abc"); //Succeeds
return 0;
} |
s ="abc"失败的原因是什么? 为什么在声明字符串后将strcpy()分配给char数组的唯一方法呢? 对于我来说,您必须使用函数来执行基本分配似乎很奇怪。
C中的数组不可分配且不可复制初始化。这就是数组在C语言中的用法。从历史上看,在值上下文中(在赋值RHS上),数组会衰减为指针,这是形式上防止赋值和复制初始化的原因。这适用于所有阵列,不仅适用于char阵列。
C语言从其前身B和BCPL语言继承了此数组的行为。在那些语言中,数组由物理指针表示。 (显然,当将一个数组分配给另一个数组时,指针的重新分配不是您想要的。)在C语言中,数组不是指针,但是它们通过衰减来"模拟" B和BCPL数??组的历史行为。在大多数情况下指向指针。这一历史遗产使C阵列至今不可复制。
上面的一个例外是使用字符串文字进行初始化。即你可以做
在这种情况下,从概念上讲,我们将字符串文字"abc"复制到数组c。另一个例外是包装到结构类型中的数组,复制整个结构对象时将复制该数组。就是这样。
这意味着无论何时要复制裸(非包装)阵列,都必须使用库级别的内存复制功能,例如memcpy。 strcpy只是专门针对弦乐而设计的一种风格。
-
为了澄清起见,可以使用格式为{ val0, val1, ... }的适当初始化程序来初始化所有数组类型。
-
您不必使用库函数;您可以分配单个字符,例如for (char *dst = s, *src ="abc"; *dst++ = *src++;) ;。不过,库函数是一个更好的选择,因为它更易于阅读并且可以针对系统进行优化。
-
是的,要进一步了解@AnT的内容,strcpy()几乎与memcpy()完全一样,不同之处在于它包含空字节。
这就是C中的数组。您无法分配给它们。如果愿意,可以使用指针:
附带地,有一个C常见问题解答。
Arrays are ``second-class citizens'' in C; one upshot of this
prejudice is that you cannot assign to them.
-
是的,我确实使用了指针,但我只是不理解为什么s =" abc"在我的示例中不起作用。 s是一个字符数组," abc"也是如此...
-
@ C_p678-不,s是char数组," abc"是指向常量字符串的指针。
-
@MByD:并不完全正确。 "abc"不是指针。 "abc"类型为char[4]的数组,在这种情况下,该数组将衰减为类型为char *的指针。注意,在C中,字符串不是常量。好的,它是不可修改的,但类型本身不包含const限定符。
-
@AndryT:要变得更挑剔," const"和" constant"是两个非常不同的东西。" const"可能应该被称为" readonly"。常量或常量表达式是可以在编译时求值的表达式; const对象是无法在运行时修改的对象。考虑const int r = rand();。
简短的答案:历史原因。 C从来没有内置字符串类型。直到C ++出现了std :: string,甚至在第一个实现中都没有实现
长答案:" abc"的类型不是char[],而是char *。 strcpy是一种机制,您可以使用该机制复制指针指向的数据(在本例中为ABC)。
strcpy不是初始化数组的唯一方法,但是,它足够聪明,可以检测并遵守字符串末尾的终止0。您还可以使用memcpy将字符串复制到s中,但这要求您传入要复制的数据的长度,并确保在s中存在终止符0(NULL)。
-
"abc"的类型是char[4]。
-
strcpy不是初始化,而是赋值。可以将字符数组初始化为所有其他数组,请参见AndreyTs的答案。
C语言缺乏任何方便的语法来获取指向字符串文字的指针及其长度指示。包括许多Pascal方言在内的某些语言在每个字符串前加一个字节来报告其长度。这对于许多目的都很好,但是将字符串文字限制为255个字符。 C的方法允许容纳任意长度的字符串文字,但无论长度如何,都只会增加一个字节的开销。
零终止的字符串在几乎所有目的上都比其他形式都差劲,除了字符串文字,但文字到目前为止是许多程序必须处理的最常见的字符串形式,因此拥有库函数具有相当大的优势有效地处理它们;这样,如果它们不理想,就比使用单独的其他类型的库例程集更容易使用零终止的字符串。