I have a function which searches for extrema in some data array. It takes pointer to data, some parameters and a pointer to struct array where the result is stored. The function returns the length of the resulting struct array.
int FindPeaks(float *data, int WindowWidth, float threshold, struct result *p)
{
int RightBorder = 0;
int LeftBorder = 0;
bool flag = 1;
int i = 0;
int k = 0;
while(1)
{
flag = 1;
if (WindowWidth >= 200) cout << "Your window is larger than the signal! << endl";
if (i >= 200) break;
if ((i + WindowWidth) < 200) RightBorder = i + WindowWidth;
if ((i - WindowWidth) >= 0) LeftBorder = i - WindowWidth;
for(int j = LeftBorder; j <= RightBorder; j ++)
{
if (*(data + i) < *(data + j))
{
flag = 0;
break;
}
}
if (flag && *(data + i) >= threshold && i != 0 && i != 199)
{
struct result pointer = p + k;
pointer.amplitude = *(data + i);
pointer.position = i;
i = i + WindowWidth;
k++;
}
else
{
i ++;
}
}
return k;
}
I'm confused with a reference to i-th struct field to put the result in there. Am I doing something wrong?
You're trying to be too smart with use of pointers, so your code won't even compile.
Instead of using *(data + i) or *(data+j) everywhere, use data[i] or data[j]. They're equivalent, and the second is often more readable when working with an array (assuming the data passed by the caller is actually (the address of the first element of) an array of float).
The problem you asked about is this code
struct result pointer = p + k;
pointer.amplitude = *(data + i);
pointer.position = i;
where p is a pointer to struct result passed to the function as argument. In this case, pointer actually needs to be a true pointer. Assuming you want it to point at p[k] (rather than creating a separate struct result) you might need to do
struct result *pointer = p + k; /* equivalently &p[k] */
pointer->amplitude = data[i];
pointer->position = i;
This will get the code to compile. Note that you have not described what the function is actually supposed to achieve, so I have not bothered to check if the code actually does anything sensible.
Note that you're actually (mis)using C techniques in C++. There are much better alternatives in modern C++, such as using standard containers.
Related
I am currently building a median filter in C++. I have a decent amount of experience with other languages but C++ and its pointers confuse me. I am building a function which takes in a 2D array of RGB values of an image. The function may not be 100% yet but I just cannot get past returning the 2d array. My input parameters is the row major version of the image array and the filter size and the output is the pointer to the filtered 2D array. It has the following error when debugging >"Cannot convert 'int (*)[size]' to 'int"
Can you possibly walk me through this error and how to deal with it?
Also if you spot any other peculiarities please mention it, it would be greatly appreciated!
int** seq_medFilter(int image[][3], int filter)
{
int output[640 * 480][3];
int rows = 640;
int cols = 480;
int fil_arr_size = pow((2 * filter + 1), 2);
for (int i = 0; i<rows*cols; ++i)
{
int temp[fil_arr_size][3];
//edge cases excluded
int current_col = i / cols;
int current_row = i%cols;
if (current_col < filter || current_col > cols - filter - 1 || current_row < filter || current_row > rows - filter - 1)
{
for (int j = 0; j<3; j++) {
output[i][j] = image[i][j];
}
}
else
{
// just for a filter size of one now
int pos_x = i / cols - filter;
int pos_y = i%cols - filter;
for (int x = 0; x< fil_arr_size - 1; ++x)
{
for (int j = 0; j<3; j++) {
temp[x][j] = image[pos_x*cols + pos_y][j];
}
pos_x += 1;
if (pos_x == (2 * filter + 1))
{
pos_x = pos_x - (2 * filter + 1);
pos_y += 1;
}
}
int N = sizeof(temp) / sizeof(temp[0]);
sort(temp, temp + N);
for (int j = 0; j<3; j++) {
output[i][j] = temp[N / 2][j];
}
}
}
return output;
}
int main()
{
return 0;
}
The issue is that you cannot return a int output[][] as an int **. They are considered different types, but also, output is a local variable, and thus cannot be returned as a pointer without causing UB.
You could use a vector instead, like so:
std::vector<std::vector<int>> seq_medFilter(int image[][3], int filter)
{
std::vector<std::vector<int>> output( 640 * 480, std::vector<int>( 3 ) );
//...
If you insist on using pointers, then you can used unique_ptr/shared_ptr, or use new, though I would say that all three of these options are worse than just using a vector here.
You could also use an std::array
Example:
std::array<std::array<int, 3>, 640*480> seq_medFilter(int image[][3], int filter)
Then, where you declare output, you would change its type to
std::array<std::array<int, 3>, 640*480> output;
Note that the line:
int temp[fil_arr_size][3];
Is not valid in standard C++ (see here).
For completeness, using the pointer method, you would keep your function head the same, but then use:
int **output = new int*[640*480];
for ( size_t idx = 0; idx < 640*480; ++idx ) {
output[idx] = new int[3];
}
Again, I don't recommend this method.
I am working with a dynamic square 2D array that I sometimes need to enlarge for my needs. The enlarging part consist in adding a new case on each border of the array, like this:
To achieve this, I first copy the content of my actual 2D array in a temporary other 2D array of the same size. Then I create the new 2D array with the good size, and copy the original content of the array in the middle of the new one.
Is there any quick way to copy the content of the old array in the middle of my new array? The only way I have found so far is only by using two for sections:
for(int i = 1; i < arraySize-1; i++)
{
for(int j = 1; j < arraySize-1; j++)
{
array[i][j] = oldArray[i-1][j-1];
}
}
But I'm wondering if there is no quicker way to achieve this. I thought about using std::fill, but I don't see how it would be possible to use it in this particular case.
My EnlargeArray function:
template< typename T >
void MyClass<T>::EnlargeArray()
{
const int oldArraySize = tabSize;
// Create temporary array
T** oldArray = new T*[oldArraySize];
for(int i = 0; i < oldArraySize; i++)
{
oldArray[i] = new T[oldArraySize];
}
// Copy old array content in the temporary array
for(int i = 0; i < arraySize; i++)
{
for(int j = 0; j < arraySize; j++)
{
oldArray[i][j] = array[i][j];
}
}
tabSize+=2;
const int newArraySize = arraySize;
// Enlarge the array
array= new T*[newArraySize];
for(int i = 0; i < newArraySize; i++)
{
array[i] = new T[newArraySize] {0};
}
// Copy of the old array in the center of the new array
for(int i = 1; i < arraySize-1; i++)
{
for(int j = 1; j < arraySize-1; j++)
{
array[i][j] = oldArray[i-1][j-1];
}
}
for(int i = 0; i < oldArraySize; i++)
{
delete [] oldArray[i];
}
delete [] oldArray;
}
Is there any quick way to copy the content of the old array in the middle of my new array?
(Assuming the question is "can I do better than a 2D for-loop?".)
Short answer: no - if your array has R rows and C columns you will have to iterate over all of them, performing R*C operations.
std::fill and similar algorithms still have to go through every element internally.
Alternative answer: if your array is huge and you make sure to avoid
false sharing, splitting the copy operation in multiple threads that deal with a independent subset of the array could be beneficial (this depends on many factors and on the hardware - research/experimentation/profiling would be required).
First, you can use std::make_unique<T[]> to manage the lifetime of your arrays. You can make your array contiguous if you allocate a single array of size row_count * col_count and perform some simple arithmetic to convert (col, row) pairs into array indices. Then, assuming row-major order:
Use std::fill to fill the first and last rows with zeros.
Use std::copy to copy the old rows into the middle of the middle rows.
Fill the cells at the start and end of the middle rows with zero using simple assignment.
Do not enlarge the array. Keep it as it is and allocate new memory only for the borders. Then, in the public interface of your class, adapt the calculation of the offets.
To the client of the class, it will appear as if the array had been enlarged, when in fact it wasn't really touched by the supposed enlargement. The drawback is that the storage for the array contents is no longer contiguous.
Here is a toy example, using std::vector because I cannot see any reason to use new[] and delete[]:
#include <vector>
#include <iostream>
#include <cassert>
template <class T>
class MyClass
{
public:
MyClass(int width, int height) :
inner_data(width * height),
border_data(),
width(width),
height(height)
{
}
void Enlarge()
{
assert(border_data.empty()); // enlarge only once
border_data.resize((width + 2) * 2 + (height * 2));
width += 2;
height += 2;
}
int Width() const
{
return width;
}
int Height() const
{
return height;
}
T& operator()(int x, int y)
{
assert(x >= 0);
assert(y >= 0);
assert(x < width);
assert(y < height);
if (border_data.empty())
{
return inner_data[y * width + x];
}
else
{
if (y == 0)
{
return border_data[x]; // top border
}
else if (y == height - 1)
{
return border_data[width + x]; // bottom border
}
else if (x == 0)
{
return border_data[width + height + y]; // left border
}
else if (x == width - 1)
{
return border_data[width * 2 + height * 2 + y]; // right border
}
else
{
return inner_data[(y - 1) * (width - 2) + (x - 1)]; // inner matrix
}
}
}
private:
std::vector<T> inner_data;
std::vector<T> border_data;
int width;
int height;
};
int main()
{
MyClass<int> test(2, 2);
test(0, 0) = 10;
test(1, 0) = 20;
test(0, 1) = 30;
test(1, 1) = 40;
for (auto y = 0; y < test.Height(); ++y)
{
for (auto x = 0; x < test.Width(); ++x)
{
std::cout << test(x, y) << '\t';
}
std::cout << '\n';
}
std::cout << '\n';
test.Enlarge();
test(2, 0) = 50;
test(1, 1) += 1;
test(3, 3) = 60;
for (auto y = 0; y < test.Height(); ++y)
{
for (auto x = 0; x < test.Width(); ++x)
{
std::cout << test(x, y) << '\t';
}
std::cout << '\n';
}
}
Output:
10 20
30 40
0 0 50 0
0 11 20 0
0 30 40 0
0 0 0 60
The key point is that the physical representation of the enlarged "array" no longer matches the logical one.
I would like to pass a character array micPointsChar[] to a function initMicPoints() and parse it into a multi-dimensional array micPoints. I am able to successfully do this using a one dimensional array:
char micPointsChar[30 + 1] = {};
float *initMicPoints(char micPointsChar[], float micPoints[3]);
int main()
{
// Read in mic points from file
char micPointsChar[40] = "2,3.343,4.432\n";
float micPoints[3] = {};
float *newMicPoints = initMicPoints(micPointsChar, micPoints);
for (int i = 1; i <= 3; i++)
{
Serial.print(newMicPoints[i]);
Serial.print("\n");
}
return 0;
}
float *initMicPoints(char micPointsChar[], float micPoints[3])
{
static int i = 1;
static int micNum = 1;
static int numMics = 1;
float coordinateDec = 0;
char *coordinate = strtok(micPointsChar, ",\n");
coordinateDec = atof(coordinate);
while (micNum <= numMics)
{
while (i <= ((micNum * 3)) && (coordinate != NULL))
{
if (i == ((micNum * 3) - 2))
{
micPoints[1] = coordinateDec;
}
else if (i == ((micNum * 3) - 1))
{
micPoints[2] = coordinateDec;
}
else if (i == ((micNum * 3) - 0))
{
micPoints[3] = coordinateDec;
}
coordinate = strtok(NULL, ",\n");
coordinateDec = atof(coordinate);
i++;
}
micNum++;
}
return micPoints;
}
This outputs the expected:
2.00
3.34
4.43
However, when I change my code to handle a multidimensional array, micPoints[360][3]:
char micPointsChar[30 + 1] = {};
float *initMicPoints(char micPointsChar[], float micPoints[360][3]);
int main()
{
// Read in mic points from file
char micPointsChar[40] = "2,3.343,4.432\n";
float micPoints[360][3] = {};
float *newMicPoints = initMicPoints(micPointsChar, micPoints);
static int i = 0;
for (i = 1; i <= 3; i++)
{
Serial.print(*newMicPoints[i][0]);
Serial.print("\n");
Serial.print(*newMicPoints[i][1]);
Serial.print("\n");
Serial.print(*newMicPoints[i][2]);
Serial.print("\n");
}
return 0;
}
float *initMicPoints(char micPointsChar[], float micPoints[360][3])
{
static int i = 1;
static int micNum = 1;
static int numMics = 1;
float coordinateDec = 0;
char *coordinate = strtok(micPointsChar, ",\n");
coordinateDec = atof(coordinate);
while (micNum <= numMics)
{
while (i <= ((micNum * 3)) && (coordinate != NULL))
{
if (i == ((micNum * 3) - 2))
{
micPoints[i][0] = coordinateDec;
}
else if (i == ((micNum * 3) - 1))
{
micPoints[i][1] = coordinateDec;
}
else if (i == ((micNum * 3) - 0))
{
micPoints[i][2] = coordinateDec;
}
coordinate = strtok(NULL, ",\n");
coordinateDec = atof(coordinate);
i++;
}
micNum++;
}
return micPoints;
}
I receive a compile time error of:
cannot convert 'float (*)[3]' to 'float*' in return
Am I making this too complicated? What is the best way to return a multidimensional array?
Firstly, unfortunately
float *initMicPoints(char micPointsChar[], float micPoints[360][3])
is seen as
float *initMicPoints(char* micPointsChar, float (*micPoints)[3])
you may pass by reference to keep the size:
float *initMicPoints(char* micPointsChar, float (&micPoints)[360][3])
Then as you return micPoints
return type should be float (&)[360][3] or float (&)[360][3]
which give an ugly
float (&initMicPoints(char* micPointsChar, float (&micPoints)[360][3]))[360][3]
and at the call site:
float (&newMicPoints)[360][3] = initMicPoints(micPointsChar, micPoints);
Prefer std::array or std::vector with cleaner syntax.
In both cases you are just returning the parameter. So this return value is redundant. Instead, avoid the problem by returning void:
void initMicPoints(char micPointsChar[], float micPoints[360][3])
The calling code would look like:
float micPoints[360][3] = {};
initMicPoints(micPointsChar, micPoints);
for (int i = 1; i <= 3; i++)
{
Serial.print(micPoints[i][0]);
Serial.print("\n");
etc. You could make another variable float (*newMicPoints)[3] = micPoints; if you want but this would also be redundant.
There is little point in returning the array, because your function hasn't constructed it. You're just giving the caller a copy of the argument value.
A few traditional functions in the standard C library do this, like strcpy. I can't remember the last time I saw a piece of code which used the return value of strcpy, which is just the destination pointer that was passed in.
// redeclare and redefine to return nothing!
void initMicPoints(char micPointsChar[], float micPoints[3]);
int main()
{
// Read in mic points from file
char micPointsChar[40] = "2,3.343,4.432\n";
float micPoints[3] = {};
initMicPoints(micPointsChar, micPoints);
for (int i = 1; i <= 3; i++)
{
Serial.print(micPoints[i]); // refer to original array, now initialized
Serial.print("\n");
}
return 0;
}
Fact is that initMicPoints clobbers the array that is passed in, which is why you called it init. There is little use in capturing a pointer, and then ignoring the original array that you have in scope. That just dresses up imperative code to look functional, without the underlying semantics.
In the above code we can turn the array two dimensional, without the return value type issue cropping up; we eliminated it.
How do I access a three-dimensional array via pointers? At the moment I have this code, trying to get the same results. I need the access via pointers to use the values in the array in OpenCL.
for (l = 0; l < NumberOfLayers - 1; l++) {
for (i = 0; i < NeuronsPerLayer[l]; i++) {
for (j = 0; j < NeuronsPerLayer[l + 1] - bias[l + 1]; j++) {
cout<<Synweights[l][i][j]<<endl;
cout<<*(*Synweights[0]+l*NumberOfLayers + i * NeuronsPerLayer[l] + j)<<endl;
}
}
}
Synweights is declared as:
double ***Synweights
Synweights = (double ** *)malloc((NumberOfLayers - 1) * sizeof(double **));
for (l = 0; l < NumberOfLayers - 1; l++) {
Synweights[l] = (double **)malloc(NeuronsPerLayer[l] * sizeof(double *));
for (i = 0; i < NeuronsPerLayer[l]; i++) {
Synweights[l][i] = (double *)malloc((NeuronsPerLayer[l + 1] - bias[l + 1]) * sizeof(double));
}
}
It depends on the structure of your arrays.
Synweights is an array of arrays of arrays which means there are many memory blocks at different locations. If you have a pointer to such a structure you can do the very same with a pointer:
float p*** = new float**[sizeL];
for(int l=0; l<sizeL; ++l)
{
p[l] = new float*[sizeI];
for(int i=0; i<sizeI; ++i)
p[l][i] = new float[sizeJ];
}
...
p[l][i][j] = 0; // Access
In case you have just on block of memory which is interpreted as 3D array you need to do some arithmetic. This should be the case you need for CpenCL anyway.
float* p = new float[sizeL*sizeI*sizeJ];
...
p[(l*sizeI+i)*sizeJ+j] = 0; // Access
p + ((l*sizeI+i)*sizeJ+j); // Direct address/pointer calculation
This variant is faster due to cache performance and less address computations. You can store the computed index if you intend to access more than once.
A three dimensional array may be accessed in the following way;
T* myArray = new T[3][4][5];
T* aParticularT = myArray[1][2][2];
T* anArrayOfTs = myArray[1][2];
T* aTwoDimensionalArrayOfTs = myArray[1];
T* aThreeDimensionalArrayOfTs = myArray;
aTypeName aMemberOfT = aParticularT->memberName;
We are writing a method (myFunc) that writes some data to the array. The array must be a field of the class (MyClass).
Example:
class MyClass {
public:
MyClass(int dimension);
~MyClass();
void myFunc();
protected:
float* _nodes;
};
MyClass::MyClass(int dimension){
_nodes = new float[dimension];
}
void MyClass::myFunc(){
for (int i = 0; i < _dimension; ++i)
_nodes[i] = (i % 2 == 0) ? 0 : 1;
}
The method myFunc is called near 10000 times and it takes near 9-10 seconds (with other methods).
But if we define myFunc as:
void MyClass::myFunc(){
float* test = new float[_dimension];
for (int i = 0; i < _dimension; ++i)
test[i] = (i % 2 == 0) ? 0 : 1;
}
our programm works much faster - it takes near 2-3 seconds (if it's calles near 10000 times).
Thanks in advance!
This may help (in either case)
for (int i = 0; i < _dimension; )
{
test[i++] = 0.0f;
test[i++] = 1.0f;
}
I'm assuming _dimension is even, but easy to fix if it is not.
If you want to speed up Debug-mode, maybe help the compiler, try
void MyClass::myFunc(){
float* const nodes = _nodes;
const int dimension = _dimension;
for (int i = 0; i < dimension; ++i)
nodes[i] = (i % 2 == 0) ? 0.0f : 1.0f;
}
Of course, in reality you should focus on using Release-mode for everything performance-related.
In your example code, you do not initialise _dimension in the constructor, but use it in MyFunc. So you might be filling millions of entries in the array even though you have only allocated a few thousand entries. In the example that works, you use the same dimension for creating and filling the array so you are probably initialising it correctly in that case..
Just make sure that _dimension is properly initialised.
This is faster on most machine.
void MyClass::myFunc(){
float* const nodes = _nodes;
const int dimension = _dimension;
if(dimension < 2){
if(dimension < 1)
return;
nodes[0] = 0.0f;
return;
}
nodes[0] = 0.0f;
nodes[1] = 1.0f;
for (int i = 2; ; i <<= 1){
if( (i << 1) < dimension ){
memcpy(nodes + i, nodes, i * sizeof(float));
}else{
memcpy(nodes + i, nodes, (dimension - i) * sizeof(float));
break;
}
}
}
Try this:
memset(test, 0, sizeof(float) * _dimension));
for (int i = 1; i < _dimension; i += 2)
{
test[i] = 1.0f;
}
You can also run this piece once and store the array at static location.
For each consecutive iteration you can address the stored data without any computation.