How to make a class member big 2D C array properly? - c++

I have a very simple piece of code:
#include <iostream>
#include <random>
using namespace std;
const int K=1;
const int N=1024*K;
const int M=1024;
class C {
public:
C(){
minstd_rand0 g(1);
for(int i=0; i<N; ++i) for(int j=0; j<M; ++j)
a[i][j]=generate_canonical<float, numeric_limits<float>::digits>(g);
}
private:
float a[N][M];
};
int main()
{
C c;
cout<<"size="<<N*M/(1<<20)<<endl;
return 0;
}
At K=1 the code works, but at K=2 immeadiately fails with a segmentation fault.
So, as I understand, there is some restriction on the amount of data an arbitrary class can contain (not more than this amount of MB). How to get to know this amount exactly?
In my work I deal with arrays similar to a, which stand for the probability function distribution on some line segment. I have dozens of such arrays. I supposed to put all these arrays in 1 manager class that will handle all of them, but as this example shows, it is impossible, a segmentation fault occurs. So, I have for example 10 arrays (I would like to incapsulate all of them inside some single object) of double's with the number of elements 2x1024x1024. How to manage them in the program properly?
P. S. If to allocate them on the heap:
class C {
public:
C(){
p = new float*[N];
for(int i=0; i<N; ++i) p[i]=new float[M];
minstd_rand0 g(1);
for(int i=0; i<N; ++i) for(int j=0; j<M; ++j)
p[i][j]=generate_canonical<float,
numeric_limits<float>::digits>(g);
}
~C(){
for(int i=0; i<N; ++i) delete [] p[i];
delete [] p;
}
private:
float ** p;
};
the program works even at K=100. Is it a proper way to manage them?
After all, is there a way to allocate the array statically without making it a static class member?
P. P. S.
This piece of code works:
const int K=10;
const int N=1024*K;
const int M=1024;
float a[N][M];
class C {
public:
C(){
p=(float *)a;
minstd_rand0 g(1);
for(int i=0; i<N; ++i) for(int j=0; j<M; ++j)
p[i*M+j]=generate_canonical<float,
numeric_limits<float>::digits>
(g);
}
public:
float *p;
};
But I don't know if it is a proper way to hande such big arrays.

Related

Printing array obtained as a return value C++ [duplicate]

This question already has answers here:
Closed 10 years ago.
The following code is printing garbage values. I am passing an array to a function which adds 5 to every element, but when it returns that array's pointer, the main is showing garbage.
I have tried both indexing and pointers there in main but still same results. How can I fix this?
# include <conio.h>
# include <iostream>
using namespace std;
int * add5ToEveryElement(int arr[], int size)
{
int theArray[5];
for(int i=0; i<size; i++)
{
theArray[i] = arr[i] + 5;
cout<<theArray[i]<<endl;
}
return theArray;
}
void main()
{
const int size = 5;
int noArr[size];
for(int i=0; i<size; i++)
{
noArr[i] = i;
}
int *arr = add5ToEveryElement(noArr, size);
cout<<endl;cout<<endl;
for(int i=0; i<size; i++)
{
cout<<arr[i]<<endl;
}
cout<<endl;cout<<endl;cout<<endl;cout<<endl;
for(int i=0; i<size; i++)
{
cout<<*arr<<endl;
*arr++;
}
getch();
}
theArray is a local array in the function add5ToEveryElement() which you are returning to main(). This is undefined behaviour.
Minimally you can change this line:
int theArray[5];
to:
int *theArray = new int[5];
It'll work fine. Don't forget to delete it later in main(). SInce you modify the original pointer, save it:
int *arr = add5ToEveryElement(noArr, size);
int *org = arr;
// Rest of the code
//Finally
delete[] org;
Returning an array from a function is generally considered bad.
Unless you MUST have a "new" array, I would suggest the typical case in C and C++ is to modify the input array. If the CALLING function wants to have two separate arrays, then it can do so by making it's own copy. Alternatively, you could write your code to have two arrays passed into your function, e.g.
void add5ToEveryElement(int arr[], int arr2[], int size)
{
for(int i=0; i<size; i++)
{
arr2[i] = arr[i] + 5;
cout<<theArray[i]<<endl;
}
}
then your main would call with two array arguments, and if you wish to use the same as input and output it will do that too.
Sure, this isn't exactly the answer to your question, but it gives a "better" solution to your problem.
I generally dislike allocation in functions - especially "hidden" allocation (this function says it's adding 5 to every element, not "allocate array with added 5 to each element". Code should never do surprising things, and allocating memory is a little bit of a surprise if you only asked for adding 5 to each element)
this is the perfect code
# include <conio.h>
# include <iostream>
using namespace std;
int * add5ToEveryElement(int arr[], int size)
{
int *theArray = new int[5];
for(int i=0; i<size; i++)
{
theArray[i] = arr[i] + 5;
cout<<theArray[i]<<endl;
}
return theArray;
}
void main()
{
const int size = 5;
int noArr[size];
for(int i=0; i<size; i++)
{
noArr[i] = i;
}
int *arr = add5ToEveryElement(noArr, size);
int *p = arr;
cout<<endl;cout<<endl;
for(int i=0; i<size; i++)
{
cout<<arr[i]<<endl;
}
cout<<endl;cout<<endl;cout<<endl;cout<<endl;
for(int i=0; i<size; i++)
{
cout<<*arr<<endl;
*arr++;
}
getch();
delete[] p;
}

Declaring an array of pointers to objects dynamically in C++

I have to declare an array of pointers to objects (of classes) in C++. I thought this was the only way, but apparently I was wrong, as it throws a syntax error when I try to compile it. Specifically, among the 7 errors I received, 2 of these errors are in the lines: where I create the array using "new", and in the line where I call the "setData()" function. Can you tell me where I went wrong? Thanks.
#include <iostream>
class Test
{
public:
int x;
Test() { x=0; }
void setData(int n) { x=n; }
};
void main()
{
int n;
Test **a;
cin >> n;
a=new *Test[n];
for(int i=0; i<n; i++)
{
*(a+i)=new Test();
*(a+i)->setData(i*3);
}
}
Use a=new Test*[n];
Other than that, you have no deleteĀ“s in your program, trivial getter/setters
for public variables are strange, and *(a+i) could be a[i]
Your syntax is close but slightly off. Use this instead:
Test **a;
...
a=new Test*[n];
for(int i=0; i<n; i++)
{
a[i]=new Test();
a[i]->setData(i*3);
}
...
// don't forget to free the memory when finished...
for(int i=0; i<n; i++)
{
delete a[i];
}
delete[] a;
Since you are using C++, you should use std::vector instead. I would also suggest passing the desired value to the class constructor:
#include <iostream>
#include <vector>
class Test
{
public:
int x;
Test(int n = 0) : x(n) { }
Test(const Test &t) : x(t.x) { }
void setData(int n) { x=n; }
};
int main()
{
int n;
std::vector<Test> a;
cin >> n;
a.reserve(n);
for(int i=0; i<n; i++)
{
a.push_back(Test(i*3));
}
...
// memory is freed automatically when finished...
return 0;
}

how to delete two-dimentional double array

I wrote two functions - one to create two-dimentional double array, and another one to delete it.
double** createMatrix(int n)
{
double **a = new double *[n];
for (int i=0; i < n; i++)
a[i] = new double[n];
return a;
}
void deleteMatrix(double** a, int n)
{
for (int i=0; i < n; i++)
delete [] a[i]; // ERROR HERE
delete []a;
}
Allocated array is working fine. But when I try to free it, I get an error (on a marked line): "project2.exe has triggered a breakpoint.".
I'm using Visual Studio 2012.
edit:
I created a full program:
int main()
{
const int n = 10;
double **m = createMatrix(n);
deleteMatrix(m, n);
return 0;
}
And it's working fine. Also, I found my problem. It was a typo in copyMatrix function.
for (int j=0; j <= n; j++) // should be < instead of <=
a[i][j] = originalMatrix[i][j];
Thanks a lot for your help!
The obvious solution is not to use an array in the first place.
How to create an n x n matrix ?
#include <iostream>
#include <vector>
using Row = std::vector<int>;
using Matrix = std::vector<Row>;
int main() {
size_t const n = 5;
Matrix matrix(Row(n), n);
}
Simple right ? And as a bonus, copy, move and destruction are provided free of charge.

How do I initialize a 2-D dynamic memory array of pointers with all elements 0

I want to initialize values of 2-D array to 0. But it seems not to work.
Can I initialize values of my **array in constructor to be 0. If yes the How.
My code is.
#include <iostream>
using namespace std;
int main(){
int row, col;
cin>>row;
cin>>col;
int **array=new int*[row];
for (int i=0; i<row; i++){
array[i]=new int[col];
}
for (int i=0; i<row;i++){
for (int j=0; j<col; j++){
array[i][j]={'0'};
cout<<array[i][j]<<" ";
}
cout<<endl;
}
}
Further can someone explain if I have to replace ith elem from the array with some other element, how would I deal with memory allocation.
You probably want array[i][j]=0;. Why were you using the char type '0'?
However, there is an easier way: array[i]=new int[col]();, just add () to value initialize each column.
There also is a better way:
std::vector<std::vector<int>> array(row, std::vector<int>(col));
For your first comment, you would need to create a new array with the new size, copy over all the data, and the delete your old 2-d array.
For your second comment, here is an example:
struct A
{
int **array;
A(int row, int col) : array(new int*[row])
{
for (int i=0; i < row; i++)
{
array[i]=new int[col]();
}
}
};
PS: You can save yourself a lot of work by using std::vector.
this codes works on gcc
#include <iostream>
using namespace std;
int main(){
int row, col;
cin>>row;
cin>>col;
int **array=new int*[row];
for (int i=0; i<row; i++){
array[i]=new int[col];
}
for (int i=0; i<row;i++){
for (int j=0; j<col; j++){
array[i][j]=0;
cout<<array[i][j]<<" ";
}
cout<<endl;
}
}
to replace ith element of the array with some other element we can do something lyk
int *aa = new int[p];
swap(array[i], aa)
but for this to work logically correct u need to make sure that p >= size of the array array[i] is pointing to. In most of our use cases we have them equal.
You can try something like this:-
class A
{
public:
A():my2DArray() {0}
private:
B* my2DArray[max1][max2];
};

How do I pass multi-dimensional arrays of unknown size into a function using pointers in c++?

Like the question says, I am trying to pass multi-dimensional arrays into a function to print it to a file for an engineering project. The format for which the data is inputted CANNOT be changed, so please don't suggest I just input it as a different datatype.
This particular function anticipates a two-dimensional array (although I have others with three dimensions after this one), where nothing is known about the size of the array until run-time. I know I must use pointers to point to each row of the array separately, but I have NO idea what the syntax is for passing it to the function. In the following code, the array in question is 'block'. The main function is just a little testing example I made to try to make it work:
#include<fstream>
using namespace std;
void of_write_blocks(string filename, string block_type[], int **block,
int grid[][3], string grade_type[], int grade[][3], int n_blocks, int m[])
{
ofstream file_out(filename.c_str(),ios::app);
file_out<<"\nblocks\n(\n";
for(int i=0;i<n_blocks;++i) {
file_out<<" "<<block_type[i]<<" ( ";
for(int j=0;j<m[i];++j)
file_out<<block[i][j]<<" ";
file_out<<") ( ";
file_out<<grid[i][0]<<' '<<grid[i][1]<<' '<<grid[i][2]<<" ) ";
file_out<<grade_type[i]<<" ( ";
file_out<<grade[i][0]<<' '<<grade[i][1]<<' '<<grade[i][2]<<" )\n";
}
file_out<<");\n";
}
//testing example:
int main()
{
int block[6][9];
for(int i=0; i<6;++i)
for(int j=0; i<9;++j)
block[i][j] = i*j;
int grid[6][3];
for(int i=0; i<6;++i)
for(int j=0; i<3;++j)
block[i][j] = i*j;
int grade[6][3];
for(int i=0; i<6;++i)
for(int j=0; i<3;++j)
block[i][j] = i*j;
string grade_type[6] = {"simpleGrading"};
string block_type[6] = {"hex"};
int m[6] = {8};
int n_blocks = 6;
of_write_blocks("name",block_type,block,grid,grade_type,grade,n_blocks,m);
}
any help is appreciated!
You can't. Multidimensional arrays are syntactic sugar, and are compiled directly into the code that does manipulations on the array, which is a single memory block. The dimensions are not passed into the function as parameters or anything like that as part of the array, as things are done in e.g. Java or C#.
If you need the dimensions of the array in your function, you'll need to just accept a pointer to the first element of the array, and the dimensions, and do the multiplies and adds to get the right index yourself.
Alternately, use something like a std::vector<std::vector<block>>, which pass the dimensions as part of the object, rather than a built in array.
If you have Boost installed, check out Boost Multi-Array.
For clarity I removed all the irrelevant code from your example.
#include <iostream>
#include <fstream>
using namespace std;
void of_write_blocks(int **block, int bh, int bw){
for(int i = 0; i < bh; ++i)
for(int j = 0; j < bw; ++j)
cout << block[i][j] << " ";
cout << endl;
}
int main(){
int bh, bw;
cin >> bh >> bw;
int** block;
block = new int*[bh];
for(int k = 0; k < bh; k++)
block[k] = new int[bw];
// initialize the array
for(int i = 0; i < bh; i++)
for(int j = 0; j < bw; j++)
block[i][j] = (i*bw) + j;
of_write_blocks( block, bh, bw);
}
In the main we are creating a 2D array and initializing it. Then we pass it to of_write_block, which prints the array. Is that what you wanted to do?
Why can't use a reference of array. See below example:
char c[10];
int i[10][20];
double d[10][20][30];
Write a wrapper function like this:
template<typename T, int SIZE>
void Array (T (&a)[SIZE])
{}
template<typename T, int SIZE1, int SIZE2>
void Array (T (&a)[SIZE1][SIZE2])
{}
template<typename T, int SIZE1, int SIZE2, int SIZE3>
void Array (T (&a)[SIZE1][SIZE2][SIZE3])
{}
This is just an example to demonstrate the syntax which will elegantly receive the array without any copying and also avoids confusing pointers. Also, if you are aware that you are going to use only for int then simply remove the typename and explicitly mention int. i.e.
template<int SIZE>
void Array (int (&a)[SIZE]); // explicitly mention int