Coming from a Java, PHP background, I am trying to get into C++. I would like to store an array in a struct. My problem is specifying the size of the array after initialising the struct.
Here's my code for the struct:
struct SpriteAnimation {
// ...
int parts; // total number of animation-parts
unsigned int textures[]; // array to store all animation-parts
// ...
};
And here for the main function:
SpriteAnimation bg_anim;
bg_anim.parts = 3;
unsigned int *myarray = new unsigned int[bg_anim.parts];
bg_anim.textures = myarray;
What do I need to change to fix this?
In modern C++, you would use a dynamic container for the inner "array":
struct SpriteAnimation {
std::vector<unsigned int> textures; // array to store all animation-parts
size_t num_parts() const { return textures.size(); }
};
This is by far safer and more modular than anything you could try with manually allocated storage. Usage:
SpriteAnimation x;
x.textures.push_back(12); // add an element
x.textures.push_back(18); // add another element
SpriteAnimation y = x; // make a copy
std::cout << "We have " << x.num_textures() << " textures." std::endl; // report
struct SpriteAnimation {
// ...
int parts; // total number of animation-parts
unsigned int * textures; // array to store all animation-parts
// ...
};
You can use type name[] syntax only if you declare members inline.
Size of a struct must be known at a compilation time.
I worked around the issue through following code.It might be having design issues so please look it up the following code works for me.
#include <iostream>
using namespace std;
struct lol {
// ...
int parts; // total number of animation-parts
unsigned int *texture; // array to store all animation-parts
// ...
};
int main() {
// your code goes here
lol bg_anim;
bg_anim.parts = 3;
unsigned int *myarray = new unsigned int[bg_anim.parts];
bg_anim.texture = myarray;
return 0;
}
Forgive me for using lol instead of your specified name.Do tell me any issues.And help me if there are other issues in my code.
Thank you !! :)
Related
I have a class, which take in a char array of size specified by a constexpr.
Message.h:
constexpr size_t InputBufferSize = 32;
class Message
{
private:
char input[InputBufferSize];
int size;
public:
//constructor
Message(char input[], int size);
//deconstructor
~Message();
int getSize();
};
I'm confused by how to define the constructor, and then create a new instance of that class using the constructor due to the char array. Here is my try (out of a few things I tried):
Message.cpp:
#include "Message.h"
Message::Message(char input[], int size) {
this->input[InputBufferSize] = input[];
this->size = size;
}
Message::~Message() { }
int Message::getSize() {
return size;
}
main.cpp:
#include <iostream>
#include "Message.h"
int main()
{
char charinp;
char input[InputBufferSize] = { 'a','b','c','d','e','f' };
Message ms1(input[], 1);
std::cout << ms1.getSize() << std::endl;
std::cin >> charinp;
return 0;
}
I'd like to create a constructor with an array as on of its parameters, where the array already has a set size, and then create an object from that. The array to be passed into the object will always be of the same size, which is the size of the array the constructor is set to take in.
Message(char input[], int size);
The use of [] in a parameter declaration is just syntax sugar, the compiler will interpret char input[] as char* input instead.
this->input[InputBufferSize] = input[];
This is not legal code. You need to use (std::)memcpy() or std::copy()/std::copy_n() to copy an array to another array:
memcpy(this->input, input, size);
std::copy(input, input + size, this->input);
std::copy_n(input, size, this->input);
On a side note, you should make sure that size does not exceed InputBufferSize before copying the input array:
size = std::min(size, InputBufferSize);
Message ms1(input[], 6);
This is also not legal code. You need to drop the [] when passing the array to a parameter:
Message ms1(input, 6);
std::cin >> charinp;
On a side note, you can use std::cin.get() instead, and remove charinp from your code (since you don't use it anyway).
You are using Message ms1(input[], 6); in your main function,try changing it to Message ms1(input, 6);.
The reason for this is that you have already declared the array char input[] and you have to refer it as inputafter you have declared it not input[].
I have been experimenting with boost multi_array_refs because of their ability to map a 2D (In my case) array view of the world onto arbitrary blocks of contiguous memory. With a multi_array_ref, a pointer to the contiguous memory is specified to the constructor. That works fine, but in my ultimate application, what I would really like to do is take a pre-existing multi_array_ref object, and point it to new buffers that are allocated later, on the fly. It seems like this should be possible, but I can't seem to figure out how to do it. Here's some skeleton code that I hope demonstrates the type of thing I'm attempting to do, although it obviously won't work as written.
const int XSIZE = 10;
const int YSIZE = 5;
typedef boost::multi_array_ref<int, 2> ARRAY_2D_REF;
class Test2D {
public:
Test2D(const int sizeX, const int sizeY);
~Test2D();
// I want to point this multi_array_ref to a buffer that gets
// allocated in the constructor.
ARRAY_2D_REF data;
private:
int xSize;
int ySize;
int *n;
};
// can't construct 'data' using ':' syntax here, because, the 'n'
// buffer has not been allocated yet so 'n' doesn't contain a valid
// address. This compiles okay, but segfaults if you try to use 'data'
// because 'n' contains garabge at this point.
Test2D::Test2D(const int sizeX, const int sizeY) : data(n, boost::extents[sizeX][sizeY]) // <<-- fail
{
xSize = sizeX;
ySize = sizeY;
// In the actual application, n will be populated by data arriving
// on TCP stream. The header on those mesasges contain total
// contiguous buffer size and X,Y dimensions, followed by the data.
n = (int*)malloc(xSize * ySize * sizeof(int));
// I want to set the multi_array_ref origin and define extents right
// here. The thought was to set the origin to 'n', and then
// resize(), but how? Of course I can't actually construct it here
// as shown. Seems like there should be a simple way to set
// (change) the origin pointer. There probably is in fact. But I
// can't seem to figure it out.
data(n, boost::extents[xSize][ySize]);
}
Initializers in the initializer list are evaluated in order of declaration of class members (members after base-classes).
So, you fix it all by moving the data member declaration after the other members.
#include <boost/multi_array.hpp>
static const int XSIZE = 10;
static const int YSIZE = 5;
typedef boost::multi_array_ref<int, 2> ARRAY_2D_REF;
class Test2D {
public:
Test2D(const int sizeX, const int sizeY)
: xSize(sizeX),
ySize(sizeY),
n (new int[xSize*ySize]),
data(n, boost::extents[xSize][ySize])
{ }
~Test2D() {
delete n;
}
Test2D(Test2D const&) = delete; // Rule Of Three!
private:
int xSize;
int ySize;
int *n;
public:
ARRAY_2D_REF data;
};
int main() {
Test2D wrapped(XSIZE, YSIZE);
}
Note also that
there is no place for malloc in C++
you should guard the type against copying, because otherwise you will do double-delete of the data buffer.
Other Thoughts
It really doesn't make any sense to be allocating the buffer from inside the constructor (body, or initializer-list regardless), if your comment says:
// In the actual application, n will be populated by data arriving
// on TCP stream. The header on those mesasges contain total
// contiguous buffer size and X,Y dimensions, followed by the data.
The constructor doesn't have the dependencies necessary to do the allocation, nor SHOULD it. There are two options:
if the buffer is always owned by the Test2D instance (and the data is going to be copied from the IO buffer(s)), then just use multi_array, not multi_array_ref. It does the allocations, safely, for you.
otherwise, pass in the buffer:
#include <boost/multi_array.hpp>
#include <memory>
static const int XSIZE = 10;
static const int YSIZE = 5;
static const int HEADER_SIZE = 16;
typedef boost::const_multi_array_ref<int, 2> ArrayCRef;
class Test2D {
public:
Test2D(int const* raw, int sizeX, int sizeY) : data(raw, boost::extents[sizeX][sizeY])
{ }
ArrayCRef::size_type xSize() const { return data.shape()[0]; }
ArrayCRef::size_type ySize() const { return data.shape()[1]; }
public:
ArrayCRef data;
};
int main() {
auto io_buf = std::make_unique<char[]>(XSIZE*YSIZE*sizeof(int)+HEADER_SIZE);
// TODO parse XSIZE/YSIZE from io_buf
auto raw = reinterpret_cast<int const*>(io_buf.get() + HEADER_SIZE);
Test2D wrapped(raw, XSIZE, YSIZE);
}
I would like to create an array that can store ID and Content in a single cell. I want to store the information so that I could receive both pieces of information from one piece of input.
Currently I am doing it this way:
int order[100];
int content[100];
int count = 0;
//method for adding a new piece of information
void setFrame(int nextOrder, int nextContent){
order[count] = nextOrder;
content[count] = nextContent;
count++;
}
This works, but I would like a way to call a single array, like Array[i], and get two integers from it. How could I accomplish this?
You can use standard class std::pair declared in header <utility>
#include <utility>
//...
std::pair<int, int> order[100];
void setFrame( int nextOrder, int nextContent )
{
order[count++] = { nextOrder, nextContent };
}
Create a struct:
struct Data{
int order;
int content;
};
Data array[100];
int count = 0;
//method for adding a new piece of information
void setFrame(int nextOrder, int nextContent){
array[count].order = nextOrder;
array[count].content = nextContent;
count++;
}
Should be a simple question, I have a struct
struct Foo{
float *bar;
Foo(){
bar = 0;
}
};
and a load function:
bool loadFoo(Foo *data){
float nums[4] = {0,1,2,3};
data->bar = nums;
return true;
};
And I run it like this:
void main(){
char data;
Foo myFoo;
loadFoo(&myFoo);
std::cerr << sizeof(myFoo.bar) << "\n";
std::cerr << myFoo.bar[0] << "\n";
std::cerr << myFoo.bar[1] << "\n";
std::cerr << myFoo.bar[2] << "\n";
std::cerr << myFoo.bar[3];
std::cin >> data;
};
and the output is 4 bytes for the sizeof(myFoo->bar) I thought by passing the struct to the method I could modify data->bar and since bar is, float *bar; I could make it an array since I cant specify that bar is an array because its an 'unknown size' when loaded. (when implemented the program will read in values from a file) This works fine with non pointer variables but its the pointer that I can't seem to understand.
How do I make it so that when I pass the struct I can modify the variable pointer?
any help would be greatly appreciated!
You can do something like you've specified, but the exact implementation you've given will encounter undefined behavior.
bool loadFoo(Foo *data){
// Create an array of 4 floats ON THE STACK.
float nums[4] = {0,1,2,3};
// point data->bar at the above slice of stack.
data->bar = nums;
return true;
// abandon the piece of stack we're pointing at.
}
You might want to look into std::vector as a growable way of storing runtime sizes arrays, or you will need to allocate backing store for the destination floats, e.g.
data->bar = new float[4];
and free it when you are done with it
delete data->bar;
That said; it would seem more elegant to do these operations as members of Foo.
#include <vector>
// #include <algorithm> // (for the std::copy option)
class Foo
{
std::vector<float> m_floats;
public:
Foo() : m_floats() {}
void loadFloats()
{
m_floats = { 0, 1, 2, 3 };
}
// or load them from someplace else
void loadFloats(float* srcFloats, size_t numFloats)
{
m_floats.clear();
m_floats.reserve(numFloats);
// copy by hand:
for (size_t i = 0; i < numFloats; ++i) {
m_floats.push_back(srcFloats[i]);
}
// or just:
// std::copy(srcFloats, srcFloats + numFloats, m_floats);
}
};
You haven't specified the problem but let me guess - it crashes and/or doesn't yield the result you expect. The reason for that is assigning a pointer to a local variable in the line data->bar = nums; Here you link your data->bar to a nums array which is allocated on stack and is freed when you exit loadFoo. The result is a dangling pointer inside your Foo object.
You can solve this in different ways. The most straightforward would be to use a constructor with size parameter - this will solve your unkonwn size issue. You'll need to explicitly allocate memory for the data->bar and copy the data into the allocated space (of course, it will require to free it when not in use anymore). Same effect can be achieved by using your loadFoo func but using internal language features (constructor/destructor) is much cleaner.
Instead of loadFoo you can have constructor
struct Foo{
float *bar;
Foo( int size){
bar = new float[size]; //allocate memory
//... Initialize bar
}
~Foo() { delete bar;}
};
OR using initializer_list
#include <initializer_list>
struct Foo{
float *bar;
Foo( std::initializer_list<float> l){
bar = new float[l.size()]; //allocate memory
std::initializer_list<float> ::iterator it = l.begin();
size_t i=0;
for(;it!=l.end();++it,++i)
bar[i] = *it;
}
~Foo() { delete bar;}
};
Also, make sure you follow rule of three
I would like to create a struct and use it inside an other struct as an array. My problem is that I don't know how big array I would like to allocate, I will only know once I am in a function. I mean I would like to use [] instead of a pre-determined constant, like 10000.
I think if you look at my code it would be self-explanatory. Can you help me how to make this code work? Moreover it would help me a lot if you could tell me what is the name of the topic I am asking about (is it dynamic arrays?) and that where can I find articles/tutorials about this topic.
Here is the code with my broken way of thinking about arrays in structs.
#include <iostream>
using namespace std;
struct keyframe {
bool a;
int b;
int c;
};
struct keyframe_file {
const int num_views;
const int num_keyframes;
keyframe keyframes[];
};
int main() {
keyframe_file my_file;
my_file.num_views = 1;
my_file.num_keyframes = 6;
my_file.keyframes = new keyframe[my_file.num_keyframes];
my_file.keyframes[0].a = true;
my_file.keyframes[0].b = 5;
my_file.keyframes[0].c = 9;
return 0;
}
Use a std::vector.
struct keyframe_file {
const int num_views;
const int num_keyframes;
std::vector<keyframe> keyframes;
};
int main() {
keyframe_file frame;
frame.keyframes.resize(...);
}
If it suits your purpose, an STL container (std::vector) is easily one of the best options - the less memory management you have to worry about, the better.
In any case, look at the struct definition Nawaz posted above - that's exactly how it should be. Dynamic arrays in C++ are simply pointers. You have, however, allocated the memory properly in your code, but you haven't freed it (so it's leaking). Since you allocated with new [] you will need to
delete [] my_file.keyframes;
in order to free the memory properly.
Resizing is another issue: with a smart implementation, array resizing can be an amortized O(1) operation which is nice. When you resize, it will always take you O(n) since you need to copy all the elements into a new array of different size, but if you do it half as much, it becomes O(1). That is, double the array each time you need to resize. Here is a very quick example
void resize()
{
if(numOfElementsInArray == sizeOfArray)
{
ArrayType * arr = new ArrayType[sizeOfArray*2]; // Allocate a double size array
for(int i=0;i<sizeOfArray;++i)
currentArray[i] = arr[i];
delete [] currentArray; // Free memory in old array
currentArray = arr; // Set the array to our new one
sizeOfArray *= 2; // Double the size
}
}
NOTE: The example above does not take into account space complexity; that said, if you have 5000 elements, and remove all but 5, this method with not shrink it (which is probably what you will want to do for all practical purposes)
Your code appears to be almost correct, except for two things:
keyframes needs to be a keyframe* rather than a keyframe[]
You forgot to delete the memory you allocated
That is incomplete type. In C++, array must be provided with size, and the size must be known at compile time itself.
You're using new, with which you should be using pointer.
struct keyframe_file {
const int num_views;
const int num_keyframes;
keyframe *keyframes;
};
But std::vector<keyframe> is still a better choice, as #DeadMG already suggested.
By the way, the first two members are const in the struct, that means, they cannot be assigned value, as you're doing in your code. They must be initialized with values you want them to hold. That implies, now with vector, you've to include a constructor, to initialize the struct, as the struct is no more a POD.
struct keyframe_file {
const int num_views; //const member
const int num_keyframes; //const member
std::vector<keyframe> keyframes;
keyframe_file(int nviews, int nkeyframes)
: num_views(nviews), num_keyframes(nkeyframes), keyframes(nkeyframes){}
};
keyframe_file my_file(1,6); //done!
The suggested "Vector" is they safest way to do it.
But if it is only about making your code work (without resizing and stuff) the following should be working:
#include <iostream>
using namespace std;
struct keyframe {
bool a;
int b;
int c;
};
struct keyframe_file {
const int num_views;
const int num_keyframes;
keyframe* keyframes;
};
int main()
{
keyframe_file my_file = {1, 6}; // initialization needed bcause of 'const int'
my_file.keyframes = new keyframe[my_file.num_keyframes];
for (int i = 0; i < my_file.num_keyframes; i++)
{
my_file.keyframes[i].a = true;
my_file.keyframes[i].b = 5 + i;
my_file.keyframes[i].c = 9 - i;
}
return 0;
}
somewhere in your code, when you are done using the array you have to call delete [] my_file.keyframes; as already mentioned.
There's a basic rule when using dynamic arrays in c++, especially when using it inside structs or classes, and it's to delete what you no longer need.
If you want to make your struct dynamic, it's easy, just replace the [] with * and the array will become dynamic, but it's not over yet, there is a lot of work.
You have to construct the array and destory it, and destoroying it is possible and useful noly with destructors, like this:
struct keyframe_file
{
const int num_views;
const int num_keyframes;
keyframe* keyframes;
~keyframe_file() // this is the destructor
{
delete[] keyframes;
}
};
Yet even that code isn't going to work at all, since you are assigning values to constants in variable my_file after creating it, it's illegal in c++, you should then use classes instead.
Using classes with dynamic arrays is very easy and interesting and makes your code very good, you don't have to know too much to do that, just learn what is a constructor, an initializer, destructor, private and public and go on with the following code:
#include <iostream>
using namespace std;
struct keyframe
{
bool a;
int b,c;
};
class keyframe_file
{
public:
keyframe_file(int NV, int NKF):num_keyframes(NKF),num_views(NV)
{
keyframes = new keyframe[num_keyframes];
}
~keyframe_file()
{
delete[] keyframes;
}
private:
const int num_views;
const int num_keyframes;
keyframe* keyframes;
};
int main()
{
keyframe_file my_file(1,6);
return 0;
}
This code works very well, it allows you to assign value to the constants num_views and num_keyframes for one time when creating the object (variable) my_file.
Remember, you are a C++ programmer, be proud of that, and use classes instead of structs and dynamic arrays instead of static ones.
Hope that's useful.
Use pointers and apply to your structure!
int *p;
p = new int;
#include <iostream>
using namespace std;
struct keyframe {
bool a;
int b;
int c;
};
struct keyframe_file {
const int num_views;
const int num_keyframes;
keyframe *keyframes;
};
int main() {
keyframe_file my_file;
my_file.num_views = 1;
my_file.num_keyframes = 6;
for (int i = 0; i < my_file.num_keyframes; i++){
my_file.keyframes = new keyframe; //<---
}
my_file.keyframes[0].a = true;
my_file.keyframes[0].b = 5;
my_file.keyframes[0].c = 9;
return 0;
}