• Advertisement
Sign in to follow this  

Empty Array In Structures

This topic is 1449 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hey there. I wanna be able to have some way of being able to use an empty array inside a structure to be reinitialized later on. The reason why is cause it will have an unknown number of elements until a file is loaded, and then I can reinitialize the array to an appropriate size and start storing data. The only thing I can think of for a solution since in C++ you cant have empty arrays in structures is to make a pointer to a variable in the structure:

#include <iostream>
using namespace std;

struct Test_Structure
{
     unsigned char *myarray;
};

Test_Structure test;

int main()
{
	unsigned char some_other_array[10];
	test.myarray = new unsigned char[10];
	cout << "test.myarray: " << sizeof(test.myarray) << endl;
	cout << "some_other_array: " << sizeof(some_other_array) << endl;
	system("pause");
	return 0;
}

However if you were to run that, it only shows the size of the pointer rather than the whole array. Can I still the pointer as an array? Or is there another way around using empty arrays from structures?

Share this post


Link to post
Share on other sites
Advertisement

You can have an empty array at the end of a structure like:

struct Test_Structure {
   const int32_t some_data_0;
   const uint32_t array_of_some_sort[];
};
I find these can be useful when using memory mapped files.  In many file formats you'll have a header to a block of data, and then a variable number of some item following the header.  These sorts of trailing empty arrays can make traversing the files very easy I found.  These sorts of things are good when the memory is allocated through some other means.  As Hodgman pointed out, if you intend to allocate the memory your self, use a std::vector or similar container.

 

I would take note that const makes you unable to change the data of this structure, so it would need to be initialized in a constructor initializer list, and also that uint32_t array[] is equal to typing uint32_t* array, but the latter makes it a bit more clear as to what the variable is: a pointer, as there's no such thing as an empty array in C++. Using such a construct is fine in C, but it'd personally avoid it in C++, considering there's a safe way to do it which avoids accidental memory leaks.

I failed at reading the specific use case, as is explained in later posts, which now makes sense to me. Learn something new everyday!

Edited by Strewya

Share this post


Link to post
Share on other sites
Ryan_001 already explicitly stated his use case for these structs (namely when working on data provided through memory mapped files). In this context, const makes a lot of sense.

I'd also like to point out that an open array and a pointer are not the same thing. The open array once again works perfectly for his use case, a pointer would not work at all.

Share this post


Link to post
Share on other sites

You can have an empty array at the end of a structure like:

struct Test_Structure {
   const int32_t some_data_0;
   const uint32_t array_of_some_sort[];
};
I find these can be useful when using memory mapped files.  In many file formats you'll have a header to a block of data, and then a variable number of some item following the header.  These sorts of trailing empty arrays can make traversing the files very easy I found.  These sorts of things are good when the memory is allocated through some other means.  As Hodgman pointed out, if you intend to allocate the memory your self, use a std::vector or similar container.

 

Yep. I'm using this frequently in resource management, rendering jobs, and similar tasks, because at that level things are just blobs with a specific header. Only certain sub-systems are able to interpret the blob correctly.

Share this post


Link to post
Share on other sites

Thanks for the solutions. I tried using vector but theres a problem. If you use a variable declared from vector, you wont be able to use that variable to extract data from a file because you cant convert a vector(unsigned char) to (char *). I am using ifstream file and file.read to get the data.

Edited by Psychopathetica

Share this post


Link to post
Share on other sites

you could first get the filesize, then preallocate enough space in the vector and push back chunks of the file that you read into a temporary buffer.

 

Edit: Because I haven't programmed in c++ for a while and your problem has piqued my interest. Here is the shortest form I think:

//... constructed before
std::vector<char> content();

//...load data
std::ifstream inputFile("input.dat", std::ios::binary);
content.assign(std::istreambuf_iterator<char>(inputFile)), std::istreambuf_iterator<char>());
Edited by Madhed

Share this post


Link to post
Share on other sites

Thanks for the solutions. I tried using vector but theres a problem. If you use a variable declared from vector, you wont be able to use that variable to extract data from a file because you cant convert a vector(unsigned char) to (char *). I am using ifstream file and file.read to get the data.

Vec.resize(fileSize);
char* buffer = (char*)&Vec[0]

Share this post


Link to post
Share on other sites

Or the long overdue C++11 way:

 

char* buffer = Vec.data();

 

edit: okay, char to unsigned char means not getting rid of the cast. Which means being torn between the "proper" way of the ugly static_cast<char>() or the "evil" easy C-style cast (char*).

Edited by Trienco

Share this post


Link to post
Share on other sites

Such a royal pain to comprehend on why something so simple can be so cryptic. Back when I was learning VB6 14 years ago, doing empty arrays in structures to be redeclared later wasnt so hard:

Private Type MyStruct
     MyArray() As Byte
End Type

Dim Test As MyStruct

Private Sub Form_Load()
     ReDim Test.MyArray(10) As Byte
End Sub

Even with VB.Net theres no issue:

Public Class Form1

    Private Structure MyStruct
        Dim MyArray() As Byte
    End Structure

    Dim Test As MyStruct

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        ReDim Test.MyArray(10)
    End Sub
End Class

And although itll work in C++ to use a pointer and make it an array later (I think), I still kinda find it funny that you have to go through including the library vector, using vector<your data type here>, Resizing the vector, store the address of the vector into a pointer buffer to be used as an array by static_casting<char *>, load the data into that buffer and possibly put it back into the vector array. Mega fail Microsoft on not keeping it simple.

Share this post


Link to post
Share on other sites

And although itll work in C++ to use a pointer and make it an array later (I think), I still kinda find it funny that you have to go through including the library vector, using vector<your data type here>, Resizing the vector, store the address of the vector into a pointer buffer to be used as an array by static_casting<char *>, load the data into that buffer and possibly put it back into the vector array. Mega fail Microsoft on not keeping it simple.


The point of the vector is to simplify memory management. As Ryan_001 already pointed out, if existing memory just needs to be interpreted in that specific way an empty array works and is simple.

Furthermore, std::vector has absolutely nothing to do with Microsoft or Windows. It's a part of the C++ standard library. It exists on Linux, Macs and smartphones and every other platform with a C++ compiler in the same way.

Share this post


Link to post
Share on other sites

Such a royal pain to comprehend on why something so simple can be so cryptic. Back when I was learning VB6 14 years ago, doing empty arrays in structures to be redeclared later wasnt so hard:

Private Type MyStruct
     MyArray() As Byte
End Type

Dim Test As MyStruct

Private Sub Form_Load()
     ReDim Test.MyArray(10) As Byte
End Sub
Even with VB.Net theres no issue:
Public Class Form1

    Private Structure MyStruct
        Dim MyArray() As Byte
    End Structure

    Dim Test As MyStruct

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        ReDim Test.MyArray(10)
    End Sub
End Class

And although itll work in C++ to use a pointer and make it an array later (I think), I still kinda find it funny that you have to go through including the library vector, using vector<your data type here>, Resizing the vector, store the address of the vector into a pointer buffer to be used as an array by static_casting<char *>, load the data into that buffer and possibly put it back into the vector array. Mega fail Microsoft on not keeping it simple.

 
Ya C++ is funny like that.  Simple stuff tends to be harder than it should.  There's two main problems I personally run into a lot when working with files in C++.
 
The 1st is that the fundamental types are poorly defined.  Short can be 16 bits, or 32, 1024, who knows, a char might be 8 bits or might be 9000.  Which is why I always use the <cstdint> header and types when working with files or networking.  You can't be sure unsigned char is what you want, but you can be sure that a uint8_t is.
 
The second is that I'm not a fan of the C++ stream model.  I use it when necessary, but find it unnecessarily cumbersome.  I wrote a small wrapper around the Win32 file mapping routines and haven't looked back since.  Far cleaner, faster, easier to use, and easier to make bug free code.  That said its not portable so I understand its not a solution for everyone.  To my knowledge boost also has a memory mapping library, but I've never used it so I can't comment on it. Edited by Ryan_001

Share this post


Link to post
Share on other sites

The second is that I'm not a fan of the C++ stream model.

I've been using C++ professionally for over a decade and have never seen the standard stream library in use. I've only ever used it as part of "hello world" learning exercises biggrin.png

I still kinda find it funny that you have to go through including the library vector, using vector, Resizing the vector, store the address of the vector into a pointer buffer to be used as an array by static_casting, load the data into that buffer and possibly put it back into the vector array.

C/C++ are systems programming languages, that only make the computer do exactly what you tell it to do. C was originally designed to be a "portable assembly language" -- i.e. a language that translates almost directly down to native machine instructions.
 
If you want to use simpler abstractions (rather than being extremely verbose and precise in your code), then yes, a higher level language like VB is a far better choice for you. C/C++ are for solving a different class of problems than VB, and are designed accordingly.

Share this post


Link to post
Share on other sites

 

The second is that I'm not a fan of the C++ stream model.

I've been using C++ professionally for over a decade and have never seen the standard stream library in use. I've only ever used it as part of "hello world" learning exercises biggrin.png

I still kinda find it funny that you have to go through including the library vector, using vector, Resizing the vector, store the address of the vector into a pointer buffer to be used as an array by static_casting, load the data into that buffer and possibly put it back into the vector array.

C/C++ are systems programming languages, that only make the computer do exactly what you tell it to do. C was originally designed to be a "portable assembly language" -- i.e. a language that translates almost directly down to native machine instructions.
 
If you want to use simpler abstractions (rather than being extremely verbose and precise in your code), then yes, a higher level language like VB is a far better choice for you. C/C++ are for solving a different class of problems than VB, and are designed accordingly.

 

 

What do you use for I/O in C++ then?  Do you have a go-to portable library, or do you just use something developed in house?

Share this post


Link to post
Share on other sites

What do you use for I/O in C++ then? Do you have a go-to portable library, or do you just use something developed in house?

It has been my experience over the last 3 decades that most C++ code is C-with-classes written by C programmers, and more recently by Java programmers. There is a lot of printf()-style stream formatting used in production code.

Part of this is because <iostream> is a string formatting library (not an I/O library), and most production applications these days are either GUI or server so most string formatting is for logging purposes, and the NIH syndrome is particularly apparent in the realm of logging. Most Reuleaux loggers I've seen are either reimplementations of the standard Java classes or wrappers around the standard C calls. There's no reason why the C++ streams can't be used directly for these purposes without great success, other than the prejudice of the developers.

Another reason is that the C++ formatting streams support internationalization only with great difficulty. Most solutions for that serious functional deficit end up looking remarkably like printf (or even Fortran) with formatting strings. A solution like the Boost solution (a localizable format string injected into the iostream but the standard streambufs and operator<<()/operator>>() overloads are used) is the best of both worlds.

Share this post


Link to post
Share on other sites

Or the long overdue C++11 way:
 
char* buffer = Vec.data();
 

 

Nice, learned something new today.

Edited by Madhed

Share this post


Link to post
Share on other sites

Well I just figured out how to load data from a file and store it into a vector declared array that is from a structure:

File.read(reinterpret_cast<char *>(Test.Myarray.data()), Test.Myarray.size());

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement