将一串字符赋值给字符数组

25

我想知道为什么第一个语句在C++中有效而第二个语句无效

char a[10]="iqbal";  // it works

a="iqbal"; // does not work 

这是C还是C++?请具体说明。 - user195488
2
这是SO界面的直接估计结果。请在发布之前搜索:可能是将字符串分配给字符数组的重复内容。 - Jens Gustedt
8个回答

26

严格来说,数组不是指针!而且数组(数组的基地址)不能是可修改的左值。也就是说,它不能出现在赋值运算符的左侧。只有在特定情况下,数组才会衰减为指针。阅读这篇stackoverflow文章以了解何时数组会衰减为指针。这里还有一篇精彩的文章,解释了数组和指针之间的区别。

此外,请在这里阅读关于左值和右值的内容,以便了解不能出现在等号左侧的东西。

char a[10]="iqbal"; //它能工作

在这种情况下,内部发生的事情是

a[0] = 'i';
a[1] = 'q'; 
 .
 .
a[5] = '\0';

array[i]是一个可修改的左值时,一切都好。

a="iqbal"; //不起作用

在内部,这大致相当于

0x60000(Address of a, but is a simple number here ) = Address of "iqbal"

这是错误的,因为我们不能把某物赋值给一个数字。


2
实际上,a 是一个可修改的左值,但不能出现在赋值运算符的左侧。左值和右值中 l 和 r 的含义早已失去。 - avakar
a 可以是一个左值,但不是一个可修改的左值,因此不能出现在 = 的左侧。如果我错了,你能给我指点一些文档吗?我参考了 这里 - Pavan Manjunath
@PavanManjunath:考虑将a作为实际参数传递给一个带有数组形式参数的函数。在这种情况下,显然a是一个可修改的左值。表达式的左值或右值特性不取决于上下文,因此a是一个可修改的左值。 - Cheers and hth. - Alf
我不认为它在内部等同于那个。更像是(指向a的第一个元素的指针)=(指向“iqbal”的第一个元素的指针),尽管“iqubal”是一个字符串字面量,但它应该衰减为一个指针,因为它没有被用来初始化一个数组。 - csguy

6

如果您像这样初始化,那么字符数组a将是静态的,不能更改。无论如何,在c语言中你永远不能使用 a="iqbal" 给一个字符字符串赋值。你必须使用strncpy或memcpy来完成这个任务。否则,您将尝试覆盖指向该字符串的指针,而这不是您想要的。

因此,正确的代码应该像这样:

char a[10];
strncpy(a, "iqbal", sizeof(a) - 1);
a[sizeof(a) - 1] = 0;

-1是为了保留一个字节用于终止零。请注意,您需要自行检查字符串是否以空字符结尾。这是一个糟糕的API。有一个strlcpy()调用可以为您完成此操作,但它不包含在glibc中。


3
因为它们是不同的语句,几乎完全无关。不要因为它们都使用=符号而感到困惑。在一个情况下,它表示对象初始化。在另一个情况下,它表示赋值运算符。
你的第一行是合法的,因为可以初始化聚合体,包括字符数组。
你的第二行不合法,因为不能对数组进行赋值。
由于这是C++,我建议你避免使用裸数组。对于字符字符串,请使用std::string。对于其他数组,请使用std::vector。如果这样做,你的示例将变成:
std::string a = "iqbal";  // it works
a="iqbal"; // so does this

3

第一行不是一个语句,而是一个带初始化的声明。

第二行是一个表达式语句,带有赋值运算符。

C语言中无法给数组赋值。

但你可以使用字符串字面值中的元素来初始化数组。


0

尝试:

char a[10]="iqbal";
char *my_a = a;

并且与我的_a一起工作。


0

当编写 char a[10]="iqbal" 您正在使用字符数组a的元素进行初始化。我们可以使用int类型做同样的事情(请注意,char类型会得到稍微不同的处理): int a[10]={1,2,...};

但在声明部分之后编写以下内容将无效,因为a将被视为指针。因此,编写类似于 a={1,2,...}; 或 a="iqbal" 都没有任何意义!


0
在C++11中,您可以使用lambda进行初始化,如下所示:
bool test = true;
/*const*/ char a[10] = { //Aggregate initialization
                        [=] //capture by value
                           ()//no parameters
                             { //start lambda
    switch (test) {
        case true: return *"test=true"; //*"xxx" don't return a pointer, but the 'string' itself
        case false: return *"test=false"; 
    } //switch
}()};  //}, close the lambda, (), call it, }; close aggregate initialization

当你的环境不支持 std::string,比如NVidia的CUDA或某些嵌入式环境时,这个代码就非常有用。

lambda表达式可以内联,所以内部转换为 char a[10] = test?"xxx":"yyy";

如果您有选择的话,显然应该始终使用 std::string,因为固定大小的字符缓冲区基本上是一个糟糕的设计。

如果您使用 std::string,则可以使用以下方法将其转换为char数组:chararray = mystring.c_str();。如果您坚持使用 printf,这非常有用: printf("s = %s", mystring.c_str());


0

在字符数组声明后,您不能将字符串字面值分配给它。

一个好的、简单而有效的替代方法是使用std::strcpy来实现,像这样:

struct S
{
    char name[30];
};

S s;
std::strcpy( s.name,
    "The moribunds salute you." );

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接