C ++在指向结构的指针中设置数组

时间:2014-07-28 23:29:27

标签: c++ arrays struct

我在C ++中有一个结构如下:

typedef struct DIFDict
{
    std::string name;
    std::string defs[];
    struct DIFColor *colors[];
    uint8_t defsize; 
} DIFDict;

问题在于尝试初始化它。我有一个函数,它返回一个指向结构的指针,其中所有值都已初始化:

struct DIFDict *CreateDIFDict(std::string n, std::string *d, struct DIFColor **c, uint8_t de)
{
    int memsize = sizeof(n) + sizeof(d) + sizeof(c) + sizeof(de);
    struct DIFDict *i = static_cast<struct DIFDict*>(malloc(memsize));

    if(i != NULL)
    {
        i->name = n;
        i->defs = d;
        i->colors = c;
        i->defsize = de;
    }

    return i;

}

然而,编译器抱怨类型不匹配:

error: incompatible types in assignment of 'std::string {aka std::basic_string<char>}' to 'std::string [0] {aka std::basic_string<char> [0]}'
error: incompatible types in assignment of 'DIFColor**' to 'DIFColor* [0]'

我是否误解了指针和数组之间的关系?

3 个答案:

答案 0 :(得分:2)

typedef struct DIFDict
{
    std::string name;
    std::string *defs;
    struct DIFColor **colors;
    uint8_t defsize; 
} DIFDict;

struct DIFDict *CreateDIFDict(std::string n, std::string *d, struct DIFColor *c, uint8_t de)
{   
    DIFDict *i = 0;
    i = new DIFDict;

    if(i != 0)
    {
        i->name = n;
        i->defs = d;
        i->colors = &c;
        i->defsize = de;

        return i;
    }

    return 0;
}

编辑:上面答案的问题是DIFColor参数是临时的,当函数退出时,指向临时的指针将无效。一个更加可行的(不是最好的,但至少是可行的)解决方案与上述内容密切相关,如下所示:

    struct DIFDict
    {
        std::string name;
        std::string *defs;
        DIFColor **colors;
        uint8_t defsize; 
    };

    DIFDict *CreateDIFDict(const std::string& n, std::string *d, 
                           DIFColor **c, uint8_t de) 
    {   
        DIFDict *i = new DIFDict;
        i->name = n;
        i->defs = d;
        i->colors = c;
        i->defsize = de;
        return i;
    }

请注意,我们现在不接受临时的地址 - 我们直接传递指针值并分配它。另请注意,new在失败时不返回0(除非使用nothrow选项),因此new为0时不需要检查。

然而,这个解决方案仍然是类似C的并且容易出错,并且有更好的方法,如其他答案所述。

答案 1 :(得分:2)

你似乎对C ++中的数组有一些基本的误解。它们具有固定的大小,在编译时已知。零大小的数组是非法的。 (有些编译器在标准模式下不调用时允许使用零大小的数组,但是它们的语义不清楚,当然也不能存储任何值。)

您也错误地使用sizeofsizeof x告诉您存储x需要多少字节。 (x可能指向的任何内容,如果x是指针,而不是x是句柄或容器类的任何内容。例如,std::string是一个容器,其指针指向动态分配的字符串内容。 sizeof name只能获取容器大小,它不会为您提供动态分配的空间。

在您的代码中,memsize可以在编译时确定;对函数的不同调用永远不会有所不同。

此外,使用函数CreateDIFDict的风格很差,因为它强制动态分配。相反,提供一个构造函数。然后用户可以选择是否需要动态分配,并且可以利用移动和复制语义。

目前尚不清楚您是否希望DIFDict获取正在初始化它的字符串和DIFColors的副本。如果您不想要副本:

struct DIFDict
{
    std::string name;
    std::string *defs;
    struct DIFColor **colors;
    uint8_t defsize; 

    DIFDict(std::string name, std::string *defs, struct DIFColor **colors, uint8_t defsize) :
         name(name), defs(defs), colors(colors), defsize(defsize) {}
};

确保在销毁指针所指向的内容之前销毁所有DIFDict s。 (原始指针在C ++中没有所有权语义)。

如果您确实需要副本:

struct DIFDict
{ 
    std::string name;
    std::vector<std::string> defs;    // or some other container
    // ??? colors

    DIFDict(std::string name, std::string const *p_defs, uint8_t defsize)
         : name(name), defs(p_defs, p_defs + defsize) {}
};

我不确定colors应该指向什么,如果您提供有关颜色的预期行为的更多信息,我将更新此示例。

答案 2 :(得分:1)

这是C ++,而不是C.删除typedef并像对待类一样初始化它。 structclass之间的唯一区别是成员的默认可见性。类似的东西:

struct DIFDict
{
    string name;
    vector<string> defs;
    DIFColor* colors;
    uint8_t defsize; 

    DIFDict();
    ~DIFDict();    
};

DIFDict::DIFDict : name(""), defs(...), colors(...), defsize(0) {}
DIFDict::~DIFDict() {...}

正如0x499602D2指出的那样,您应该为数组使用vector

省略号意味着创建一个帮助程序来初始化成员。帮助器应确保构造函数在异常期间按预期运行。