У меня есть структура с элементом массива символов как таковая:
typedef struct {
// ...
char myCharArr[200];
} myStruct;
У меня есть динамический массив этих структур. Когда я пытаюсь сохранить символ в myCharArray
, появляется сообщение об ошибке incompatible types in assignment of 'char' to 'char[200]'
.
int num = 2;
myStruct* data = new myStruct[num];
// ...
data[i].myCharArr = 'a'; // error here
Но если я использую строку ниже, она работает нормально
*data[i].myCharArr = 'a';
Через некоторое время я возвращаюсь к C++, поэтому был бы очень признателен, если бы кто-нибудь объяснил разницу между ними. Насколько я понимаю и помню, я могу использовать strcpy
и другие варианты для сохранения строки записи в массив символов, но в данном случае это один символ. Почему разыменование массива помогает сохранить символ в chararray? Кроме того, как сюда относится нулевой терминатор?
Через некоторое время я возвращаюсь к C++. Я могу использовать strcpy. У меня есть динамический массив этих структур. Почему бы не использовать std::string
? А динамический массив в C++ создается с помощью std::vector
. Ваш код больше похож на C
, чем на C++. Если вы только начинаете изучать C++, я рекомендую вам ознакомиться с лучшими практиками современного программирования на C++.
Что здесь i
. Нам нужен минимальный воспроизводимый пример
myCharArr
— это массив. Вы не можете назначить его одному char
. Использование operator*
разыменовывает его, и в случае массива вы получаете ссылку на первый символ, который вы можете присвоить char
.
data[i].myCharArr
дает вам элемент данных myCharArr
, который имеет тип массива char[200]
, и вы пытаетесь присвоить ему char
.
Ваш массив символов содержит 200 символов. Интересно, кто из этих 200, по вашему мнению, data[i].myCharArr = 'a'
изменится? Размышление об этом должно ответить на ваш вопрос. *data[i].myCharArr = 'a';
точно такой же, как data[i].myCharArr[0] = 'a';
, так что это ответ на ваш второй вопрос. *x
и x[0]
быть одним и тем же — одно из правил C++, именно так *
и []
работают.
Последний вопрос: нулевой терминатор вообще отсутствует в вашем коде. Но если вы хотите, чтобы ваш массив завершался нулем, вам нужно добавить код, который сделает это, это не делается за вас. Например, data[i].myCharArr[0] = 'a'; data[i].myCharArr[1] = '\0';
завершает ваш массив нулем.
присвоение значения массиву просто невозможно. Вы можете только копировать данные в массив. например, перебирая символы или используя другие средства, такие как std::memcpy
Имейте в виду, что ваш пример кода типичен для реализации C, но вы предоставили только тег C++. В C++ это выглядело бы немного иначе (в зависимости от контекста, который вы не предоставили). Скорее всего, вам следует использовать std::string
вместо char[200]
.
приложение, над которым я работаю, написано на C++, но оно использует драйвер C MongoDB из-за некоторых проблем с его настройкой для cpp - следовательно, также и некоторый код C. i
можно считать индексом динамического массива (поскольку я перебираю массив позже в коде). Замена i
на 0
подойдет для воспроизведения
Примечание: не делайте этого myStruct* data = new myStruct[num];
в C++, избегайте явного использования операторов new/delete и usw std::vector<myStruct>
. Если вы возвращаетесь к C++, возможно, будет хорошей идеей прочитать Основные рекомендации по C++, это даст вам больше информации о том, что изменилось.
@PepijnKramer спасибо за ваш комментарий, да, как было сказано в принятом ответе, планируется реорганизовать различные части приложения для использования векторов. умные указатели и т. д.
Если бы кто-нибудь мог объяснить разницу между ними.
data[i].myCharArr
дает нам элемент данных myCharArr
, который имеет тип массива char[200]
, и вы пытаетесь присвоить ему символьный литерал 'a'
, что невозможно. Обратите внимание, что массивы в стиле c также распадаются на указатели (здесь char*
).
С другой стороны, когда вы применяете operator*
к *data[i].myCharArr
, это эквивалентно написанию:
*(data[i].myCharArr) //same as data[i].myCharArr;
из-за приоритета оператора .
На этот раз мы по-прежнему получаем char[200]
от data[i].myCharArr
, но он превращается в указатель char
. Затем operator*
разыменовывает этот указатель и дает нам char
, которому можно присвоить 'a'
.
Обратите внимание, что в современном C++ вы можете использовать std::string
, std::array
, std::vector
и т. д. Кроме того, вы можете напрямую назвать класс вместо использования typedef
.
Спасибо! приоритет оператора и переход к указателю теперь делают это намного понятнее. В конечном итоге я проведу рефакторинг для использования векторов для массива структур, а также интеллектуальных указателей в других частях в рамках улучшений приложения, но есть определенные аспекты, которые должны быть на C из-за драйвера mongodb.
@SuhaibAhmad, понятно. Пожалуйста :)
@SuhaibAhmad C++ прекрасно поддерживает библиотеки C (или драйверы). Само по себе это не является причиной не использовать C++ в вашем коде. Например, если у вас есть строка C++ и вы вызываете функцию, которой нужна строка C, вы просто используете методы c_str
или data
для преобразования.
Вы создаете память myStruct динамически, используя новый оператор. Таким образом, он возвращает местоположение этой структуры в памяти. Если вы хотите получить доступ к значению по адресу или ссылке на переменную, вам необходимо разыменовать это значение. В C++ по умолчанию оператор * используется для получения значения в заданной ячейке памяти.
Например, новый myStruct[num]; который возвращает адрес, пусть это будет 3000, и он будет сохранен в data[0]. Если вы поместите data[0], это означает, что вы имеете дело или назначаете только адрес или местоположение этой структуры, то есть 3000, но не значения. Следовательно, вы не можете назначить.
Если вы поместите *(data[0]), это означает, что вы указываете значения в позиции 3000. Таким образом, вы можете назначать или изменять значения.
Приятного кодирования!!
Несвязано:
typedef
здесь больше похоже на C, чем на C++ при использовании с определением классов.