Confusion about nested loops and array access - c++

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.

Related

Storing a 3D VLA on heap

I need to store an array on heap since I got a seg fault when running the program, due to it being too large. Normally this would be easy, but in this case it is a multidimensional array (3D specifically) and it's a variable length array too.
I tried to fit this answer for a 2D array (which I'm pretty sure works because I found it on another answer on SO) into one for a 3D array
int **ary = new int*[sizeY];
for(int i = 0; i < sizeY; ++i) {
ary[i] = new int[sizeX];
}
by doing this:
double **isoarray = new double*[nBinsX];
for(int xi = 0; xi < nBinsX; ++xi){
isoarray[xi] = new double[nBinsY];
for(int yi = 0; yi < nBinsY; ++yi){
isoarray[xi][yi] = new double[nShuffles];
}
}
Where I should mention that the array is meant to have dimensions nBinsX x nBinsY x nShuffles, but it isn't working, nor did I really think it would to be honest. Can anyone offer a suggestion on how I would do this? Thanks in advance!
Rather than heap-allocating arrays of pointers to more heap-allocated arrays and so on, you should make a single giant allocation and do appropriate indexing. This is a common technique:
double *isoarray = new double[nBinsX * nBinsY * nShuffles];
If you want to make a nice C++ solution out of it, store that pointer in a class which has an indexing method something like this:
double& at(x, y, shuffle) {
return isoarray[x * nBinsY * nShuffles + y * nShuffles + shuffle];
}
This way you have a single contiguous allocation which is better for performance when allocating, when using, and when deallocating. You can play with the indexing in terms of which dimension comes "first" to achieve even better performance depending on which way you usually traverse the data.

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.

Change OpenCL function to C++

I am trying to write a code in C++, but after some search on the internet, I found one OpenCL based code is doing exactly the same thing as I want to do in C++. But since this is the first time I see a OpenCL code, I don't know how to change the following functions into c++:
const __global float4 *in_buf;
int x = get_global_id(0);
int y = get_global_id(1);
float result = y * get_global_size(0);
Is 'const __global float4 *in_buf' equivalent to 'const float *in_buf' in c++? And how to change the above other functions? Could anyone help? Thanks.
In general, you should take a look at the OpenCL specification (I'm assuming it's written in OpenCL 1.x) to better understand functions, types and how a kernel works.
Specifically for your question:
get_global_id returns the id of the current work item, and get_global_size returns the total number of work items. Since an OpenCL work-item is roughly equivalent to a single iteration in a sequential language, the equivalent of OpenCL's:
int x = get_global_id(0);
int y = get_global_id(1);
// do something with x and y
float result = y * get_global_size(0);
Will be C's:
for (int x = 0; x < dim0; x++) {
for (int y = 0; y < dim1; y++) {
// do something with x and y
float result = y * dim0;
}
}
As for float4 it's a vector type of 4 floats, roughly equivalent to C's float[4] (except that it supports many additional operators, such as vector arithmetic). Of course in this case it's a buffer, so an appropriate type would be float** or float[4]* - or better yet, just pack them together into a float* buffer and then load 4 at a time.
Feel free to ignore the __global modifier.
const __global float4 *in_buf is not equivalent to const float *in_buf.
The OpenCL uses vector variables, e.g. floatN, where N is e.g. 2,4,8. So float4 is in fact struct { float w, float x, float y, float z} with lot of tricks available to express vector operations.
get_global_id(0) gives you the iterator variable, so essentially replace every get_global_id(dim) with for(int x = 0; x< max[dim]; x++)

Setting pointer to a double array in for loop

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.

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.