How to define dynamic value on "#define" - c++

I have some problem with my code.
I wanna using struct array to calculate something.
But my array size is dynamic not static.
Here's my code
#include <iostream>
#define MAX 5
using namespace std;
struct Point{
int x,y;
}arrayy[MAX];
int main(){
int num_howmanytime,num_max;
cin >> num_howmanytime;
while(num_howmanytime--){
cin >> num_max;
}
}
As you can see the num_max is dynamic, it will change value according user input what value on it.
So my question is:
How to let MAX get the same value with num_max
I know that that is not possible so must use others ways, such as

How to let MAX get the same value with num_max?
That's impossible. MAX is a compile-time constant (that you would better declare as e.g. constexpr std::size_t max = 5; instead of using the preprocessor), while num_max is a value determined at runtime.
The difference with respect to array sizes is that you must dynamically allocate the memory for arrays with a runtime-dependent size. As suggested in the comments, you typically don't do that manually, but instead rely on an existing type, often a template.
Example for your case:
#include <vector>
std::vector<Point> points;
cin >> num_max;
// Set the runtime array size, let the vector allocate its memory.
// Also, provide a default initial value for all Point instances.
points.resize(num_max, {0, 0});
Note that passing the default Point instance {0, 0} to std::vector::resize is optional here, as the function will value-initialize the newly created elements, which is is zero-initialization in this case.

There are some ways here.
In C++
You can use std::vector
struct Point {
int x, y;
};
int main() {
int num_howmanytime, num_max;
cin >> num_howmanytime;
while (num_howmanytime--) {
cin >> num_max;
std::vector<Point> arrayy(num_max);
}
return 0;
}
In C(since C99)
You can use VLA(Variable-length array)
struct Point {
int x, y;
};
int main() {
int num_howmanytime, num_max;
scanf("%d", &num_howmanytime);
while (num_howmanytime--) {
scanf("%d", &num_max);
struct Point arrayy[num_max];
}
return 0;
}
In C(before C99)
You can allocate the memory dynamically
struct Point {
int x, y;
};
int main() {
int num_howmanytime, num_max;
scanf("%d", &num_howmanytime);
while (num_howmanytime--) {
scanf("%d", &num_max);
struct Point *arrayy;
arrayy = malloc(sizeof(struct Point) * num_max);
}
return 0;
}

Related

Setting the size of array in a struct by passing as a const to a function - Non-type template argument is not a constant expression

User sets k at running time. This number will be constant for the rest of the code. I want to create a function to pass and create a struct that includes an array of size k with that number. However, the compiler returns this error:
Non-type template argument is not a constant expression
Any recommendation will be appreciated.
The code is like:
template <int N>
struct UL {
unsigned long ul [N];
};
void func(const int k){
UL<k> x; //problem is here
}
int main () {
int k;
cin >> k;
func(k);
return 0;
}
Variable k is set at runtime, so when the code is being compiled, the compiler doesn't know what the value of k is. You can't do this. But if you know what your k value is going to be and the range of values it can be is limited, you can create your struct for each possible value of k and choose the matching class at runtime. Of course this is not probably what you want. You just need to be able to distinguish between what is known at compile-time and at runtime. Templated literals (I hope I used the right name) are a compile-time feature of C++.
Templates are processed at compile-time only. You can't pass a run-time variable, like a function parameter, to a template. For what you are trying to do, you will have to use std::vector instead, eg:
#include <vector>
struct UL {
std::vector<unsigned long> ul;
};
void func(const int k){
UL x;
x.ul.resize(k);
}
int main () {
int k;
cin >> k;
func(k);
return 0;
}
A fundamental principle about templates is that:
Any template argument must be a quantity or value that can be determined at compile time.
This has dramatic advantages on the runtime cost of template entities.
But in your example, k is not a compile time constant and you're using it as a template argument and so as a consequence of the above quoted statement you get the error.
To solve your problem you can use a std::vector as shown below:
#include <iostream>
#include <vector>
struct UL {
std::vector<unsigned long> ul;
//constructor
UL(int k): ul(k) //this creates vector ul of size k
{
std::cout<<"size of vector set to: "<<ul.size()<<std::endl;
}
};
void func(const int k){
UL x(k); //pass k as argument to constructor
}
int main () {
int k;
std::cin >> k;
func(k);
return 0;
}
The output of the program can be seen here.

Array of a specific size used out of the function it was initialized in

I'm a high school student learning programming and I have a problem that I can't figure out how to solve.
I have an integer "x", and I want a matrix "mat" to have the size of "x":
int mat[x][x];
But that works only in main() where I've read x;
For example if x == 5, the equivalent would be
int mat[5][5];
#include <iostream>
using namespace std;
int x;
int mat[x][x];
void f(int mat2[x][x])
{
}
int main()
{
cin >> x;
int m[x][x];
f(m);
}
I've wrote this short program to show where it works and it doesn't work.
error: array bound is not an integer constant before ']' token
I've the error at the global declaration, at the declaration in function void f. It only compiles without errors in main();
What can I do to create a matrix with the size of x outside of the main function?
Variable length arrays aren't spported in standard c++. Besides you don't want the global definition.
What you can use portably in that case is std::vector:
void f(std::vector<std::vector<int>>& mat)
{
}
int main()
{
cin >> x;
std::vector<std::vector<int>> m(x,std::vector<int>(x));
f(m);
}
If you pass that vector around to functions or being allocated within functions, the size information will be kept at any time.
What can I do to create a matrix with the size of x outside of the main function?
Something like this:
std::vector<std::vector<int>> foo() {
cin >> x;
std::vector<std::vector<int>> m(x,std::vector<int>(x));
return m;
}
int main()
{
std::vector<std::vector<int>> mat = foo();
}
Handling of multi-dimension arrays in C++ is not easy. The best way to go is often to map a multi-dimensionnal indexing with a linear memory chunk.
For instance, for a 2 by 2 matrix, one can create an array of 2*2=4 elements and map it this way:
+-----------+-----------+-----------+-----------+
| map[0][0] | map[0][1] | map[1][0] | map[1][1] |
+-----------+-----------+-----------+-----------+
This seems overly complicated at first glance, but it simplifies greatly the memory allocation.
For an arbitrary sized matrix of width by height, map[i][j] is at index i*height + j. This can be translated in C++, encapsulated in a template class Matrix:
#include <array>
template <typename T, size_t WIDTH, size_t HEIGHT>
class Matrix {
std::array<T, WIDTH*HEIGHT> data;
public:
T& operator()(size_t i, size_t j) {
return data[i*HEIGHT + j];
}
const T& operator()(size_t i, size_t j) const {
return data[i*HEIGHT + j];
}
};
This has the disadvantage that the Matrix' dimensions must be known at compile time (and can be mitigated, see note (ii) at end of answer). But it makes its use so easy:
void fill(Matrix<int, 2, 2>& m) {
m(0,0) = 0;
m(0,1) = 1;
m(1,0) = 2;
m(1,1) = 3;
}
int main() {
Matrix<int, 2, 2> m;
fill(m);
std::cout << m(1,0) << "\n";
}
Note (i): Elements are indexed by (line, column) rather than [line][column] because we can't create an operator[] accepting multiple values.
Live on coliru
Note (ii): This basic idea can be enriched (demo) to handle resizable matrixes, with use of a std::vector instead of std::array and a proxy to std::vector::resize().
Variable-length array is supported by some compiler as an extension. The manual of the compiler provides more information.Gnu VLR
The storage duration of a variable-length array(if supported) generally can't be static, which is why you get the error message (global variables have static storage duration).
Unrelated: The major array bound of the parameter mat2 isn't necessary, i.e. void f(int mat2[x][x]) is equivalent to void f(int mat2[][x]).
C++ has no provision for dynamic 2D matrix but provides all you need to create complex classes. A (static) 2D array is a contiguously allocated array of height arrays of width elements. Just mimic that and:
allocate a linear array of width * height
provide an operator[](int) that returns a pointer to the first element of ith row
do necessary housekeeping in destructor and in a copy (and move if C++11 or above) constructor.
Example of code:
template <typename T>
class Matrix {
T *data;
int width;
int height;
public:
// direct ctor
Matrix(int h, int w): width(w), height(h) {
data = new T[w * h];
}
//copy ctor
Matrix(const Matrix& src): width(src.width), height(src.height) {
data = new T[width * height]; // allocate and copy data array
for (int i=0; i<width * height; i++) data[i] = src.data[i];
}
// move ctor
Matrix(Matrix&& src): width(src.width), height(src.height) {
data = src.data; // steal original array in a move
src.data = NULL; // ensure no deletion will occur at src destruction
}
~Matrix() {
delete data;
data = NULL;
}
// explicitely delete assignement operators
Matrix& operator = (const Matrix&) = delete;
Matrix& operator = (Matrix&&) = delete;
T* operator[](int i) {
//optionaly test 0 <= i < width
return &data[i * width];
}
};
int main()
{
int w;
std::cin >> x;
Matrix<int> m(x, x);
// you can then use m[i][j] as you would for a static 2D array
...
}
This class does not support any resizing by design. If you need that, you really should use a vector<vector<T> >. The downside is that it has no default ctor either, because the dimension must be given at definition time (even if we could easily imagine a 2 phases initialization...).
You can dynamic allocate memory to use, in the c/c++, it does not support dynamic size of static memory allocation, so, you just modify your code like this.
int x;
cin >>x;
int** mat = new int[x][x];

Creating an array of a struct

I am trying to make an array of structs, but I am getting the error no matching function for call to 'Cell::Cell()'.
Cell is the name of my struct. Here is some of my code:
struct Cell{
int number;
Cell(int n){
number = n;
}
};
class MyClass{
public:
int nCells;
void inject(){
std::cout << "Enter number:";
string in;
std::cin >> in;
int amount = in.size()/3;
Cell cells [amount]; // <-- error
int index = 0;
int t = in.size();
while (t >= 3){
cells[index] = new Cell(atoi(in.substr(t-3,3).c_str());
t -= 3;
index++;
}
}
MyClass(int n){
nCells = n;
}
};
Cell cells [amount]; is giving me the error. I am new to classes, but I know how to make arrays of primitive types. int cells [amount]; would work, for instance.
But how am I supposed to make an array of type Cell ?
Cell doesnt have a default constructor (as soon as you specify another constructor the compiler will not create a default constructor anymore). However the definition Cell cells[amount] will automatically default initialize every element.
I think the best way in this particular situation is simply to implement a default constructor:
struct Cell{
int number;
Cell() : number(0)
{
}
Cell(int n) : number(n)
{
}
};
Also notice as amount is not known at compile time, Cell cells[amount] is basically illegal. However some compilers have extensions to allow this. But its better if you heap allocate it:
Cell* cells = new Cell[amount];
Dont forget to destroy it however.
If you know how long the array is, you can use c++11 initialization. This will do :
int main()
{
Cell c[3]{ Cell(1), Cell(2), Cell(3) };
}
By the way this
Cell cells [amount];
is using VLAs, and that is not supported by c++ (only as extension for some compilers).
In c++, much better would be to use std::vector :
#include <vector>
struct Cell{
int number;
Cell(int n){
number = n;
}
};
int main()
{
int n = 5;
std::vector< Cell > c;
for ( int i =0; i < n; ++ i )
{
c.emplace_back( Cell( i ) );
}
}
By doing Cell cells [amount]; you are calling the Cell constructor, but in this case you don't have a default constructor for Cell, so you must use pointers instead, you are using them in the while stuff.
Just change
Cell cells [amount];
for
Cell* cells [amount];

Array in Struct, Pointers [C++ Beginner]

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 !! :)

beginner question about arrays in structs in C++

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;
}