【问题标题】:A struct that contains an array of char arrays包含 char 数组的结构体
【发布时间】:2019-01-16 07:58:32
【问题描述】:

我正在尝试定义一个结构的实例,并且在设置这个变量时遇到了特别的麻烦。它是一个 char 数组。

这是我的头文件中的结构...

struct widget_t {
    char *name;
    uint8_t numberOfNicknames;
    char *nicknames[];
};

这是我尝试设置 widget_t 结构的实例...

widget_t SomeWidget;

void setUpFunction () {
    SomeWidget.name = (char *)"Lawn Mower";
    SomeWidget.numberOfNicknames = 2;
    SomeWidget.nicknames = {
        "Choppie McGrasschopper",
        "Really Noisy"
    };
}

所以,当我尝试将昵称放入 SomeWidget.nicknames 时,就会发生错误。我不确定我是否需要做一些时髦的事情,就像我用name 作为指针做的那样......?

棘手的一点是nicknames 的数量是可变的。所以每个实例都需要设置不同数量的实例。

【问题讨论】:

  • 尽管 C++ 没有灵活的数组成员,但将其作为扩展提供的编译器几乎都遵循 C 语义。这意味着,尽管标签不匹配,但这个 Q&A stackoverflow.com/q/8687671 几乎是重复的。

标签: c++ arduino flexible-array-member


【解决方案1】:

您遇到的问题是 c++ 不支持变量数组。相反,您必须使用 new 或在您的情况下使用 new[] 动态分配内存。

首先,您需要将数据类型更改为char**,与之前的几乎相同。然后你可以像nicknames = new char*[number_of_nicknames]这样分配尽可能多的字符串。

重要的是,使用这种方法,您必须像这样手动删除您的昵称:delete[] nicknames;。最好的方法是使用 RAII(在你的解构器中删除你的昵称)

当您有动态字符串时,您将使用以下结构

struct widget_t {
    // optional constructor to allocate nicknames

    ~widget_t()
    {
        for (int i = 0; i < numberOfNicknames; ++i)
        {
            char* nickname = nicknames[i];

            if (nickname)
                delete[] nickname;
        }

        delete[] nicknames;
    }

    char *name;
    uint8_t numberOfNicknames;
    char **nicknames = NULL;
};

下一个是常量字符串

struct widget_t {
    // optional constructor to allocate nicknames
    // allocate nicknames like
    // -> nicknames = new const char*[numberOfNicknames];

    ~widget_t()
    {
         if (nicknames) delete[] nicknames;
    }

    char *name;
    uint8_t numberOfNicknames;
    const char **nicknames = NULL;
};

【讨论】:

  • @duong_dajgja 已更改,我认为 RAII 将适合此目的。
  • 注意:这不是 VLA,而是不完整的类型。它们是 C 中不同的动物和不同的语义。但两者都没有被 C++ 标准指定......
【解决方案2】:

一种选择是:

struct widget_t {
    char const *name;
    uint8_t numberOfNicknames;
    char const * const *nicknames;
};

static char const *mower_nicknames[] = { "Choppie", "Bob" };
widget_t SomeWidget = { "Lawn Mower", 2, mower_nicknames };

static char const *bus_nicknames[] = { "Wheels", "Go", "Round" };
widget_t OtherWidget = { "Bus", 3, bus_nicknames };

// no setup function needed

【讨论】:

    【解决方案3】:

    您要做的是将字符串文字分配给char * 指针——这很糟糕(在How to get rid of deprecated conversion from string constant to ‘char*’ warnings in GCC? 上查看更多信息)。这是一种可能的方法:

    #define MAX_NAME_LEN 128
    #define MAX_NICK_NAMES 10
    
    struct widget_t {
        char name[MAX_NAME_LEN];
        uint8_t numberOfNicknames;
        char nicknames[MAX_NICK_NAMES][MAX_NAME_LEN];
    };
    
    widget_t SomeWidget;
    
    void setUpFunction () {
        strcpy(SomeWidget.name, "Lawn Mower");
        SomeWidget.numberOfNicknames = 2;
        strcpy(SomeWidget.nicknames[0], "Choppie McGrasschopper");
        strcpy(SomeWidget.nicknames[1], "Really Noisy");
    }
    

    无论如何,既然您用C++ 标记您的问题,我建议您改用std::stringstd::vector

    【讨论】:

    • 他还用 arduino 标记了他的答案,所以你的最后一个建议是不可能的。
    • @Phins 有 arduino 的 STL 端口。
    • @DanM.but 不是一个好的选择arduino.stackexchange.com/questions/24790/…,STL 针对不同的平台进行了优化。
    【解决方案4】:

    这里有不同的问题。

    首先你的最后一个成员是不完整类型的,因为它是一个未声明维度的数组。这在 C++ 中是不允许的,但大多数编译器允许它作为与 C 具有相同语义的扩展。无论如何,这使用起来相当棘手,因为它只能与分配的结构一起使用,在那里你为结构本身分配内存 不完整的数组。

    接下来,您尝试分配 到一个数组。你不能。数组不是 C++(也不是 C)中的第一类对象。可以将数组作为一个整体进行初始化,但只能赋值给数组元素。

    最后,您将 C 文字字符串分配给 char *。这很糟糕,因为标准声明文字字符串为const,因此稍后使用指针更改字符将是未定义的行为。如果你不这样做,它会起作用,但指针至少应该声明为const

    以下是您可以使用所有这些的方法:

    widget_t* setUpFunction () {
        // allocates a widget_t with 2 slots in nicknames
        widget_t *someWidget = (widget_t *) malloc(sizeof(widget_t) + 2 * sizeof(char *));
        someWidget.name = (char *)"Lawn Mower";   // VERY DANGEROUS: pointer should be const
        someWidget.numberOfNicknames = 2;
        someWidget.nicknames[0] = (char *) "Choppie McGrasschopper"; // SAME DANGER
        someWidget.nicknames[1] = (char *) "Really Noisy"            // Still same danger
        return widget_t;
    }
    

    但所有这些都是 C 风格的,应该在 C++ 中避免。此外,它仍然需要分配内存,这可能不是您想要的 Arduino

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-11-10
      • 1970-01-01
      • 2017-07-02
      • 1970-01-01
      • 1970-01-01
      • 2016-09-18
      • 2016-09-12
      相关资源
      最近更新 更多