【问题标题】:C++ Error: Incompatible types in assignment of ‘char*’ to ‘char [2]C++ 错误:将‘char*’分配给‘char [2]时的类型不兼容
【发布时间】:2013-04-01 14:35:30
【问题描述】:

我的构造函数有点问题。 在我的头文件中我声明:

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/setter。

【问题讨论】:

  • I already figured out that char[2] <=> char* 不是真的。
  • 但我认为 c++ 编译器的 char[2] 等同于 char* ?!我真的不知道如何正确地初始化这个构造函数和吸气剂......
  • 数组和指针是非常不同的东西。阅读comp.lang.c FAQ 的第 6 部分;这方面的规则对于 C 和 C++ 基本相同。

标签: c++ error-handling char


【解决方案1】:

C++ 中的原始数组有点烦人且充满危险。这就是为什么除非你有充分的理由,否则应该使用std::vectorstd::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)。

【讨论】:

    【解决方案2】:

    当一个函数想要一个数组作为参数时,它会得到一个指向数组第一个元素的指针。该指针不能用于初始化数组,因为它是指针,而不是数组。

    您可以编写接受引用数组作为参数的函数:

    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

    【讨论】:

      【解决方案3】:

      C++ 因为 C 拥有 C 的大部分规则。

      在 C 的情况下,总是使用 char* 来传递数组,因为 C 是这样看待它的。甚至 sizeof (short_name_) 在传递给函数时也会是 8 或 4。 现在,变量 short_name_ 中有 2 个字节的空间

      构造函数在short_name_ 中为两个字节分配内存,您需要将字节复制到其中或使用 char * 指针并假设它的大小为 2。

      Expert C Programming: Deep C Secrets 的第 9 章很适合阅读。

      为简单起见,这可能是 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();
      }
      

      【讨论】:

      • 现在是 2020 年,缓冲区溢出仍然存在。我认为示例/cmets 应该反映 strncpy() 而不是经典的 strcpy(),尤其是在初学者正在寻找的地方。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-03-26
      • 2021-03-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多