将字符串分配给字符数组


78

我对以下内容感到有些惊讶。

范例1:

char s[100] = "abcd"; // declare and initialize - WORKS

范例2:

char s[100]; // declare
s = "hello"; // initalize - DOESN'T WORK ('lvalue required' error)

我想知道为什么第二种方法不起作用。应该看起来很自然(它可以与其他数据类型一起使用)?有人能解释一下这背后的逻辑吗?

Answers:


64

初始化数组时,C允许您使用值填充它。所以

char s[100] = "abcd";

基本上和

int s[3] = { 1, 2, 3 };

但是它不允许您执行赋值,因为它s是一个数组而不是一个自由指针。的含义

s = "abcd" 

是将的指针值分配给abcds但您不能更改,s因为那样一来就不会指向数组。
如果schar*-可以指向任何对象的指针,则可以并且确实可以工作。

如果要复制字符串,请简单使用strcpy


6
好的答案,除非您永远不再使用纯strcpy。使用strncpy或strlcpy。
dwc

3
另外,s应该是const char *,而不是char *。
aib

1
s[0] = 'x'; s[1] = 'y'; s[2] = 'z'; s[3] = 'm';如果即使在初始化后也要一一替换字符串字符,则可以使用。
RBT

@RBT,也许它在您的平台中带有编译标志,但是通常这些字符串是在只读内存中定义的。写它会导致段错误或接入冲突错误
shoosh

为什么?这样做char s[100]; s = "abcd";给人错误是非常合情合理的,因为s的有效作为常量指针处理。因此,如果我们尝试在第二行中分配“ abcd”,我们将尝试更改不允许的指针值。但是,如果const指针指向一个存储位置,则该存储位置的内容当然应该可以修改。假设s指向存储位置1000,则s包含1000,而存储位置#1000包含a。我不能改变s到存储新的存储位置,例如2000,但我可以在存储器位置存储一个新的角色如ž1000
RBT

52

C中没有“字符串”之类的东西。在C中,字符串是的一维数组char,以空字符终止\0。由于无法在C中分配数组,因此也无法分配字符串。文字“你好”是语法糖const char x[] = {'h','e','l','l','o','\0'};

正确的方法是:

char s[100];
strncpy(s, "hello", 100);

或更好:

#define STRMAX 100
char    s[STRMAX];
size_t  len;
len = strncpy(s, "hello", STRMAX);

2
不是推荐的方法。当心strncpy的怪异之处:stackoverflow.com/a/1258577/2974922
nucleon

我认为可以轻松地推荐这种方法
Volt

13

初始化和赋值是两个截然不同的操作,碰巧在这里使用相同的运算符(“ =”)。


3
1    char s[100];
2    s = "hello";

在您提供的示例中,s实际上是在第1行而不是第2行初始化的。即使此时您没有显式地给它赋值,编译器还是这样做了。在第2行,您正在执行分配操作,并且不能像这样将一个字符数组分配给另一个字符数组。您必须使用strcpy()或某种循环来分配数组的每个元素。


为什么需要100个字节的问候?还char s[6]不够吗
mLstudent33

1
@ mLstudent33,这是OP给出的示例。
马特·戴维斯

2

扩大Sparr的答案

初始化和赋值是两个截然不同的操作,碰巧在这里使用相同的运算符(“ =”)。

这样想:

想象有两个函数,分别称为InitializeObjectAssignObject。当编译器看到时thing = value,它会检查上下文并InitializeObject在创建新内容时调用上下文thing。如果您不是,则调用AssignObject

通常,这很好InitializeObject并且AssignObject通常以相同的方式运行。除了在处理char数组(和其他一些边缘情况)时,它们的行为有所不同。为什么这样 好吧,这是另一篇有关堆栈与堆的文章,依此类推。

PS:顺便说一句,如果您尝试使用C ++,以这种方式进行思考也将帮助您了解复制构造函数和其他类似内容。


0

请注意,您仍然可以执行以下操作:

s[0] = 'h';
s[1] = 'e';
s[2] = 'l';
s[3] = 'l';
s[4] = 'o';
s[5] = '\0';

即使我很确定strncpy()在内部完全执行此操作,使用strncpy()也会更好,更容易。
克里斯·卢兹

当然。但这与's =“ hello”;'差不多。实际上,这应该已经在C中实现了,请参见如何分配结构。
aib

我的意思是,在结构中而不是在数组中按成员分配进行成员复制没有任何意义。
aib

0

我知道已经回答了这个问题,但是我想与一个在C / C ++ Facebook小组中问过一个非常类似问题的人分享一个答案。


数组没有赋值运算符功能*。这意味着您不能简单地将char数组分配给字符串文字。为什么?因为数组本身没有任何赋值运算符。(*这是一个常量指针,无法更改。)

数组只是连续分配的内存区域,数组的名称实际上是指向数组第一个元素的指针。(引用自https://www.quora.com/Can-we-copy-an-array-using-an-assignment-operator

要将字符串文字(例如"Hello world""abcd")复制到char数组,您必须手动将字符串文字的所有char元素复制到数组中。

char s[100]; 这将初始化一个长度为100的空数组。

现在将字符串文字复制到此数组上,使用 strcpy

strcpy(s, "abcd");这将从字符串文字中复制内容"abcd"并将其复制到s[100]数组中。

这是一个很好的例子:

int i = 0; //start at 0
do {
    s[i] = ("Hello World")[i]; //assign s[i] to the string literal index i
} while(s[i++]); //continue the loop until the last char is null

您显然应该使用strcpy此自定义字符串文字复印机代替它,但这是一个很好的示例,说明了其strcpy原理。

希望这可以帮助!


-1

您可以使用此:

yylval.sval=strdup("VHDL + Volcal trance...");

其中yylval是char *。strdup从完成这项工作。


<string.h>的strdup可以完成此工作:)
Yekatandilburg

strdup复制一个副本,并返回指向该副本的指针。在这种情况下,对于char数组,您将回到没有做任何工作的地方
JoshKisb,

-3

我会用的是

char *s = "abcd";

2
我们大多数人不会,因为它冒着不确定行为的风险。以上仅适用于const char*
Toby Speight
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.