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?
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
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?
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);
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.
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;
}
Related
I have an array of bytes that I want to change how it's accessed. Here's the array:
char bytes[100];
I want to have another array that changes how the original array is accessed. If we could put references in array, it would look something like this:
char& bytes_ref[50];
for(size_t i = 0; i < 50; i++){
bytes_ref[i] = bytes[i * 2];
}
Though array of references aren't valid. I came up with this that in theory does what I want:
#include <iostream>
struct Byte {
char* ref;
Byte(){}
Byte(char& c){
ref = &c;
}
operator char&() const {
return *ref;
}
};
int main(){
char bytes[100];
Byte bytes_ref[50];
for(size_t i = 0; i < 50; i++){
bytes_ref[i] = bytes[i * 2];
}
}
Though this works like I want it to, it takes up a ton of space.
Is there some way to do this without using up 7 more bytes per entry? My instinct is no, but I'm hopeful there may be some kind of special functionality in C++ that could do this, or maybe do some direct memory manipulation and access.
The reason I want to do this is I have an array of bytes that represent an image in NV21 format. I want to create a separate array that references the bytes in the original buffer but takes half the pixels, effectively resizing the image on the fly.
I have to pass a char** to an uncontrolled library.
Thanks in advance!
I do not think you can use less memory than one pointer per element
If you need to pass an array of char* to an uncontrolled library, I understand that you have to allocate the whole array because that is what the library is expecting. The code would like:
std::array<char*, 50> bytes_ref;
for(size_t i = 0; i < bytes_ref.size(); ++i){
bytes_ref[i] = &bytes[i * 2];
}
Then, you can pass the array as:
f(bytes_ref.data());
If you would not need to use char**, you would have more options. You may use std::reference_wrapper although its size is similar to a pointer. If you always have to skip 2 elements, you may create an object for this. For example:
class Wrapper {
public:
Wrapper(char *origin) : m_origin(origin) {}
char* operator[](size_t index) {return m_origin + 2*index;}
private:
char *m_origin;
};
The above will return a pointer to every 2 elements using the [] operator.
I am trying to read from a file and put each new line/entry in to an array. However, I am more primarily familiar with C# and C++ isn't my thing. The reason I need to do this is for a project and I am the only one that is willing to do this part.
I do not know how to properly convert character types or if it is possible. I have tried searching around the internet but have not found any answers regarding something like my issue here. Also, because I do not know what causes an illegal sizeof operand I do not know what is wrong here.
#include "..\STDInclude.h"
// TODO: Fill that list with names
char* Bots::NameList[] = {};
void Bots::GetNames()
{
using namespace std;
ifstream file("bot_names.txt");
if (file.is_open())
{
for (int i = 0; i < 48; i++)
{
file >> Bots::NameList[i];
}
}
}
void Bots::Initialize()
{
// Replace staff array with custom one
*(char***)Addresses::BotArray1 = Bots::NameList;
*(char***)Addresses::BotArray2 = Bots::NameList;
*(char***)Addresses::BotArray3 = Bots::NameList;
// Apply new array size
int size = (sizeof(Bots::NameList) / sizeof(Bots::NameList[0]));
*(BYTE*)Addresses::BotArraySize1 = size;
*(BYTE*)Addresses::BotArraySize2 = size;
*(BYTE*)Addresses::BotArraySize3 = size;
*(BYTE*)Addresses::BotArraySize4 = size;
}
Arrays in C++ are of fixed size. So when you write char* Bots::NameList[] = {} , you have an empty array of c-strings (aka char*).
Worse, when you later write file >> Bots::NameList[i]; you are writing null terminated c-strings to uninitialized pointers, which will cause memory corruption.
Unless fundamental rewrite, this code is doomed to fail. I strongly suggest that you replace use of char* with std::string and that you switch from fixed size arrays to vectors.
std::vector<std::string> Bots::NameList;
void Bots::GetNames()
{
...
for (int i = 0; i < 48; i++)
{
string s; // space separated strings ? sure ?
file >> s; // or getline(file, s) if you want lines
NameList.push_back(s);
}
}
}
Aditional remark:
I can't tell for sure, as I don't know the definition of Addresses members, but statements like the following are relatively suspicious:
*(char***)Addresses::BotArray1 = Bots::NameList;
It suggests that Addresses::BotArray1 is an array or a pointer. But the fact that you are casting with (char***) suggest that you tried to fix a type mismatch. And dereferencing the casted pointer will make sense only if BotArray points already to a valid char** pointer in which the address of NameList should be stored.
In C++ an array must be sized when created and then it is fixed, so char* Bots::NameList[] = {}; is a zero element array and is stuck that way. Worse, in file >> Bots::NameList[i] nothing ever allocated storage for Bots::NameList[i], so your program is writing into uninitialized memory. Probably a BOOM waiting to happen. I'm going to suggest something completely different.
in the Bots class definition:
std::vector<std::string> NameList;
Then later...
void Bots::GetNames()
{
std::ifstream file("bot_names.txt");
if (file.is_open())
{
for (int i = 0; i < 48; i++)
{
std::string temp;
file >> temp;
NameList.push_back(temp);
}
}
}
Addresses::BotArray1..N must also become std::vectors and Addresses::BotArraySize1..N are made redundant because vectors know their size.
I have to define a global array in my C++ code the size of which has to be read from a file. I am using the below code
#include<iostream>
#include<string>
#include<fstream>
using namespace std;
string inputfile = "input.txt";
ifstream infile(inputfile.c_str());
infile>>N; // N = size of Array
int array[N];
// ------some code here-----
int main(){
int N;
cout << N<<endl;
return 0;
}
But if I place the 3 lines
string inputfile = "input.txt";
ifstream infile(inputfile.c_str());
infile>>N; // N = size of Array
inside the main loop this code works. Unfortunately I cant put it inside any function because I need to initialise a global array from variable N.
I have asked many people and searched different places but I cant seem to be able to figure this out. Thanks for your help.
The size of an array has to be a constant expression, i.e. known at compile-time.
Reading a value from a file is an inherently dynamic operation, that happens at run-time.
One option is to use dynamic allocation:
int array_size()
{
int n;
ifstream infile("input.txt");
if (infile>>n)
return n;
else
throw std::runtime_error("Cannot read size from file");
}
int* array = new int[array_size()];
However it would be better to replace the array with std::vector<int> which can be resized dynamically.
Use a global pointer. Define
int* array;
in the global space before your main procedure. Then later, in a loop or not, say
array = new int[N];
to allocate your array. Just remember to also say
delete[] array;
before you exit your main or re-allocate array
int array[N]; - N should be know at compile-time.
Instead, use int array[]=new int[N]; /*some code using array*/ delete[] array;
int *array;
int main(){
ifstream infile("input.txt");
unsigned N;
infile>>N;
array=new int[N];
//using array...
delete[] array; //when no longer needed.
//don't use array after this line
//unless it's array=new int[] instruction
//or you know what you're doing.
}
I wondering what the best solution is for a structure with variable length array for one of the fields. I've done a bunch of research and I haven't seen a clear answer yet.
I've been playing with the below code and trying to get the varField to be set to an array the size of 10 bytes.
typedef struct TestStruct{
int size;
unsigned char varField[1];
}
I have tried doing zero sized array and that gives me a compile error.
I also tried something like this and it gave me a compile error.
int size= 10;
struct TestStruct*test = malloc(sizeof(struct TestStruct) + (size- 1));
test->size= size;
Thank you so much for help.
The preferred way is to use the dynamically re-sizable std::vector. This class has the rule of five built in.
struct TestStruct {
std::vector<unsigned char> varField;
}
If you're allergic to the standard library, you could use:
unsigned char *varfield;
And supply the necessary constructors/destructors.
If you are implementing messages, a better solution is to set up a hierarchy:
struct Message_Base
{
unsigned int message_length_in_bytes;
unsigned int message_id;
virtual Checksum_Type calculate_checksum(void) = 0;
virtual bool send_message(Receiver& r) = 0;
virtual bool receive_message(Sender& s) = 0;
virtual void process_message(void) = 0;
};
Each child class would be a different message with possible different lengths. Some possible common methods to all message are listed.
This is how to implement using Object Oriented and C++.
The class C language implementation is to declare a zero length array at the end for the message's unique data.
You look like you want a std::vector<unsigned char>:
struct TestStruct{
std::vector<unsigned char> varField;
}
and you get the size with:
ts.varField.size();
You can't. In C++ dynamic size arrays are illegal. The size of an array must be a compile time constant expression.
The options you have basically are
Use an STL container like std::vector or the like. The benefits are that they also take care of memory allocation and deallocation for you.
Use a pointer in your struct and allocate the memory for it dynamically. Don't forget to use delete[] instead of just delete!
In most compilers, the following will work:
template<unsigned N>
struct TestStruct {
unsigned size = N;
unsigned char varField[N];
};
struct ITestStruct {
unsigned size;
unsigned char varField[1]; // variable
};
template<unsigned N>
ITestStruct* make_test_struct() {
return reinterpret_cast<ITestStruct*>(new TestStruct<N>());
};
ITestStruct* make_test_struct( unsigned n ) {
char* buff = new char[ sizeof(ITestStruct)+n-1 ];
ITestStruct* retval = reinterpret_cast<ITestStruct*>(buff);
retval->size = n;
return retval;
}
If you replace char with another non-POD type, things will get hairy.
just I want to ask how can I pass array size to throw function to set size of my game recoreds the only reason I am not using vector because I will base this recored to PMI lib and it doesn't support C++ Constrainers because it written in C that's why I use array
void playGame(int max_streak_length)
{
int tracker =0 ;
const int arrsize = max_streak_length;
int gameRecored[arrsize]={0};
while( tracker < 4)
{
Craps games;
if( games.Play()== true)
{
tracker++;
}
else
if(tracker >0)
{
gameRecored[tracker-1]++;
tracker = 0;
}
}
gameRecored[tracker-1]++;
int v= 0;
}
C++ does not support the variable length array feature available in C.99. However, C++ offers std::vector<> which is as easy to use, and some may say safer.
std::vector<int> gameRecored(arrsize, 0);
You can use gameRecored as an array like you do in your current code, and it will clean itself up when the function call returns.
you can't not define an array whose size is a VARIABLE. If you want a dynamic size, you should use operator new, just like this:
int mysize = 10;
int* array = new int[mysize];
the variable mysize can be a dynamic number, such as function parameter.
If your array will never change its size, you can use :
int array[10];
remember, if you use operator new, you must use operator delete to delete your array when you don't need it.
Hop can help you.