从C++函数返回浮点数组

4

我做错了什么?

第一次打印时的值是正确的,而在第二次打印时全部都是零。

第一次打印 - q: 0.965926 0.000000 0.258819 0.000000

第二次打印 - 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]);

1
在C++中,你不能从函数中返回一个(原始的、C风格的)数组。最接近的方法是返回一个指针。 - Ron
1
为什么这是一个C++问题?我只看到了C。 - hellow
3
float q[4] = *AnglesToQaternion(0, 30.0, 0);改为float *q = AnglesToQaternion(0, 30.0, 0);。注意,翻译时不应更改原始意思并保持简洁。 - Susmit Agrawal
6
  1. 不要在局部变量中使用 static 关键字。
  2. 不要返回指向局部变量的指针。
  3. 使用 C++ 数组 std::array<float, 4>
- Dmitry Sazonov
4
可能是使用C语言返回数组的重复问题。 - Sander De Dycker
显示剩余9条评论
6个回答

8
不要返回任何数组。
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,
    };
}

4

解决方案1:如果您想要从外部访问它,则必须在函数内动态创建数组。然后,您必须考虑删除它以避免内存泄漏。

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);
}

解决方案二:您可以创建一个静态数组,并将其第一个元素的地址传递给您的函数。
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]);
}

如果可能的话,尽量避免使用new/delete(可以的话),第二种解决方案在性能方面要好得多。


你如何将本地变量发送到函数并在第二个解决方案中接受它作为指针? - Gal Dalali
当你编写 float q[4]; 时,如果这是你所问的,q 的类型为 float*q 表示浮点数数组的第一个单元格的地址。 - Benjamin Barrois
哦,我不小心漏掉了“return q;”,最后,非常感谢。 - Gal Dalali
@BenjaminBarrois 完全不是。q 的类型是 float[4],可以被衰减为指向其第一个元素的指针——这是很大的区别。 - Quentin

1

只需最小限度更改您的代码,函数和 q 应如下所示:

#include <array>

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

& 使用如下函数:

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

q = AnglesToQaternion(0, 30.0, 0);

1
在这里使用std::array<float,4>vector更好。大小始终是已知的,而std::vector将动态分配其存储空间。 - Khouri Giordano
@KhouriGiordano,你是对的。我已经从向量更新到数组了。 - Amit G.

1

Caleth已经写了展示方法的答案。但我认为您需要开始考虑C++而不是C。这里有一个完整的例子:

#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;
}

0

正如在您的问题下的评论中提到的那样,您不能真正返回一个数组,而是返回一个指针。如果您确实希望将其作为返回值,则在使用它之前,请确保在该函数中为其分配内存。类似于:

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

另一种选择是将数组作为参数传递给您的函数,并在函数中填充它。

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


谢谢,但我的主要问题是最终如何实现:float q[4] = AnglesToQaternion,我不想使用数组。 - Gal Dalali
你不能简单地这样做。你需要将数组的内容(返回的指针)复制到新数组中。但是,如果在函数中分配了内存,你可以这样做:float *q = AnglesToQaternion(...); - PhoenixBlue

0
将 main() 中本地 q 的地址传递给 AnglesToQaternion,以便它填充。
void AnglesToQaternion(float roll, float pitch, float yaw, float * quaternion)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接