У меня есть структура с элементом массива символов как таковая:
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++ при использовании с определением классов.