例子1:
char s[100] = "abcd"; // declare and initialize - WORKS
示例2:
char s[100]; // declare
s = "hello"; // initalize - DOESN'T WORK ('lvalue required' error)
我想知道为什么第二种方法不起作用。它看起来应该是自然的(对于其他数据类型也有效),有人能解释一下背后的逻辑吗?
char s[100] = "abcd"; // declare and initialize - WORKS
示例2:
char s[100]; // declare
s = "hello"; // initalize - DOESN'T WORK ('lvalue required' error)
我想知道为什么第二种方法不起作用。它看起来应该是自然的(对于其他数据类型也有效),有人能解释一下背后的逻辑吗?
在初始化数组时,C允许您使用值来填充数组。所以
char s[100] = "abcd";
基本上相当于
int s[3] = { 1, 2, 3 };
但是它不允许你进行赋值操作,因为s
是一个数组而不是自由指针。
s = "abcd"
将指向abcd
的指针值赋给s
,但您不能更改s
,因为那么就没有任何东西指向该数组。
如果s
是可以指向任何内容的指针char*
,则可以这样做并且会生效。
如果您想要复制字符串,请使用strcpy
。
\0
来结束的一维字符数组 char
。由于在C语言中不能给数组赋值,因此也不能给字符串赋值。字面量 "hello" 是语法糖,其实际等同于 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);
初始化和赋值是两个不同的操作,它们恰好在这里使用相同的运算符(“=”)。
1 char s[100];
2 s = "hello";
char s[6]
不够吗? - mLstudent33对Sparr's answer进行详细解释:
初始化和赋值是两个不同的操作,但在这里它们都使用相同的运算符(“=”)。
可以这样理解:
想象一下有两个函数,称为InitializeObject
和AssignObject
。当编译器看到thing = value
时,它会查看上下文并调用一个InitializeObject
,如果你正在创建一个新的thing
。如果不是,则调用AssignObject
。
通常情况下,InitializeObject
和AssignObject
的行为通常相同,这没问题。但是在处理char数组(以及其他一些边缘情况)时,它们的行为不同。为什么要这样做?这涉及堆栈与堆等内容,需要另外的文章来详细说明。
PS:顺便说一下,如果您曾经尝试使用C ++,这种思考方式也将有助于您理解复制构造函数和其他类似的东西。
s[0] = 'h';
s[1] = 'e';
s[2] = 'l';
s[3] = 'l';
s[4] = 'o';
s[5] = '\0';
我知道这个问题已经有答案了,但我想分享一下我在C/C++ Facebook群里回答一个非常类似问题的答案。
要将字符串字面值(例如数组只是一块连续分配的内存区域,数组的名称实际上是数组的第一个元素的指针。(引自https://www.quora.com/Can-we-copy-an-array-using-an-assignment-operator)
"Hello world"
或"abcd"
)复制到您的字符数组中,必须手动将字符串字面值的所有字符元素复制到数组中。
char s[100];
这将初始化一个长度为100的空数组。strcpy
strcpy(s, "abcd");
这将从字符串字面值"abcd"
复制内容并将其复制到s [100]
数组中。Here's a great example of what it's doing:
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
的基本工作原理。我对此感到烦恼... 如果能这样做,那真的很合乎逻辑:
char string[10] = "hello";
应该给出相同的结果:
char string[10] = {0};
string = "hello"; // doesn't work!
但我猜它就是不那么工作。无论如何,这是我的解决方法:
char string[10] = {0};
sprintf(string,"hello");
这几乎一样好,因为它很短。
奇怪的是,对我有用的另一件事(虽然可能有点离题)是当你声明结构体数组时,可以使用双引号进行初始化,像这样:
struct myStruct {
char name[NAX_NAME_LEN];
};
struct myStruct name[DATA_ARRAY_SIZE];
name[1] = (struct myStruct ) { "Hello" };
顺便提一下,这种初始化方法被称为“复合字面量”,我很想知道有没有人能解释为什么可以使用双引号而不是字符串 =“hello”的方式……
顺便说一下,如果你有很多字符串,这种方法非常棒,因为它允许你编写像这样的代码:
#define DATA_ARRAY_SIZE 4
enum names{ BOB, GEORGE, FRANK, SARAH};
struct myStruct {
char name[NAX_NAME_LEN];
};
struct myStruct name[DATA_ARRAY_SIZE];
name[BOB ] = (struct myStruct ) { "Bob" };
name[GEORGE] = (struct myStruct ) { "George" };
name[FRANK ] = (struct myStruct ) { "Frank" };
name[SARAH ] = (struct myStruct ) { "Sarah" };
或者,如果你要为某个应用程序进行多语言支持:
#define NUM_LANGUAGES 4
enum languages{ ENGLISH , FRENCH , SWEDISH , ITALIAN };
struct myStruct {
char intro[NAX_NAME_LEN];
};
struct myStruct name[DATA_ARRAY_SIZE];
intro[ENGLISH ] = (struct myStruct ) { "Hello" };
intro[FRENCH ] = (struct myStruct ) { "Bonjour" };
intro[SWEDISH ] = (struct myStruct ) { "Hej" };
intro[ITALIAN ] = (struct myStruct ) { "Ciao" };
yylval.sval=strdup("VHDL + Volcal trance...");
在编程中,yylval是char*类型。strdup函数可以完成该任务。
我会使用的是
char *s = "abcd";
s[0] = 'x'; s[1] = 'y'; s[2] = 'z'; s[3] = 'm';
是可行的。 - RBTchar s[100];
在堆栈上分配了100个字节。您可以像访问int
数组一样访问和修改这些值。行s = "abcd";
试图将指向字符串"abcd"的指针赋给s
,但这没有意义。你引用的话是说,如果你能够进行那个赋值,原始的100个字节的数组将会丢失。(我认为更清楚的是意识到这个操作没有任何意义。虽然s
可能像一个指针一样工作,但它不是一个指针;它是一个在堆栈上的100个字节的数组。) - Nick Matteo