Setting pointer to a double array in for loop - c++

I have an algorithm that I want to run that uses a potentially long double array. Because the array can be millions in length, I'm putting it on the GPU so I need to export the array from a CPP file to a CU file. However, Im prototyping it in CPP only for now because it doesnt work in either case.
In my CPU prototype I get errors when I try to set the members of the double array with my for loop. For example, any operation including cout will give error c2109:subscript requires array or pointer type in the CPP file
or if the same code is run from a CU file, error: expression must have a pointer-to-object type
const int size = 100000;
double inputMeshPts_PROXY[size][4];
inputMeshPts.get(inputMeshPts_PROXY);
int lengthPts = inputMeshPts.length();
if (useCUDA == 1)
{
double *inputMeshPts_CUDA = &inputMeshPts_PROXY[size][4];
myArray(lengthPts, inputMeshPts_CUDA);
}
MStatus abjBlendShape::myArray(int length_CUDA, float weight_CUDA, double *inputMeshPts_CUDA)
{
for (int i = 0; i < length_CUDA; i++)
{
for (int j = 0; j < 3; j++)
{
cout << inputMeshPts_CUDA[i][j] << endl;
// inputMeshPts_CUDA[i][j] += (sculptedMeshPts_PROXY[i][j] - inputMeshPts_CUDA[i][j]); // WHAT I WANT, EVENTUALLY
}
}
}

When you are writing:
double *inputMeshPts_CUDA = &inputMeshPts_PROXY[size][4];
The variable inputMeshPts_CUDA is a pure pointer. You cannot use 2-dimensional indexing [][] as before. The right way to access it is now to linearize the indexes:
inputMeshPts_CUDA[i*4+j]
Alternatively you could declare "correctly" your pointer:
double (*inputMeshPts_CUDA)[4] = inputMeshPts_PROXY;
which allows you to use the 2-dimensional indexing again.

MStatus abjBlendShape::myArray(int length_CUDA, float weight_CUDA, double *inputMeshPts_CUDA)
{
inputMeshPts_CUDA is just a pointer, the compiler has lost all the dimension information. It needs that dimension information for inputMeshPts_CUDA[i][j], which gets converted to an access to address (byte arithmetic, not C++ pointer arithmetic)
inputMeshPts_CUDA + i * sizeof (double) * num_colums + j * sizeof (double)
You can either provide the missing information yourself and do the arithmetic like Angew suggests, or have the compiler pass the dimension information through:
template<size_t M, size_t N>
MStatus abjBlendShape::myArray(int length_CUDA, float weight_CUDA, double (&inputMeshPts_CUDA)[M][N])
Of course, this only works when the size is known at compile-time.

inputMeshPts_CUDA is a pointer to double - that is, it can represent a 1D array. You're accessing it as a 2D array: inputMeshPts_CUDA[i][j]. That doesn't make sense - you're effectively applying [j] to the double object storead at inputMeshPts_CUDA[i].
I believe you were looking for inputMeshPts_CUDA[i * 4 + j] - you have to compute the 2D addressing yourself.

Related

Unable to access the elements of a pointer to an array

I have a following array which I am passing as a pointer. BTW, I am new to C++ and just started pointers.
int arr[3][4]= {{2,3,4,8},{5,7,9,12},{1, 0, 6, 10}};
//int *a = &arr[0][0];
BuildStringFromMatrix((int *)arr, 3, 4);
I have a a following function with which I wanna access the elements of the passed array.
void BuildStringFromMatrix(int *a, int height, int width);
My implementation of the accessing the element is as follows
for(int i=0; i<height; i++){
for(int j=0; i<width; j++){
int x = *(*(a+i) + j);
std::cout<<x;
}
}
While using this implementation I am getting an error
invalid type argument of unary β€˜*’ (have β€˜int’
)
int x = *(*(a+i) + j);
How can I fix this issue.
P.S - I wanna implement this using single pointer.
Your function receives a pointer to int. It doesn't "remember" that it is actually pointing to an int that is in a 2-D array (let alone what the array dimensions are).
So if you want to access a certain element of the 2-D array you must perform a calculation to find how many units to offset from the pointer to get to the intended element. (This is sometimes called "flattening an array").
Typically row * row_length + column is the offset for a particular row-column entry, so in your case int x = a[i*width + j]; is the right statement to use.
If this is still unclear I suggest printing out the value of i*width+j at each iteration and seeing how it iterates over the array (or follow in your debugger).

Converting linear array to a bidimensional array of structs using pointers

EDIT: I will improve this question. I will clarify it right in a little days.
first, I am writing a litlle bmp image analyzer. I have the following problem: The image is stored on plain bytes, without format as an array.
The image is 24 bits, and requires 3 bytes per pixel. I have tried with a solution that I have found on this stackoverflow page, but I can not adapt it for structures.
I have tried but it references invalid areas and bytes. Here's my complete code if you want to see it in TinyPaste (just for a better highlighting): The code in TinyPaste
EDIT 1: This code is in C++, I want to translate it to pure C for portability reasons. This is just the example from I taken the idea of convert a linear array to bidimensional. I have tried to adapt it to pure C for structs but I fail.
This snippet was taken from a stackoverflow question that made me think about this
//The resulting array
unsigned int** array2d;
// Linear memory allocation
unsigned int* temp = new unsigned int[sizeX * sizeY];
// These are the important steps:
// Allocate the pointers inside the array,
// which will be used to index the linear memory
array2d = new unsigned int*[sizeY];
// Let the pointers inside the array point to the correct memory addresses
for (int i = 0; i < sizeY; ++i)
{
array2d[i] = (temp + i * sizeX);
}
// Fill the array with ascending numbers
for (int y = 0; y < sizeY; ++y)
{
for (int x = 0; x < sizeX; ++x)
{
array2d[y][x] = x + y * sizeX;
}
}
I adapt it to reference structs, but it fails. I have tried multiplying by three in this line:
array2d[i] = (temp + i * sizeX /* multiply by 3*/);
But it still without work. I have also done the related castings from char to the struct bmp_pixel(char r, char g, char b).
Can somebody tell me how to adapt it to pure C for structs?? Thanks.

how to assign two 2d array

I have written a program which make a 2d array and then set its numbers.
The second step that I have problem in it is that when I want to shift rows and columns I face with a problem in this line nmatrix[i*c+j] = 0;
the error is this : error: incompatible types in assignment of 'int' to 'int [(((sizetype)(((ssizetype)(c + shiftc)) + -1)) + 1)]'
here is the code :
void shiftMatrix(int *matrix, int r,int c ,int shiftr,int shiftc){
int nmatrix [r+shiftr][c+shiftc];
for(int i = 0; i< shiftr; i++)
{
for(int j = 0; j<shiftc;j++)
{
nmatrix[i*c+j] = 0;
}
}
for(int i = shiftr; i< r; i++)
{
for(int j = shiftc; j<c;j++)
{
nmatrix[i*c+j] = matrix[i*c+j];
}
}
}
Any help please??
thanks in advance
int nmatrix [r+shiftr][c+shiftc];
First of all, you are using an array with non-constant bounds, which is a controversial feature.
In addition, here you are declaring a two-dimensional array nmatrix, but your other matrix (matrix) is a pointer to int (or a one-dimensional array, if you like to look at it this way). This is a recipe for confusion.
You can easily declare nmatrix ("new matrix"?) as a one-dimensional array:
int nmatrix[(r+shiftr) * (c+shiftc)];
Or (presumably better)
std::vector<int> nmatrix((r+shiftr) * (c+shiftc));
Then, your code nmatrix[i*c+j] = 0 will work (however, you have to change c to c+shiftc whenever you work with nmatrix).
You cannot define an array dynamically the way you do it.
You need to use the c++ keyword new:
int nmatrix[][] = new int [r+shiftr][c+shiftc];
You cannot define arrays the way you did, with non constant int value for dimension, because such static arrays are to be defined for memory at the compile stage. Thus dimensions should be const expression.
On the contrary with keyword new you can define dimensions for arrays at run-time stage, because it's dynamic allocation.
There are more detailed answers in this SO question here.

Dynamically allocating 2D int array

Can someone please point out what I am doing wrong in the following code?
int* a = NULL;
int* b = NULL;
a = new int[map->mapSize.width];
b = new int[map->mapSize.height];
layer->tileGids = new int[a][b];
Here's what the code uses:
typedef struct _size {
int width, height;
} size;
class Map {
size mapSize;
}
class Layer {
int * tileGids;
}
EDIT: Compiler-Errors (in line 6 of the first bit of code):
error: expression in new-declarator must have integral or enumeration type|
error: 'b' cannot appear in a constant-expression|
Solution:
I have decided to accept lightalchemist's answer. In essence, what works for me is use a vector instead of the array. Vector manages the memory for you and hence is a lot easier to deal with.
You can't pass a pointer for initializing the size of an array. Others have now mentioned this.
This post (it's not mine) seems like it might help you: http://eli.thegreenplace.net/2003/07/23/allocating-multi-dimensional-arrays-in-c/
You should also consider doing the allocation in the class Layer's constructor and then deleting the memory in it's destructor (i.e. RAII - resource acquisition is initialization). This is considered good style.
Finally, you might consider using continuous memory and a custom indexing scheme, which you could easily use Layer to encapsulate. This of course depends upon how big things will get. The bigger they get the better the case for continuous memory becomes.
This should give you a flavor.
#include <iostream>
#include <cstdlib>
int main()
{
const size_t ROWS = 5;
const size_t COLS = 2;
const size_t size = ROWS*COLS;
int* arr = new int[size];
int i = 0;
for ( size_t r = 0 ; r < ROWS; ++r )
{
for (size_t c = 0; c < COLS; ++c )
{
arr[r*COLS+c] = i++;
}
}
for ( int j = 0; j < i; ++j)
{
std::cout << arr[j] << std::endl;
}
delete [] arr;
}
Firstly, your variables "a" and "b" are pointers. Your code:
layer->tileGids = new int[a][b]
is the root cause of the problem.
I'm trying to guess your intention here and I think what you are trying to do is make layer.tileGids a 2 dimension array to reference a "grid" of size (mapSize.Width, mapSize.height) so that you can refer to each "cell" in the grid using layer.tileGids[x][y].
If you are indeed trying to create a 2 dimension array, there are 2 methods to do it.
Method 1:
class Layer {
int ** tileGids; // NOTE the "**" to indicate tileGids is a pointer to pointer i.e. 2D array.
}
To initialize it:
int width = map->mapSize.width;
int height = map->mapSize.height;
layer.tileGids = new int*[width]; // NOTE the "int*" to indicate tileGids is a new array of pointers to int.
for (int i = 0; i < width; i++) // Initialize each element in layer.tileGids[] to be a pointer to int.
{
layer.tileGids[i] = new int[height];
}
Now you can access the items in layer.tileGids using:
int value = layer.tileGids[x][y] // where 0 <= x < width and 0 <= y < height
To deallocate this data structure, similar to how you allocate it, you need to deallocate each dynamically allocated array in each "row":
for (int i = 0; i < width; i++)
{
delete [] layer.tileGids[i]; // Deallocate each row.
}
delete [] layer.tileGids; // Deallocate "array" to the pointers itself.
Method 2:
Now another easier, less messy method (avoid pointers) is to use the C++ vector class. You need to make the following changes:
#include <vector>
class Layer {
vector<vector<int> > tileGids; // Note the space at "<int> >".
}
To initialize:
int width = map->mapSize.width;
int height = map->mapSize.height;
layer.tileGids = vector<vector<int> >(width, vector<int>(height, 0)); // Initialize all entries to 0.
To access the elements:
int value = layer.tileGids[x][y]; // Where 0 <= x < width and 0 <= y < height
Note that for the second method using vectors, you do not have to do any memory cleanup as is required in the first method because the vector will automatically take care of it. However, because a vector can grow dynamically i.e. you can add items to it, you lose the safety of having a fixed size array i.e. someone could accidentally increase the size of your grid if you use the vector method but if he tries to do that when you intialized it using the first method above an error will occur and you will immediately know that something is wrong.
Can someone please point out what I am doing wrong in the following code?
A lot. You're allocating two single arrays (a "row array" and a "column array", not what you need), and then you try to do something strange.
Generally you can't (strictly speaking) dynamically allocate a 2D array in C++ (because the type system would still need the type, along with the dimensions, to be known at compile time). You can emulate it with an array of arrays or so, but the best way is to allocate an 1D array:
int width=5;
std::vector<int> tab(width*height);
and then access the element by calculating the coordinates manually:
// access the element (1,2)
tab[1 + 2*width] = 10;
This way you're essentially interpreting a 1D array as a 2D array (with performance equal to static 2D arrays).
Then it's best to wrap the indexing with a class for convenience; boost::multi_array also has this done for you already.
a and b are int* here:
layer->tileGids = new int[a][b];
Perhaps you meant to say this?
layer->tileGids = new int[*a][*b];

Confusion about nested loops and array access

I have some C++ I'm trying to port, and I'm confused about a couple lines and what exactly they're doing. The code is as follows. The variable im is a 2D float array of size num_rows by num_cols.
for(x=0; x < num_cols; x++){
float *im_x_cp = im[1]+x; //(1)
for(y = 1; y < num_rows; y++, im_x_cp+=num_cols){
float s1 = *im_x_cp;
//et cetera
}
}
The code marked (1) is particularly confusing to me. What part of the 2d array im is this referencing?
Thanks for your help in advance.
im[1] is a pointer to an array of floats, that is, it's the second line/column of your matrix.
im[1] + x is a pointer to the element at coordinate (1,x) (recall how pointer arithmetic works) and s1 is its value.
The type of im[1] is float *. So, according to the rules of C++ pointer arithmetic:
float* im_x_cp = im[1];
im_x_cp = im_x_cp + x;
Now it's a float* pointing to item '1+x' in that slice.