1

Lets say i store headers in some file, but some part of the header is dynamic length, something like this it would look:

struct HeaderTest {
    int someparam;
    int more;
    int arrsize;      // how big array, read arrsize elements into arr:
    int arr[arrsize]; // not valid
};

Is there some elegant way for reading dynamic data into a struct?

Newbie
  • 1,143
  • 5
  • 20
  • 30

5 Answers5

6

Instead of having arr and arrsize variables in your struct, you can define your struct like this:

struct HeaderTest 
{
    int someparam;
    int more;
    std::vector<int> data;
}

No arr, no arrsize. Just use std::vector, and std::vector::size(). That is elegant!

And if you want to read binary data from a file, then you can write like this:

struct HeaderTest 
{
    int someparam;
    int more;
    int size;
    char *data;
}

Otherwise, go with the first struct!


An Advice:

Reading your comments everywhere, I feel that I should suggest you to get a good book, and study it first. Here is list of really good books:

The Definitive C++ Book Guide and List

Community
  • 1
  • 1
Nawaz
  • 353,942
  • 115
  • 666
  • 851
  • 1
    how do you read the file data into that struct if you dont know the length of the data? – Newbie Jan 16 '11 at 20:15
  • @Newbie: you can read file data, and push_back into the vector like this : `data.push_back(file_data_int)`. – Nawaz Jan 16 '11 at 20:19
  • 2
    @Chris: of course you can. Maybe not directly via `operator >>` but using a binary serializer, sure, why not? – Konrad Rudolph Jan 16 '11 at 20:26
  • 1
    @Chris - WHAT? What made you think that?? – Edward Strange Jan 16 '11 at 20:35
  • 1. adding a pointer to the struct is worse as you can't write those out to disk. 2. the format written by a binary serializer seems flaky as I don't believe theres a real expectation that a different implementation of the STL would be able to read the data. Its not just an int array. – Chris Becke Jan 16 '11 at 20:40
  • @Chris: why can't I write data pointed to by a pointer to the disk? – Nawaz Jan 16 '11 at 20:44
  • @Nawaz: yes, i do that already... but i was hoping i dont need to do that, some way to automate it, so i would have to write a struct or etc, and then just call fread() and it would do everything for me with the vectors etc. atm i have splitted the reading method into several lines, and it feels kinda crappy way. – Newbie Jan 16 '11 at 22:32
2

Well, if you don't want to use a container class (not sure why you wouldn't) you can declare arr as a pointer to int and leave it to the client to initialize the pointer to a valid memory location as well as correctly initialize arrsize.

That said, you should just use a vector. Why make things more difficult than they need to be?

Ed S.
  • 122,712
  • 22
  • 185
  • 265
1

This answer is more C than C++, but, you can easily make use of realloc() to resize a buffer to be as large as you need it. As demonstrated in this pseudo code.

struct HeaderTest {
  int someparam;
  int more;
  int arrsize;
  int arr[];
};

HeaderTest* pkt = (HeaderTest*)malloc(sizeof(HeaderTest));
read(&pkt,sizeof(pkt));
pkt = (HeaderTest*)realloc(pkt,sizeof(HeaderTest)+sizeof(pkt->arr[0])*pkt->arrsize);
read(pkt->arr,sizeof(int)*pkt->arrsize);
Chris Becke
  • 34,244
  • 12
  • 79
  • 148
0

I don't think there is a very elegant way. You should probably make that dynamic member a pointer, then read all other members first, allocate memory for the last one, and then read the remainder of the data.

Since you're in C++, you can nicely encapsulate this in a class so that you don't have to worry about this detail in your code anymore. Also, as other have said, a std::vector would be a more C++-like approach than a simple pointer and manually allocated memory. It would also be more resistant to memory leaks.

Vilx-
  • 104,512
  • 87
  • 279
  • 422
  • "you can nicely encapsulate this in a class", i dont know what you mean, but do you mean i could somehow with 1 line of code read the header and it would automatically allocate the vector for arrsize elements and read the elements there? and this would work for other structs too (with little or no work) ? can you show some example if this class method? – Newbie Jan 16 '11 at 20:25
  • by one line i mean some method that doesnt force me to split my reader function manually for every struct. I was thinking if theres some way to just write struct and then call fread() and it would do all the necessary allocations and my struct would be ready to use. – Newbie Jan 16 '11 at 22:37
  • @Newbie - Sorry, there is no such option. But you can write a function that performs all the necessary allocations/calculations, and returns a pointer to a ready struct. Alternatively, as I've suggested, you could give your struct/class a constructor which does all the reading and stores the data in class members. The rest of your code would only interact with this class, not the file directly. – Vilx- Jan 17 '11 at 00:04
0

No one was able to give you the solution you wanted, but I have devised it for you. This function takes a C-string filename, opens the file and reads the contents for you. It returns an int*, which can be assigned to t.container. Enjoy.

int* read(char* filename)
{
    // open file
    ifstream f;
    f.open(filename, ios::binary);
    // get file size
    f.seekg (0, ios::end);
    int length = f.tellg();
    f.seekg (0, ios::beg);
    // allocate new int*
    length = (length -(sizeof(int)*2)) / sizeof(int);
    int* buf = new int[length];
    for(int i = 0; i < length; ++i)
    {
        // create byte array to hold bytes
        unsigned char* temp = new char[sizeof(int)];
        stream.read((char*)temp, sizeof(int));
        // convert byte array to int
        for(int j = 0; j < sizeof(int); ++j)
        {
            buf[i] = buf[i] + (temp[j] << (j*8));
        }
        delete[] temp;
    }
    f.close();
    return buf;
}
Charles Ray
  • 470
  • 1
  • 5
  • 16