Ошибка 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();
}
Другие вопросы по тегам