Assigning the function output to a variable - c++

I have a function which returns the address of a 4x2 matrix whose name is 'a'.
This function computes the elements of 'a' matrix inside and returns the address of the matrix. When I use that function, I want to assign its output to a matrix called 'a1' but when I do so, 'a1' becomes a zero matrix. However, when I assign the output to the same 'a' matrix, everything works fine. Can anyone help me? The code is written on Arduino IDE.
double a[4][2], a1[4][2];
double T0E[4][4]={
{0.1632, -0.3420, 0.9254, 297.9772},
{0.0594, 0.9397, 0.3368, 108.4548},
{-0.9848, 0, 0.1736, -280.5472},
{0, 0, 0, 1}
};
const int axis_limits[4][2]=
{
{ -160, 160 },
{ -135, 60 },
{ -135, 135 },
{ -90, 90 }
};
const unsigned int basex = 50, basez = 100, link1 = 200, link2 = 200, link3=30, endeff=link3+50;
double *inversekinematic(double target[4][4])
{
// angle 1
a[0][0] = -asin(target[0][1]);
a[0][1] = a[0][0];
if (a[0][0]<axis_limits[0][0] || a[0][0]>axis_limits[0][1] || isnan(a[0][0]))
{
bool error=true;
}
// angle 2
double A = sqrt(pow(target[0][3]-cos(a[0][0])*endeff*target[2][2], 2) + pow(target[1][3]-sin(a[0][0])*endeff*target[2][2], 2));
double N = (A - basex) / link1;
double M = -(target[2][3]-endeff*target[2][0] - basez) / link2;
double theta = acos(N / sqrt(pow(N, 2) + pow(M, 2)));
a[1][0] = theta + acos(sqrt(pow(N, 2) + pow(M, 2)) / 2);
a[1][1] = theta - acos(sqrt(pow(N, 2) + pow(M, 2)) / 2);
// angle 3
for (int i = 0; i <= 1; i++)
{
a[2][i] = {asin(-(target[2][3]-endeff*target[2][0]-basez)/link2-sin(a[1][i]))-a[1][i]};
}
// angle 4
for(int i = 0; i <=1; i++)
{
a[3][i] = {-asin(target[2][0])-a[1][i]-a[2][i]};
}
return &a[4][2];
}
void setup(){
Serial.begin(9600);
}
void loop() {
a1[4][2]={*inversekinematic(T0E)};
}

When you type return &a[4][2]; you are returning the address of the 3rd element of the 5th row. This is out of bounds, since C++ uses zero-based indexing and the array was declared as double a[4][2];. I think what you want to do is just return a; to return the address of the entire matrix.
Also, you're doing lots of strange things like declaring the parameter double target[4][4] with a size and using initializer lists to assign single elements, which look unusual to me.
I'll try to be a little more detailed. In C/C++, arrays are nothing more than pointers. So, when you assign one array to another array you are making them literally point to the same data in memory. What you will have to do is copy the elements with loops, or perhaps use memcpy(dest, src, size). For example, if you want to copy the contents of double a[4][2] to double b[4][2], you would use something like memcpy(b, a, sizeof(double) * 8);. If you use a = b; then a and b are pointing to same locations in memory.

Two points:
1. your code says the function inversekinematic() returns a pointer to a double, not an array.
2. you return a pointer to a double, but it's always the same address.
Maybe typedefs will help simplify the code?
typedef double Mat42[4][2];
Mat42 a, a1;
Mat42 *inversekinematic(double target[4][4])
{
// ...
return &a;
}
But, for the code you've shown, I don't see why you need to return the address of a fixed global value. Perhaps your real code might return the address of 'a' or 'a1', but if it doesn't ...

Related

C++ Getting neighbours of a cell in a grid, -1x throwing null exception when checked if != NULL

recently moved from C# to C++ so I'm new to pointers and references and so on.
I've a pointer-to-pointer array declared like this
enum Type
{
Void,
DeepWater,
Water,
... etc }
Tile::Type** tiles;
TileManager::TileManager(int width, int height)
{
this->tiles = new Tile::Type*[width];
for (int w = 0; w < width; w++)
{
tiles[w] = new Tile::Type[height];
for (int h = 0; h < height; h++)
{
tiles[w][h] = Tile::Type::Dirt;
}
}
}
Now I'm putting together a method that returns the neighbours of a cell in the tiles array and checking if each neighbour is not-equal to NULL.
However even when checking whether it's null or not seems to throw an error, so I'm stumped.
Tile::Type * TileManager::GetNeighbours(int x, int y)
{
Tile::Type neighbours[8];
if(tiles[x][y+1] != NULL)
neighbours[0] = tiles[x ][y + 1];
...etc
if (tiles[x - 1][y - 1] != NULL) //<-- Error fires here
neighbours[5] = tiles[x - 1][y - 1];
return neighbours;
}
I know why it's throwing the error but shy of checking X and Y to see if they go over the limit or below 0... I figure there's a more practical way to prevent this so thought I'd best ask.
Edit:
Thank you, user4581301. I found most of this code elsewhere and adapted it to reflect the changes you suggested.
std::array<Tile::Type, 8> TileManager::GetNeighbours(int c, int r)
{
std::array<Tile::Type, 8> neighbours;
const int y[] = { -1, -1, -1, 1, 1, 1, 0, 0 };// 8 shifts to neighbors
const int x[] = { -1, 0, 1, -1, 0, 1, -1, 1 };// used in functions
for (int i = 0; i < 8; ++i)// visit the 8 spaces around it
if (inField(r + y[i], c + x[i]))
neighbours[i] = tiles[r + y[i]][c + x[i]];
else
neighbours[i] = Tile::Type::Void;
return neighbours;
}
bool TileManager::inField(int r, int c)
{
if (r < 0 || r >= 25) return false;
if (c < 0 || c >= 25) return false;
return true;
}
tiles[x][y+1], if y is the maximum valid value, will not be NULL except by the grace of . This goes out of bounds and as soon as you go out of bounds all bets are off. You've invoked Undefined Behaviour and pretty much anything can happen. Even what you expected to happen.
The same applies to the reported crash site, tiles[x - 1][y - 1].
Edit: Left out solution. Not helpful.
The only way, short of taking off and nuking the entire site from orbit, is to test the index to make sure it does not puncture the array bounds before using the index on the array. You'll probably want a function to handle this.
void assign_if(Type & neighbour, int x, int y)
{
if(x >= 0 && x < width && y >= 0 && y < height)
neighbour = tiles[x][y];
}
and call it
assign_if(neighbours[0], x, y+1);
and later
assign_if(neighbours[0], x-1, y-1);
Edit: Stealing this from Bob__ for completeness
It is impossible to return a raw array from a function. The array goes out of scope and the pointer to it becomes invalid. Either pass in the array as another parameter or use a std::array or std::vector, both of which can be returned. Thanks to Copy Elision, a smart compiler will likely eliminate the copying costs.
Example:
std::array<Tile::Type, 8> TileManager::GetNeighbours(int x, int y)
{
std::array<Tile::Type, 8> neighbours;
...
return neighbours;
}
Edit by original poster. Here is my solution:
std::array<Tile::Type, 8> TileManager::GetNeighbours(int c, int r)
{
std::array<Tile::Type, 8> neighbours;
const int y[] = { -1, -1, -1, 1, 1, 1, 0, 0 };// 8 shifts to neighbors
const int x[] = { -1, 0, 1, -1, 0, 1, -1, 1 };// used in functions
for (int i = 0; i < 8; ++i)// visit the 8 spaces around it
if (inField(r + y[i], c + x[i]))
neighbours[i] = tiles[r + y[i]][c + x[i]];
else
neighbours[i] = Tile::Type::Void;
return neighbours;
}
bool TileManager::inField(int r, int c)
{
if (r < 0 || r >= 25) return false;
if (c < 0 || c >= 25) return false;
return true;
}
Edit: Caveat
This answer deals directly with solving the problem as asked. See the answer by Kaz for a description of a more practical solution that trades a bit of memory to completely eliminate the need for testing and generating the neighbours array.
The more "practical" way (shorter code that avoids conditional checks) is to create the tile array so that it's it contains an additional "border" of tiles around the valid area. If any tile position is in the valid area, then is valid and so is .
You can have a special type for the border tiles which only they have, and simply include those tiles in the "neighbors" list. If your world has walls, then the border can consist of wall material.
Needless to say, you must never ask for the list of neighbors of a border tile. This is ensured by logic such as not allowing a border tile to be the valid position for anything.
This tile is in the valid area within the border" is a condition that is easier to check, in fewer places, and your program can be structured so that this check is actually just a removable assertion (a check for a situation that should not happen if the program is correct, rather than a check for an expected situation).
In C and C++, we can displace the pointers so that position [0][0] is still the corner of the valid area, yet the out-of-bounds coordinates [-1][-1] are valid indices, as are [w][h].
Firstly, the column array is allocated two elements larger than necessary, and the pointer is the incremented by one. Then the columns are allocated two elements larger, and each pointer is incremented by one before being assigned into the main array.
When freeing the arrays with delete [], you have to remember to decrement each pointer by one.

How to check whether an index in an array is empty

I'm making a small OpenGL program for my intro to C++ class in Uni. I have a program that is complete but I want to change it up a bit to make it more unique. I have a Cube class:
class Cube {
public:
Cube(Mesh* mesh, Texture2D* texture, float x, float y, float z);
~Cube();
void Draw();
void Update(float rSpeed);
Vector3 position;
private:
GLfloat rotationSpeed;
Vector3 rotationVector;
Mesh* _mesh;
Texture2D* _texture;
};
I then create an array of type Cube:
Cube* cubes[CUBE_AMOUNT];
I then fill each index of this array with data to draw the cube on screen later in the program:
for (int i = 0; i < CUBE_AMOUNT; i++) {
float x = ((rand() % 400) / 10.0f) - 20.0f;
float y = ((rand() % 200) / 10.0f) - 10.0f;
float z = -(rand() % 1000);
if (i % 2 == 1) {
cubes[i] = new Cube(cubeMesh, textureStars, x, y, z);
}
else {
cubes[i] = new Cube(cubeMesh, texturePenguins, x, y, z);
}
}
With this new thing I want to add to the program, I want to check whether an index of cubes[] has been filled with the data yet. However I keep getting exceptions when running. I have tried to check whether cubes[i] is equal to nullptr, and tried checking whether it is NULL too, but neither seem to match.
Sorry for any errors in terminology that I used. New to C++, and having come from only doing Python before this, it is confusing!
Solution:
When I create the array, I changed it to Cube* cubes[CUBE_AMOUNT] = { NULL }, and now when checking the array, cubes[i] == NULL!
If cubes is not a global variable, you can use:
Cube* cubes[CUBE_AMOUNT] = {};
to initialize all the elements to nullptr.
You can also use:
std::vector<std::unique_ptr<Cube>> cubes(CUBE_AMOUNT);
to remove the burden of having to deallocate dynamic memory in your code.
In either case, can use:
if ( cubes[index] )
{
// Got a valid pointer. Use it.
}
Your cubes variable is not automatically initialized with null_ptr's. Until you either fill it with null_ptr's or good pointers it initially points to random garbage.
I think this would work
//This bit should check if theres anything stored currently.
cout << "\nWhich Slot would you like to store the informaton in ?(1-10)";
cin >> i;
i--;
if (information[i] != NULL){
// Already written
cout << "THERES SOMETHING HERE";
}
else{
cout << "\nEMPTY!!!!!!!!!";
}

C++ - How to generate every possible combination of n 3D coordinates by incrementing x/y/z by a given value x

As part of a larger program I need to generate every possible set of 3D coordinate points contained within the rectangular prism formed by the origin and point (Y1, Y2, Y3), given the number of points, n, that will be in the set, and the value by which the x/y/z values are to be incremented by.
This was what I initially wrote, which does the job of cycling through all possible coordinates correctly for an individual point, but does not correctly generate all the overall combinations of points needed.
In the program I created a point object, and created a vector of point objects with default x/y/z values of zero.
void allPoints(double Y1, double Y2, double Y3, double increment, vector<Point> pointset)
{
int count = pointset.size()-1;
while (count>=0)
{
while (pointset.at(count).getX()<Y1)
{
while (pointset.at(count).getY()<Y2)
{
while (pointset.at(count).getZ()<Y3)
{
//insert intended statistical test to be run on each possible set here
}
pointset.at(count).setZ(0);
pointset.at(count).incY(increment);
}
pointset.at(count).setY(0);
pointset.at(count).incX(increment);
}
count--;
}
}
I am new to coding and may be approaching this entirely wrong, and am just looking for help getting in the right direction. If using a point object isn't the way to go, it's not needed in the rest of the program - I could use 3d arrays instead.
Thanks!
Lets assume you have class Point3d which represents a point, Vec3d which represents a vector which can translate points (proper operators are defined).
In such case this should go like this:
std::vector<Point3d> CrystalNet(
size_t size,
const Point3d& origin,
const Vec3d& a = { 1, 0, 0 },
const Vec3d& b = { 0, 1, 0 },
const Vec3d& c = { 0, 0, 1 })
{
std::vector<Point3d> result;
result.reserve(size * size * size);
for (int i = 0; i < size; ++i)
for (int j = 0; j < size; ++j)
for (int k = 0; k < size; ++k) {
result.empalce_back(origin + a * i + b * j + c * k);
}
return result;
}
Defining Point3d and Vec3d is quite standard and I'm sure there is ready library which can do it.
The chief problem appears to be that your textual description is about creating a pointset. The count isn't known up front. The example code takes an already created pointset. That just doesn't work.
That's also why you end up with the // insert test here - that's not the location for a test, that's where you would add a new point to the pointset you have to create.

Assigning in high-dimensional Xtensor arrays

I am using the Xtensor library for C++.
I have a xt::zeros({n, n, 3}) array and I would like to assign the its i, j, element an xt::xarray{ , , } so that it would store a 3D dimensional vector at each (i, j). However the documentation does not mention assigning values - I am in general unable to figure out from the documentation how arrays with multiple coodinates works.
What I have been trying is this
xt::xarray<double> force(Body body1, Body body2){
// Function to calulate the vector force on body2 from
// body 1
xt::xarray<double> pos1 = body1.get_position();
xt::xarray<double> pos2 = body2.get_position();
// If the positions are equal return the zero-vector
if(xt::all(xt::equal(pos1, pos2))) {
return xt::zeros<double>({1, 3});
}
xt::xarray<double> r12 = pos2 - pos1;
double dist = xt::linalg::norm(r12);
return -6.67259e-11 * body1.get_mass() * body2.get_mass()/pow(dist, 3) * r12;
}
xt::xarray <double> force_matrix(){
// Initialize the matrix that will hold the force vectors
xt::xarray <double> forces = xt::zeros({self_n, self_n, 3});
// Enter the values into the force matrix
for (int i = 0; i < self_n; ++i) {
for (int j = 0; j < self_n; ++j)
forces({i, j}) = force(self_bodies[i], self_bodies[j]);
}
}
Where I'm trying to assign the output of the force function as the ij'th coordinate in the forces array, but that does not seem to work.
In xtensor, assigning and indexing into multidimensional arrays is quite simple. There are two main ways:
Either index with round brackets:
xarray<double> a = xt::zeros({3, 3, 5});
a(0, 1, 3) = 10;
a(1, 1, 0) = -100; ...
or by using the xindex type (which is a std::vector at the moment), and the square brackets:
xindex idx = {0, 1, 3};
a[idx] = 10;
idx[0] = 1;
a[idx] = -100; ...
Hope that helps.
You can also use view to achieve that.
In the inner loop, you could do:
xt::view(forces, i, j, xt::all()) = a_xarray_with_proper_size;

Plotting Euler Integration using Polyline(), C++

So I'm trying to plot the output of this Euler integration function:
typedef double F(double,double);
using std::vector;
void euler(F f, double y0, double a, double b, double h,vector<POINT> Points)
{
POINT Pt;
double y_n = y0;
double t = a;
for (double t = a; t != b; t += h )
{
y_n += h * f(t, y_n);
Pt.x = t; // assign the x value of the point to t.
Pt.y = y_n; // assign the y value of the point to y_n.
Points.push_back(Pt);
}
}
// Example: Newton's cooling law
double newtonCoolingLaw(double, double t)
{
return t; // return statement ends the function; here, it gives the time derivative y' = -0.07 * (t - 20)
}
I'm trying to use the Polyline() function in a Win32 application, so I do this under the case WM_PAINT:
case WM_PAINT:
{
hdc = BeginPaint(hWnd, &ps);
//Draw lines to screen.
hPen = CreatePen(PS_SOLID, 1, RGB(255, 25, 5));
SelectObject(hdc, hPen);
using std::vector;
vector<POINT> Points(0);
euler(newtonCoolingLaw, 1, 0, 20, 1,Points);
POINT tmp = Points.at(0);
const POINT* elementPoints[1] = { &tmp };
int numberpoints = (int) Points.size() - 1 ;
Polyline(hdc,elementPoints[1],numberpoints);
When I reroute my I/O to console, here are the outputs for the variables:
I'm able to draw the expected lines to the screen using MovetoEx(hdc,0,0,NULL) and LineTo(hdc,20,20), but for some reason none of these functions will work with my vector<POINT> Points. Any suggestions?
There are multiple things that seem erroneous to me:
1) You should pass the vector by reference or as a return value:
void euler(/*...*/,vector<POINT>& Points)
Currently you are only passing a copy into the function, so the original vector will not be modified.
2) Don't compare doubles for (in-)equality in your for-loop header. Doubles have a limited precision, so if b is much bigger than h, your loop might never terminate, as t might never exactly match b. Compare for "smaller" instead:
for (double t = a; t < b; t += h )
3) Why are you declaring elementPoints as an array of pointers of size 1? Wouldn't a simple pointer do:
const POINT* elementPoints = &tmp ; //EDIT: see point 5)
4) You have an of-by-one error when calling Polyline. If you want to stick with the array at all use.
Polyline(hdc,elementPoints[0],numberpoints);
EDIT: Sorry, I forgot an important one:
5) In your code, elementPoints[0] points to a single double (tmp) and not to the array inside of the vector. This would probably work, if you declared tmpas a reference:
POINT& tmp = Points.at(0); //I'm wondering why this doesn't throw an exception, as the vector should actually be empty here
However, I think what you actually want to do is to get rid of tmp and elementPoints altogether and write in the last line:
Polyline(hdc,&Points[0],(int) Points.size()-1);
//Or probably rather:
Polyline(hdc,&Points[0],(int) Points.size());
Btw.: What is the purpose of the -1?