Spook
Spook

Reputation: 25929

How to initialize nested array of structs in C++?

I have the following definitions:

struct Display_font_char 
{
    unsigned char * data;
    int originX;
    int originY;
    unsigned int width;
    unsigned int height;
    unsigned int delta;
};

struct Display_font 
{
    Display_font_char * chars;
    unsigned char rangeStart;
    unsigned char rangeEnd;
};

How can I initialize it inplace? I'm trying:

const Display_font font = 
{
    {
        {
            { 1, 2, 3 },
            1,
            2,
            3u,
            4u,
            5u
        }
    },
    1u,
    2u
}

However, I'm getting an error: "Cannot use value of type int to initialize field of type Display_font_char *"

Upvotes: 0

Views: 97

Answers (2)

rturrado
rturrado

Reputation: 8074

In order to initialize your pointers, you have to create the pointed structures first, for example using new.

Notice that, if you want to treat Display_font.chars and Display_font_char.data as arrays, you should save their sizes (e.g. through a size_t data_size member).

In the example below I create the arrays with new[] and I delete them later on with delete[].

[Demo]

#include <iostream>  // cout
#include <ostream>

struct Display_font_char 
{
    unsigned char* data;
    size_t data_size;
    int originX;
    int originY;
    unsigned int width;
    unsigned int height;
    unsigned int delta;
};
std::ostream& operator<<(std::ostream& os, const Display_font_char& f)
{
    os << "\tdata = [";
    for (size_t i{0}; i < f.data_size; ++i)
    {
        os << ((i == 0) ? "" : ", ") << static_cast<int>(f.data[i]);
    }
    os << "]\n";
    os << "\toriginX = " << f.originX << "\n";
    os << "\toriginY = " << f.originY << "\n";
    os << "\twidth = " << f.width << "\n";
    os << "\theight = " << f.height << "\n";
    os << "\tdelta = " << f.delta << "\n";
    return os;
}

struct Display_font 
{
    Display_font_char* chars;
    size_t chars_size;
    unsigned char rangeStart;
    unsigned char rangeEnd;
};
std::ostream& operator<<(std::ostream& os, const Display_font& f)
{
    os << "chars = [\n";
    for (size_t i{0}; i < f.chars_size; ++i)
    {
        os << ((i == 0) ? "" : ", ") << f.chars[i];
    }
    os << "]\n";
    os << "rangeStart = " << static_cast<int>(f.rangeStart) << "\n";
    os << "rangeEnd = " << static_cast<int>(f.rangeEnd) << "\n";
    return os;
}

int main()
{
    const Display_font font = {
        new Display_font_char[1]{
            new unsigned char[4]{1, 2, 3},
            3,  // data size
            1, 2,
            3u, 4u, 5u
        },
        1,  // chars size
        1, 2
    };
    std::cout << font;
    delete[] font.chars[0].data;
    delete[] font.chars;
}

This other version uses std::vector instead of Display_font_char* and unsigned char*, so you don't have to do care about memory allocations/deallocations.

[Demo]

#include <iostream>  // cout
#include <ostream>
#include <vector>

struct Display_font_char
{
    std::vector<unsigned char> data;
    int originX;
    int originY;
    unsigned int width;
    unsigned int height;
    unsigned int delta;
};
std::ostream& operator<<(std::ostream& os, const Display_font_char& f)
{
    os << "\tdata = [";
    bool first{true};
    for (auto& d : f.data)
    {
        os << (first ? "" : ", ") << static_cast<int>(d);
        first = false;
    }
    os << "]\n";
    os << "\toriginX = " << f.originX << "\n";
    os << "\toriginY = " << f.originY << "\n";
    os << "\twidth = " << f.width << "\n";
    os << "\theight = " << f.height << "\n";
    os << "\tdelta = " << f.delta << "\n";
    return os;
}

struct Display_font 
{
    std::vector<Display_font_char> chars;
    unsigned char rangeStart;
    unsigned char rangeEnd;

};
std::ostream& operator<<(std::ostream& os, const Display_font& f)
{
    os << "chars = [\n";
    bool first{true};
    for (auto& c : f.chars)
    {
        os << (first ? "" : ", ") << c;
        first = false;
    }
    os << "]\n";
    os << "trangeStart = " << static_cast<int>(f.rangeStart) << "\n";
    os << "rangeEnd = " << static_cast<int>(f.rangeEnd) << "\n";
    return os;
}

int main()
{
    const Display_font font{
        { { {1, 2, 3}, 1, 2, 3u, 4u, 5u } },
        1,
        2
    };
    std::cout << font;
}

Upvotes: 1

eerorika
eerorika

Reputation: 238461

You cannot initialise a pointer with a braced init list of multiple values.

Here is an example of how you could initialise an instance of the class:

unsigned char uc[] = { 1, 2, 3 };
Display_font_char fc {
    uc,
    1,
    2,
    3u,
    4u,
    5u,
};
const Display_font font = 
{
    &fc,
    1u,
    2u,
};

As a sidenote, if you were to switch to C, then you could use compound literals:

const struct Display_font font = 
{
    &(struct Display_font_char){
        (unsigned char []){ 1, 2, 3 },
        1,
        2,
        3u,
        4u,
        5u
    },
    1u,
    2u
};

But alas, compound literals don't exist in C++.

Upvotes: 1

Related Questions