I was following a tutorial here. I came across the following lines of code.
double** pvalue = NULL; // Pointer initialized with null
pvalue = new double [3][4]; // Allocate memory for a 3x4 array
When I compiled it, it is throwing an error
"cannot convert 'double (*)[4]' to 'double**' in assignment"
Is the code invalid? or I'm doing something wrong.Also, please, if possible, describe how could I declare pointer to multi dimension array?
You can not do it. double [3][4]; allocates a flat memory of 3 arrays double[4]. The tutorial has the error.
using d4 = double [4];
// or typedef double d4[4];
d4* pvalue = nullptr;
pvalue = new double [3][4];
delete[] pvalue;
This pvalue = new double [3][4]; is not correct. Find how to allocate memory for 2D array using new. May be you want like below.
int main(void) {
double** pvalue = NULL;
/* first allocate for pvalue */
pvalue = new double *[3];
for(int col = 0; col < 3 ; col++ )
/* allocate for each palue element */
pvalue[col] = new double [4];
return 0;
}
Once done, don't forget to free the dynamically allocated memory by calling delete.
You can't do this. If you must allocate memory by yourself, try:
double** pt=nullptr;
pt=new double[3];
for(std::size_t i=0;i<3;++i)
pt[i]=new double[4];
the deletion is a reverse process of allocation.
And one thing you need to notice is that you shouldn't use range-based for non-member begin and end function or sizeof operator since pt is not an array.
If you want to keep allocation of the two dimensional array,
new double [3][4]
there are two way to refer to this memory chunk,
1.,
double* pvalue = NULL;
pvalue = (double*)new double [3][4];
and 2.,
double (* parray)[4] = NULL;
parray = new double [3][4];
if you want to keep the pointer-to-pointer variable, i.e., double** ppvalue, then,
double** ppvalue = NULL;
ppvalue = new double*[3]; (a)
for(int i =0; i<3; i++)
ppvalue[i]=new double[4]; (b)
basically, you need to allocate memory for the array of pointers(a), and populate those pointers with concrete addresses.
The code you posted
double** pvalue = NULL; // Pointer initialized with null
pvalue = new double [3][4]; // Allocate memory for a 3x4 array
does not work because there is no way it can deduct the offset of pvalue, though it looks very nice and clear.
I also paste the full testing code so you can have a play:
#include <stdio.h>
int main() {
double* pvalue = NULL;
pvalue = (double*)new double [3][4];
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 4; j++) {
*(pvalue+i*4+j) = (double)i*(double)j;
printf("%f\n", *(pvalue+i*4+j));
}
}
double (* parray)[4] = NULL;
parray = new double [3][4];
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 4; j++) {
parray[i][j] = (double)i*(double)j;
printf("%f\n", parray[i][j]);
}
}
double** ppvalue = NULL;
ppvalue = new double*[3];
for(int i =0; i<3; i++)
ppvalue[i]=new double[4];
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 4; j++) {
ppvalue[i][j] = (double)i*(double)j;
printf("%f\n", ppvalue[i][j]);
}
}
}
As the compiler explicitly told you, new double [3][4] evaluates to a pointer of double (*)[4] type
double (*pvalue)[4] = new double [3][4];
You can't store that value in a double ** pointer.
P.S. The "tutorial" you linked is just nonsensical garbage.
Related
I try to build a function which deletes the last element of an array. So I need an input array and its dimension, then delete the last term and obtain a new output array. I don't want that. My goal is to somehow make the output array the new input array. In other words, I want to overwrite the input array with the output array.
So if dimension is 4, I don't want to have a 4-dim array in the memory but only 3-dim table after the deletion.
void del (int* ptr_array, int dim) {
int* temp = ptr_array; //Hold the very first address of the input array.
ptr_array = new int[dim - 1]; // Let the address of the input array be
// the address of new output array. Overwritting.
for (int i = 0; i < dim - 1; i++) {
ptr_array = (temp+i); // Will it remember what is temp+1 if I have
// already overwritten the arrays?
ptr_array++;
}
//delete[] ptr_array; - this one is out of the questions - deletes now the input table.
}
Can you tell me what is wrong with this code? - in fact it doesn't change anything
in you function
for (int i = 0; i < dim - 1; i++) {
ptr_array = (temp+i); // Will it remember what is temp+1 if I have
// already overwritten the arrays?
ptr_array++;
}
does nothing, you wanted
for (int i = 0; i < dim - 1; i++) {
ptr_array[i] = temp[i];
}
Note the delete in your comment is invalid because you do not delete the result of a new[] but a pointer inside the allocated array
If the call is like
int * v = ...;
del(v);
// here v is unchanged
probably you wanted to modify v, in that case you can return the new array or to use an input-output variable using a reference
First possibility :
int* del (int* ptr_array, int dim) {
int* new_array = new int[dim - 1];
for (int i = 0; i < dim - 1; i++) {
new_array[i] = ptr_array[i];
}
delete[] ptr_array;
return new_array;
}
with
int * v = ...;
v = del(v);
Second possibility
void del (int*& ptr_array, int dim) {
int* new_array = new int[dim - 1];
for (int i = 0; i < dim - 1; i++) {
new_array[i] = ptr_array[i];
}
delete[] ptr_array;
ptr_array = new_array;
}
with
int * v = ...;
del(v);
// here v is the new array
Warning these codes suppose the input array has at least one element
However the use of an std::vector<int> does all of that for you and is more practical to use
std::vector<int> v;
...
v.resize(v.size() - 1);
or
std::vector<int> v;
...
v.pop_back();
I would like to allocate memory to store/manipulate data using a triple pointer. Given that I have to allocate the data at multiple points in my code, I implemented a function to do it. In the code below I give the implementation of this function and a simple main method that illustrates how I use this function in my code.
The code compile without error but when I run the program it crushes. I would appreciate your help to fix this problem.
EDIT: it crushes in the function AllocateMemory at the line
*data[i][j] = new double[x];
for i = 0 and j =1
Thank you.
int main()
{
int x = 2;
int y = 2;
int z = 2;
double*** data;//
AllocateMemory(&data, x, y, z);
//play with data
FreeMemory(data, x, y, z);
return 0;
}
void AllocateMemory(double**** data, int x, int y, int z)
{
*data = new double**[z];
for(int i = 0; i < z; i++)
{
*data[i] = new double*[y];
for(int j = 0; j < y; j++)
{
*data[i][j] = new double[x];
}
}
}
void FreeMemory(double*** data, int x, int y, int z)
{
for(int i = 0; i < z; i++)
{
for(int j = 0; j < y; j++)
{
delete [] data[i][j];
data[i][j] = NULL;
}
delete [] data[i];
data[i] = NULL;
}
delete [] data;
data = NULL;
}
Remember that array subscription has a higher precedence than dereference operator. Here:
*data[i] = new double*[y];
You're subscripting data and then dereferencing that pointer. data argument of AllocateMemory is not a pointer to an array, but instead to a single variable which is data in main. Therefore data[1] was never initialized and you get undefined behaviour. Given the context, you probably intended it the other way round:
(*data)[i] = new double*[y];
You have the same bug on the line *data[i][j] = new double[x];.
You could have avoided this either by using a reference parameter or - as I would recommend - by returning the pointer to the newly allocated array of pointers instead of passing it as an argument.
I want to have a function which initializes dynamic 2d arrays in cpp like below
void initArrays(int n,double **a,double **b,double **c) {
a = new double*[n];
for (int i = 0; i < n; i++)
a[i] = new double[n];
b = new double*[n];
for (int i = 0; i < n; i++)
b[i] = new double[n];
c = new double*[n];
for (int i = 0; i < n; i++)
c[i] = new double[n];
}
The function call completes but it does not initialize the pointers I give as function arguments.
For example if I call this function in the main
double **x,**y,**z;
initArrays(3,x,y,z);
I cannot access
x[0][0]
what am I doing wrong here?
The pointers stay uninitialized because you never assign them a value. The pointers in your init function are copies of the ones that you passed. You can pass the pointers by reference:
void initArrays(int n,double **&a,double **&b,double **&c)
That said, you'll probably be better off with std::vector.
CASE1:
int nrows=5;
int ncols=10;
int **rowptr;
rowptr=new int*;
for(int rows=0;rows<nrows;rows++) {
for(int cols=0;cols<ncols;cols++) {
*rowptr=new int;
}
}
CASE2:
int nrows=5;
int ncols=10;
int **rowptr;
for(int rows=0;rows<nrows;rows++) {
rowptr=new int*;
for(int cols=0;cols<ncols;cols++) {
*rowptr=new int;
}
}
I am able to insert and print values using both ways. What is the difference in initializations?
What is the difference?
#1 just allocates memory enough to hold a integer pointer and not an array of integer pointers.
#2 Causes a memory leak by just overwritting the memory allocation of the previous iteration.
I am able to insert and print values using both the ways
Memory leaks and Undefined behaviors may not produce immediate observale erroneous results in your program but they sure are good cases of the Murphy's Law.
The correct way to do this is:
int nrows = 5;
int ncols = 10;
//Allocate enough memory for an array of integer pointers
int **rowptr = new int*[nrows];
//loop through the array and create the second dimension
for (int i = 0;i < nrows;i++)
rowptr[i] = new int[ncols];
You have a memory leak in both cases.
The proper way to initialize such a "2d" array is
int** arr = new int*[nrows];
for (int i = 0; i < nrows; i++)
arr[i] = new int[ncols];
Note however, that it isn't a 2d array as defined by C/C++. It may not, and probably will not, be consecutive in memory. Also, the assembly code for accessing members is different.
In your case, the accessing by indexing is equivalent to *(*(arr+i)+j)
And in the case of a 2d array it's *(arr + N_COLS*i + j) when N_COLS is a compile time constant.
If you want a true 2d array you should do something like this:
int (*arr)[N_COLS] = (int(*)[N_COLS])(new int[N_ROWS * N_COLS])
You'd better use 1d array to manage 2d array
int **x = new int*[nrows];
x[0] = new int[nrows*ncols];
for (int i = 1; i < nrows; i++)
x[i] = x[i-1] + ncols;
for (int i = 0; i < nrows; i++)
for (int j = 0; j < ncols; j++)
x[i][j] = 0;
delete [] x[0];
delete [] x;
I have
main(){...
float **tree;
//How to set some values here for e.g. If I want tree to be a 15x2 array of some values?
reprVectorsTree *r1 = new reprVectorsTree(tree,8,2);
...}
reprVectorsTree(float **tree, int noOfReprVectors, int dimensions)
{.....
How to use malloc here so that I can set some data inside the tree array?
To allocate memory for tree, try something like:
float** tree;
tree = (float**)malloc(15 * sizeof(float*));
for(i = 0; i < 15; i++)
tree[i] = (float*)malloc(2 * sizeof(float));
Now you can set values:
for(i = 0; i < 15; i++)
for(j = 0; j < 2; j++)
tree[i][j] = 2;
Don't forget to free it later, although I don't understand why you are combining new and malloc together?
I guess it's the tree variable you want to allocate for.
You can do like this:
float **tree;
// Allocate 15 "arrays"
tree = new float*[15];
for (int i = 0; i < 15; i++)
{
// Allocate a new "array" of two floats
tree[i] = new float[2];
// Fill the newly allocated floats with "random" data
tree[i][0] = 1.0;
tree[i][1] = 2.0;
}
However, if it's possible I would recommend that you change the reprVectorsTree object to accept std::vector< std::vector< float > > instead.