Ошибка C++: несовместимые типы в присваивании 'char*' для 'char [2]
У меня есть небольшая проблема с моим конструктором. В моем заголовочном файле я заявляю:
char short_name_[2];
- и другие переменные
В моем конструкторе:
Territory(std::string name, char short_name[2], Player* owner, char units);
void setShortName(char* short_name);
inline const char (&getShortName() const)[2] { return short_name_; }
В моем файле cpp:
Territory::Territory(std::string name, char short_name[2], Player* owner,
char units) : name_(name), short_name_(short_name),
owner_(owner), units_(units)
{ }
Моя ошибка:
Territory.cpp: в конструкторе 'Territory::Territory(std::string, char*, Player*, char)': Territory.cpp:15:33: ошибка: несовместимые типы при назначении 'char *' для 'char [2]
Я уже понял, что char[2] <=> char*
но я не уверен, как справиться с этим в моем конструкторе и get/setters.
2 ответа
Необработанные массивы в C++ раздражают и представляют опасность. Вот почему, если у вас нет очень веских причин, вы должны использовать std::vector
или же std::array
,
Во-первых, как говорили другие, char[2]
это не то же самое, что char*
или, по крайней мере, обычно. char[2]
размер массива 2 char
а также char*
это указатель на char
, Они часто путаются, потому что массивы будут распадаться на указатель на первый элемент всякий раз, когда им это нужно. Так что это работает:
char foo[2];
char* bar = foo;
Но обратного нет:
const char* bar = "hello";
const char foo[6] = bar; // ERROR
Добавление к путанице, при объявлении параметров функции, char[]
эквивалентно char*
, Так что в вашем конструкторе параметр char short_name[2]
действительно char* short_name
,
Еще одна особенность массивов заключается в том, что они не могут быть скопированы, как другие типы (это одно из объяснений того, почему массивы в параметрах функций рассматриваются как указатели). Так например я не могу сделать что-то вроде этого:
char foo[2] = {'a', 'b'};
char bar[2] = foo;
Вместо этого я должен перебрать элементы foo
и скопировать их в bar
или используйте какую-то функцию, которая делает это для меня, такую как std::copy
:
char foo[2] = {'a', 'b'};
char bar[2];
// std::begin and std::end are only available in C++11
std::copy(std::begin(foo), std::end(foo), std::begin(bar));
Таким образом, в вашем конструкторе вы должны вручную скопировать элементы short_name
в short_name_
:
Territory::Territory(std::string name, char* short_name, Player* owner,
char units) : name_(name), owner_(owner), units_(units)
{
// Note that std::begin and std::end can *not* be used on pointers.
std::copy(short_name, short_name + 2, std::begin(short_name));
}
Как вы видите, все это очень раздражает, поэтому, если у вас нет веских причин, вам просто следует использовать std::vector
вместо сырых массивов (или в этом случае, вероятно, std::string
).
Когда функция хочет получить массив в качестве аргумента, она получает указатель на первый элемент массива. Этот указатель нельзя использовать для инициализации массива, потому что это указатель, а не массив.
Вы можете написать функции, которые принимают ссылки на массивы в качестве аргументов:
void i_dont_accept_pointers(const char (array&)[2]) {}
Проблема в том, что эта ссылка на массив не может быть использована для инициализации другого массива.
class Foo {
char vars[2];
Foo(const char (args&)[2])
: vars(args) // This will not work
{}
};
C++ 11 представлен std::array
устранить эту и другие проблемы массивов. В старых версиях вам придется перебирать элементы массива и копировать их по отдельности или использовать std::copy
,
C++ как C поддерживает большинство правил C.
В случае C всегда используйте char* для передачи массива, потому что так на него смотрит C. Дажеsizeof (short_name_)
будет 8 или 4 при передаче в функцию. Теперь у вас есть 2 байта в переменнойshort_name_
Конструктор выделил память для двух байтов в short_name_
и вам нужно скопировать в него байты или использовать указатель char* и предположить его размер, если 2.
Чтобы понять это, полезно прочитать главу 9 книги "Программирование для экспертов C: секреты Deep C".
Для простоты это может быть код в стиле C.
#include <stdio.h>
#include <iostream>
using namespace std;
class Territory {
private:
string s;
char c[2];
public:
Territory(std::string a, char b[2] /*visualize as char *b*/) {
s = a;
c[0] = b[0]; //or use strcpy
c[1] = b[1];
}
void PrintMe() {
printf ("As string %s as char %c or %s\n",this->s.c_str(), c[0],c);
}
};
main () {
Territory a("hello", "h");
a.PrintMe();
}