Jump to content

  • Log In with Google      Sign In   
  • Create Account


Empty Array In Structures


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
19 replies to this topic

#1 Psychopathetica   Members   -  Reputation: 186

Like
1Likes
Like

Posted 27 January 2014 - 11:41 PM

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?



Sponsor:

#2 Hodgman   Moderators   -  Reputation: 28582

Like
12Likes
Like

Posted 28 January 2014 - 12:05 AM

The solution in C++ is to use std::vector instead of raw-arrays.

#include <iostream>
#include <vector>
using namespace std;

struct Test_Structure
{
     vector<unsigned char> myarray;
};

Test_Structure test;

int main()
{
	vector<unsigned char> some_other_array(10);
	test.myarray.resize(10);
	cout << "test.myarray: " << test.myarray.size() << endl;
	cout << "some_other_array: " << some_other_array.size() << endl;
	system("pause");
	return 0;
}

Alternatively, you need to remember the size of the allocation in a variable yourself:

#include <iostream>
using namespace std;

struct Test_Structure
{
     unsigned char *myarray;
     int size;
};

Test_Structure test;

int main()
{
	unsigned char some_other_array[10];
	test.myarray = new unsigned char[10];
	test.size = 10;
	cout << "test.myarray: " << test.size << endl;
	cout << "some_other_array: " << sizeof(some_other_array) << endl;
	delete [] test.myarray;//don't leak memory
	system("pause");
	return 0;
}


#3 Ryan_001   Prime Members   -  Reputation: 1304

Like
6Likes
Like

Posted 28 January 2014 - 04:57 AM

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.

Edited by Ryan_001, 28 January 2014 - 04:58 AM.


#4 Strewya   Members   -  Reputation: 1331

Like
-2Likes
Like

Posted 28 January 2014 - 06:19 AM

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, 28 January 2014 - 11:21 AM.

devstropo.blogspot.com - Random stuff about my gamedev hobby


#5 BitMaster   Crossbones+   -  Reputation: 3784

Like
2Likes
Like

Posted 28 January 2014 - 06:51 AM

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.

#6 haegarr   Crossbones+   -  Reputation: 3958

Like
0Likes
Like

Posted 28 January 2014 - 07:20 AM

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.



#7 Psychopathetica   Members   -  Reputation: 186

Like
0Likes
Like

Posted 28 January 2014 - 02:57 PM

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, 28 January 2014 - 02:58 PM.


#8 Madhed   Crossbones+   -  Reputation: 2685

Like
0Likes
Like

Posted 28 January 2014 - 03:13 PM

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, 28 January 2014 - 03:36 PM.


#9 Hodgman   Moderators   -  Reputation: 28582

Like
3Likes
Like

Posted 28 January 2014 - 03:36 PM

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]

#10 Trienco   Crossbones+   -  Reputation: 2085

Like
3Likes
Like

Posted 28 January 2014 - 11:03 PM

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, 28 January 2014 - 11:08 PM.

f@dzhttp://festini.device-zero.de

#11 Psychopathetica   Members   -  Reputation: 186

Like
-4Likes
Like

Posted 28 January 2014 - 11:52 PM

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.



#12 BitMaster   Crossbones+   -  Reputation: 3784

Like
1Likes
Like

Posted 29 January 2014 - 01:39 AM

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.

#13 Ryan_001   Prime Members   -  Reputation: 1304

Like
0Likes
Like

Posted 29 January 2014 - 06:43 AM

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, 29 January 2014 - 06:44 AM.


#14 TheComet   Members   -  Reputation: 1459

Like
0Likes
Like

Posted 29 January 2014 - 06:57 AM

The C++ standard does not specify the size of integral types in bytes, but it specifies minimum ranges they must be able to hold.

http://stackoverflow.com/questions/589575/size-of-int-long-etc


YOUR_OPINION >/dev/null


#15 Hodgman   Moderators   -  Reputation: 28582

Like
3Likes
Like

Posted 29 January 2014 - 07:01 AM

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.



#16 Ryan_001   Prime Members   -  Reputation: 1304

Like
0Likes
Like

Posted 29 January 2014 - 07:50 AM

 

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?



#17 Bregma   Crossbones+   -  Reputation: 4848

Like
3Likes
Like

Posted 29 January 2014 - 08:31 AM

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.
Stephen M. Webb
Professional Free Software Developer

#18 Madhed   Crossbones+   -  Reputation: 2685

Like
0Likes
Like

Posted 29 January 2014 - 03:07 PM


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

 

Nice, learned something new today.


Edited by Madhed, 29 January 2014 - 03:15 PM.


#19 Psychopathetica   Members   -  Reputation: 186

Like
0Likes
Like

Posted 29 January 2014 - 05:50 PM

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());


#20 Servant of the Lord   Crossbones+   -  Reputation: 18109

Like
0Likes
Like

Posted 30 January 2014 - 06:06 PM

Alternatively, if not using C++11 and you don't have data(), you can do: &myVector[0]


It's perfectly fine to abbreviate my username to 'Servant' rather than copy+pasting it all the time.

[Fly with me on Twitter] [Google+] [My broken website]

All glory be to the Man at the right hand... On David's throne the King will reign, and the Government will rest upon His shoulders. All the earth will see the salvation of God.                                                                                                                                                            [Need web hosting? I personally like A Small Orange]
Of Stranger Flames - [indie turn-based rpg set in a para-historical French colony] | Indie RPG development journal





Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS