Присвоение строк массивам символов - PullRequest
62 голосов
/ 24 февраля 2009

Я немного удивлен следующим.

Пример 1:

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

Пример 2:

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

Мне интересно, почему второй подход не работает. Кажется естественным, что он должен (это работает с другими типами данных)? Может ли кто-нибудь объяснить мне логику этого?

Ответы [ 9 ]

51 голосов
/ 24 февраля 2009

При инициализации массива C позволяет вам заполнить его значениями. Так

char s[100] = "abcd";

в основном совпадает с

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

но это не позволяет вам выполнять присваивание, поскольку s является массивом, а не свободным указателем. Значение

s = "abcd" 

- присвоить значение указателя abcd для s, но вы не можете изменить s, поскольку тогда ничто не будет указывать на массив.
Это может работать и работает, если s является char* - указатель, который может указывать на что угодно.

Если вы хотите скопировать строку, просто используйте strcpy.

49 голосов
/ 24 февраля 2009

В Си нет такой вещи, как «строка». В Си строки - это одномерный массив 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);
10 голосов
/ 24 февраля 2009

Инициализация и присвоение - это две разные операции, в которых используется один и тот же оператор ("=").

3 голосов
/ 24 февраля 2009
1    char s[100];
2    s = "hello";

В приведенном вами примере s фактически инициализируется в строке 1, а не в строке 2. Несмотря на то, что в этот момент вы не указали ему значение явно, это сделал компилятор. В строке 2 вы выполняете операцию присваивания, и вы не можете назначить один массив символов другому массиву символов, как этот. Вам нужно будет использовать strcpy () или какой-нибудь цикл для назначения каждого элемента массива.

2 голосов
/ 24 февраля 2009

Расширить на Ответ Спарра

Инициализация и присвоение - это две разные операции, в которых используется один и тот же оператор ("=").

Думайте об этом так:

Представьте, что есть 2 функции, называемые InitializeObject и AssignObject. Когда компилятор видит thing = value, он смотрит на контекст и вызывает один InitializeObject, если вы создаете новый thing. Если нет, вместо этого он вызывает AssignObject.

Обычно это нормально, поскольку InitializeObject и AssignObject обычно ведут себя одинаково. За исключением случаев, когда имеешь дело с массивами символов (и несколькими другими крайними случаями), в этом случае они ведут себя по-разному. Зачем это делать? Ну, это совсем другой пост, касающийся стека против кучи и так далее и тому подобное.

PS: Если подумать об этом, это поможет вам понять конструкторы копирования и другие подобные вещи, если вы когда-нибудь решитесь на C ++

0 голосов
/ 01 марта 2019

Я знаю, что на этот вопрос уже был дан ответ, но я хотел бы поделиться ответом, который я дал кому-то, кто задал очень похожий вопрос в группе C / C ++ Facebook.


Массивы не имеют функций оператора присваивания *. Это означает, что вы не можете просто присвоить массив символов строковому литералу. Зачем? Потому что сам массив не имеет оператора присваивания. (* Это константный указатель, который нельзя изменить.)

массивы - это просто область непрерывной выделенной памяти и имя массива на самом деле является указателем на первый элемент массива. (Цитата из 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 в основном работает.

Надеюсь, это поможет!

0 голосов
/ 21 июля 2015

Вы можете использовать это:

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

Где yylval - это char *. strdup от делает работу.

0 голосов
/ 09 октября 2012

Я бы использовал

char *s = "abcd";
0 голосов
/ 24 февраля 2009

Обратите внимание, что вы все еще можете сделать:

s[0] = 'h';
s[1] = 'e';
s[2] = 'l';
s[3] = 'l';
s[4] = 'o';
s[5] = '\0';
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...