4

What am I doing wrong?

In the first print the values are fain, in the second it's all zeros.

The first print - q: 0.965926 0.000000 0.258819 0.000000

The Second print - q: 0.000000 0.000000 0.000000 0.000000

float *AnglesToQaternion(float roll, float pitch, float yaw) { // Convert Euler angles in degrees to quaternions

    static float q[4];

    roll  = roll  * DEG_TO_RAD;
    pitch = pitch * DEG_TO_RAD;
    yaw   = yaw   * DEG_TO_RAD;

    float t0 = cosf(yaw * 0.5);
    float t1 = sinf(yaw * 0.5);
    float t2 = cosf(roll * 0.5);
    float t3 = sinf(roll * 0.5);
    float t4 = cosf(pitch * 0.5);
    float t5 = sinf(pitch * 0.5);

    q[0] = t0 * t2 * t4 + t1 * t3 * t5;
    q[1] = t0 * t3 * t4 - t1 * t2 * t5;
    q[2] = t0 * t2 * t5 + t1 * t3 * t4;
    q[3] = t1 * t2 * t4 - t0 * t3 * t5;

    printf(">> q-1: %f %f %f %f \n", q[0], q[1], q[2], q[3]);

    return q;
}

float q[4] = *AnglesToQaternion(0, 30.0, 0); 
printf(">> q-2: %f %f %f %f \n", q[0], q[1], q[2], q[3]);
14
  • 1
    You can't return an (raw, C-style) array from a function in C++. The closest you can come to it is to return a pointer. Commented Jul 31, 2018 at 9:21
  • 1
    Why is this a C++ question? All I see is C Commented Jul 31, 2018 at 9:22
  • 3
    float q[4] = *AnglesToQaternion(0, 30.0, 0); should be float *q = AnglesToQaternion(0, 30.0, 0); Commented Jul 31, 2018 at 9:23
  • 6
    1) Don't use static for local variables. 2) don't return pointers to locals 3) use C++ arrays std::array<float, 4> Commented Jul 31, 2018 at 9:23
  • 4
    Possible duplicate of Returning an array using C Commented Jul 31, 2018 at 9:26

6 Answers 6

7

Don't return an array at all.

using degree = float;

struct Angles {
    degree roll;
    degree pitch;
    degree yaw;
};

struct Quaternion {
    float i;
    float j;
    float k;
    float l;
};

Quaternion angles_to_quaternion(Angles angles) 
{ 
    float yaw = angles.yaw * DEG_TO_RAD;
    float pitch = angles.pitch * DEG_TO_RAD;
    float roll = angles.roll * DEG_TO_RAD;

    float t0 = cosf(yaw * 0.5);
    float t1 = sinf(yaw * 0.5);
    float t2 = cosf(roll * 0.5);
    float t3 = sinf(roll * 0.5);
    float t4 = cosf(pitch * 0.5);
    float t5 = sinf(pitch * 0.5);

    return {
        t0 * t2 * t4 + t1 * t3 * t5,
        t0 * t3 * t4 - t1 * t2 * t5,
        t0 * t2 * t5 + t1 * t3 * t4,
        t1 * t2 * t4 - t0 * t3 * t5,
    };
}
Sign up to request clarification or add additional context in comments.

Comments

4

Solution 1: You have to create your array dynamically inside your function if you want to be able to access it from outside. Then you must think to delete it to avoid memory leaks.

float *AnglesToQaternion(float roll, float pitch, float yaw) { // Convert Euler angles in degrees to quaternions

    float *q = new float[4];
    // Or C-style: float *q = malloc(sizeof(float)*4);

    roll  = roll  * DEG_TO_RAD;
    pitch = pitch * DEG_TO_RAD;
    yaw   = yaw   * DEG_TO_RAD;

    float t0 = cosf(yaw * 0.5);
    float t1 = sinf(yaw * 0.5);
    float t2 = cosf(roll * 0.5);
    float t3 = sinf(roll * 0.5);
    float t4 = cosf(pitch * 0.5);
    float t5 = sinf(pitch * 0.5);

    q[0] = t0 * t2 * t4 + t1 * t3 * t5;
    q[1] = t0 * t3 * t4 - t1 * t2 * t5;
    q[2] = t0 * t2 * t5 + t1 * t3 * t4;
    q[3] = t1 * t2 * t4 - t0 * t3 * t5;

    printf(">> q-1: %f %f %f %f \n", q[0], q[1], q[2], q[3]);

    return q;
}

int main() {
    float *q = AnglesToQaternion(0, 30.0, 0); 
    printf(">> q-2: %f %f %f %f \n", q[0], q[1], q[2], q[3]);
    delete[] q;
    // Or C-style: free(q);
}

Solution 2: You can make a static array creation and then pass the address of its first element to your function.

void AnglesToQaternion(float *q, float roll, float pitch, float yaw) { // Convert Euler angles in degrees to quaternions

    roll  = roll  * DEG_TO_RAD;
    pitch = pitch * DEG_TO_RAD;
    yaw   = yaw   * DEG_TO_RAD;

    float t0 = cosf(yaw * 0.5);
    float t1 = sinf(yaw * 0.5);
    float t2 = cosf(roll * 0.5);
    float t3 = sinf(roll * 0.5);
    float t4 = cosf(pitch * 0.5);
    float t5 = sinf(pitch * 0.5);

    q[0] = t0 * t2 * t4 + t1 * t3 * t5;
    q[1] = t0 * t3 * t4 - t1 * t2 * t5;
    q[2] = t0 * t2 * t5 + t1 * t3 * t4;
    q[3] = t1 * t2 * t4 - t0 * t3 * t5;

    printf(">> q-1: %f %f %f %f \n", q[0], q[1], q[2], q[3]);
}

int main() {
    float q[4];
    AnglesToQaternion(&q[0], 0, 30.0, 0); 
    printf(">> q-2: %f %f %f %f \n", q[0], q[1], q[2], q[3]);
}

This second solution is much better for performance (you should avoid new/delete as much as you can if you can).

4 Comments

How can you send to a function local and accept it as a pointer on your second solution?
When you write float q[4];, q is of type float* if this is what you are asking. q represents the address of the first cell of your float array.
Oh, I accidently left the "return q;", finally, Thanks a lot
@BenjaminBarrois not at all. q is of type float[4] and can be decayed into a pointer to its first element -- big difference.
1

With the minimum change to your code, the function and q should looks like this:

#include <array>

std::array<float, 4> AnglesToQaternion(float roll, float pitch, float yaw)
{
    std::array<float, 4> q{ 0,0,0,0 };

& use the function like this:

std::array<float, 4> q{ 0,0,0,0 };

q = AnglesToQaternion(0, 30.0, 0);

2 Comments

std::array<float,4> is better than vector here. The size is always known and std::vector will dynamically allocate its storage.
@KhouriGiordano You are right. I updated from vector to array.
1

Caleth already wrote the answer that shows the way. But I think you need to start thinking C++ instead of C. Here a complete example:

#define _USE_MATH_DEFINES
#include <cmath>
constexpr float halfDegToRad = 0.5 * M_PI / 180.0;

struct Angles
{
    float roll;
    float pitch;
    float yaw;
};

#include <iostream>
struct Quaternion
{
    float i, j, k, l;

    friend std::ostream& operator<< (std::ostream& os, const Quaternion& q);
};

std::ostream& operator<< (std::ostream& os, const Quaternion& q)
{
    os << q.i << " " << q.j << " " << q.k << " "<< q.l << " ";
    return os;
}

// Convert Euler angles in degrees to quaternions
Quaternion AnglesToQuaternion(const Angles& ang)
{
    float t0 = std::cos(ang.yaw * halfDegToRad);
    float t1 = std::sin(ang.yaw * halfDegToRad);
    float t2 = std::cos(ang.roll * halfDegToRad);
    float t3 = std::sin(ang.roll * halfDegToRad);
    float t4 = std::cos(ang.pitch * halfDegToRad);
    float t5 = std::sin(ang.pitch * halfDegToRad);

    return {
        t0 * t2 * t4 + t1 * t3 * t5,
        t0 * t3 * t4 - t1 * t2 * t5,
        t0 * t2 * t5 + t1 * t3 * t4,
        t1 * t2 * t4 - t0 * t3 * t5 };
}

int main()
{
    Quaternion q = AnglesToQuaternion({ 0.0f, 30.0f, 0.0f });
    std::cout << ">> q-2 : " << q << "\n";
    return 0;
}

Comments

0

As Mentioned in one of the comment under your question, you cannot really return an array, but a pointer. If you really want it as return value, then make sure you allocate memory in that function for that before using it. Something like:

float *f_array = malloc(sizeof(float)*lengthArray);

An alternative is to pass an array as argument to your function and fill it in the function.

void AnglesToQaternion(float roll, float pitch, float yaw, float resultArray[])

2 Comments

Thanks, but my main question is how at the end I can do: float q[4] = AnglesToQaternion, I don't want to work with array.
You simply can't. You need to copy content of the array(returned pointer) into the new array. However, you can do float *q = AnglesToQaternion(...); Provided that you have allocated memory in the function.
0

Pass the address of the local q in main() to AnglesToQaternion for it to populate.

void AnglesToQaternion(float roll, float pitch, float yaw, float * quaternion)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.