为什么我不能在结构体中初始化字符数组?

3
typedef struct book {

   int a;
   int b;
   char cb[100];

   book(int a1, int b1, char* cb1) {
       a = a1;
       b = b1;
       cb = cb1;
   }

} book;

为什么我不能将cb初始化为cb1,如何在不使用strcpy的情况下完成它?

2
cb 是一个数组,不是指针,不能被赋值。它实际上是在结构体内为您分配的内存,您获得了这个内存块的关键。这就像“嘿,我买了一栋房子,它在 Wayway Ave 39 号”,然后你的妻子说“太好了,你能把它搬到 Wayway Ave 40 号吗?”如果您想要一个可以赋值的指针,请使用 char *cb - Amadan
3个回答

4

为什么我不能将cb初始化为cb1,如何在不使用strcpy的情况下进行初始化?

cb1char*类型,但cb是C风格的数组,也就是正式的数组对象类型(具体来说是一个char[100])。数组对象类型无法被修改(即使它们是lvalue)。如果你只想进行浅拷贝而不是像你所说的strcpy(),那么你可以将cb定义为char*而不是char[100]

typedef struct book {

   // ...
   char* cb;

   book(int a1, int b1, char* cb1) {
       // ...
       cb = cb1;
   }

} book;

但在大多数情况下,我不建议这样做,因为它会导致对原始指针的不稳定管理。既然标记为[C++],有没有使用std::string的理由呢?


注意:虽然您没有标记这个[C++11]或更高版本,但进一步的原因不使用这样的原始指针或类C数组是当您尝试使用上面的结构体时可能会发生什么,可能是这样的:
int main() {
    book b(4, 2, "Hello");
    return 0;
}

一个相当标准的编译器,例如Clang,会立即让你知道:

ISO C++11不允许将字符串文字转换为“char *”。

这种从字符串字面量(其类型为const char[])到char*的隐式转换,即使在C++03中也已经过时,现在自C++11起完全删除。

1默认情况下,这至少是一个警告,并且在例如使用-pedantic-errors构建时会出错。


1
@SkepticalEmpiricist,谢谢您的回答,确实澄清了我的疑虑。无需进一步解释。 - Manish Madugula
@Destructor,我在规范中找不到这个条款,你有吗?能否提供一下,我可以添加到答案中? - Geezer
@SkepticalEmpiricist:请查看这个链接,并阅读这篇回答以获取更多信息。希望您能更新您的回答。 - Destructor
@Destructor 尽管我的代码段是有效的,但它现在不包括您所要求添加的内容,我完全同意您指出的这一点非常重要。非常感谢您的推动,并让我知道是否有其他需要改变或添加的地方。 - Geezer
1
@SkepticalEmpiricist 你花了近7个小时的时间进行研究,最终得出了一个好答案。值得点赞 :) - JeJo
显示剩余4条评论

1
您问为什么无法在结构体中初始化char[],原因是:
在C语言中,数组是“二等公民”;这种偏见的一个结果是你不能对它们进行赋值。在C和C++中,数组不是可修改的lvalue。
C和C++是不同的编程语言。在C++中应该避免使用旧式的C风格数组,因为C++提供了更方便、更好的替代方法。
因为这个问题被标记为C++问题,惯用的解决方法是在C++中使用std::string。
所以,最好按照以下步骤操作:
#include <string>

struct book {

   int a;
   int b;
   std::string cb;

   book(int a1, int b1, std::string cb1) {
       a = a1;
       b = b1;
       cb = cb1;
   }

} book;

1
我不会说数组是二等公民。数组类型是完整的类型。它们是真实的事物,而非幽灵。它们有存储、生命周期以及其他你期望的一切东西。你可以轻松地传递指向它们的指针和引用,并且(当包装在类中时)也可以被复制/移动。就个人而言,我认为名字衰减规则以及无法通过直接赋值进行复制的特性是孤立的怪异之处。无论如何,这不重要,因为 OP 正试图从已经有缺陷的指针初始化数组。 - Lightness Races in Orbit

1
你的帖子标记为[C++],但没有使用现代惯用语。这是一个允许简单初始化的版本。通过使用std::string,您可以避免复杂的初始化。
请注意,您也不必重命名参数。
使用std::string
#include <iostream>
#include <string>

class book {
public:
   int a;
   int b;
   std::string cb;

   book(int a, int b, const char* cb)
    : a(a),
      b(b),
      cb(cb)
    {
    }
};

int main()
{
    using namespace std;
    const book test(5, 17, "Woot!");
    cout << "Hello " << test.cb << endl; 

    return 0;
}

输出

$main
Hello Woot!

2
您还可以将cb参数定义为std::string类型。 - Destructor
1
使用const来声明数据成员不是一个好主意。 - M.M
1
@M.M. 你让它听起来好像那是本质上的坏事一样。 - Lightness Races in Orbit
1
如果您想将此内容放入容器中,那么最好使用可变但私有成员,这些成员无法通过提供的API进行修改。 - Lightness Races in Orbit
1
好的,没问题 ^_^ - Lightness Races in Orbit
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接