以下是我的代码。
#include <stdio.h>
#define _USE_MATH_DEFINES
#include <math.h>
void rot(int angle);
static double R[3][3]={0};
int main(void) {
int angle = 30;
rot(angle);
int i, j = 0;
for (i = 0; i < 3;i++) {
for (j = 0; j < 3; j++) {
printf("%lf\n", R[i][j]);
}
}
return 0;
}
void rot(int angle) {
double cang = cos(angle*M_PI / 180);
double sang = sin(angle*M_PI / 180);
R[0][0] = cang;
R[1][1] = cang;
R[1][0] = -sang;
R[0][1] = sang;
}
目前,函数rot本身不返回任何值。 但由于R是静态双倍,我能够打印出由rot函数改变的R. 我想改变函数rot以返回R [3] [3](二维数组)。 所以我想在主要像
上使用rot函数double R1=rot(30);
double R2=rot(60);
有什么办法可以实现吗?
答案 0 :(得分:4)
副本不一定对此有好处。由于这些R²矩阵需要易于复制,因此表示它们的最佳方法是将它们放在 struct 中:
typedef struct Matrix3x3 {
double v[3][3];
} Matrix3x3;
然后将它们作为返回值是微不足道的:
Matrix3x3 rot(int angle) {
Matrix3x3 m = {0};
double cang = cos(angle*M_PI / 180);
double sang = sin(angle*M_PI / 180);
m.v[0][0] = cang;
m.v[1][1] = cang;
m.v[1][0] = -sang;
m.v[0][1] = sang;
return m;
}
与数组不同,包含数组的结构也很容易复制:
Matrix3x3 x = y;
答案 1 :(得分:3)
C不允许从函数返回数组。可以在调用函数中分配数组,也可以在函数中动态分配数组,并返回指向数组的指针。请注意,函数中定义的数组是本地的,并且返回指向此类数组的指针是无用的,因为函数返回后局部变量不再存在。另一方面,动态分配继续存在。第三种选择是使用以下事实:虽然不能从C中的函数返回数组,但struct
的可以从函数返回 。
一个简单的解决方案是在调用函数中定义一个数组。该数组将在rot_3x3_a()
函数中修改。请注意,不是依赖函数的用户记住对数组进行零初始化,而是在函数内使用memset()
(在string.h
中定义)来将数组归零。
使用此方法的优点是可以避免动态分配,并且需要稍后解除分配以避免内存泄漏。所有方法都需要在调用函数中声明一个变量来接收旋转矩阵,但是这个方法也要求将数组传递给函数,因此这可能不符合OP要求。
更复杂的解决方案是使用动态分配。正如OP示例所示,rot_3x3_b()
函数只接受int
参数,但返回指向3 double
s数组的指针(这是3x3数组衰减到的指针类型)在大多数表达式中)。此处使用typedef
,因此Matrix_3x3
是指向3 double
s数组的指针;这样可以更容易地编写函数原型。
此处memset()
可能与malloc()
一起使用,但已使用calloc()
,它会自动对分配进行零初始化。请注意,在rot_3x3_b()
函数中,如果分配失败,则不会发生任何其他情况,并返回空指针。调用者必须检查并正确处理错误。
使用这种方法的优点是结果矩阵分配可以简单地索引为2d数组,并且函数的参数符合OP要求。缺点是代码比其他解决方案稍微复杂一些,并且更容易出错,并且此函数的用户必须记住free
已分配的内存以避免内存泄漏。
虽然C不允许将数组分配给另一个数组,但可以将struct
分配给另一个struct
。此外,struct
是可以从函数返回的左值。因此,该问题的一个解决方案是在struct
函数内创建包含3x3数组的rot_3x3_c()
。在从函数返回struct
之前,可以填充struct
的数组成员。在这种情况下,已使用指定的初始化程序对struct
的数组成员进行零初始化。
这里的优点是实施简单。没有动态分配,因此无需担心内存泄漏。缺点是数组必须作为struct
成员访问,因此该函数的用户必须声明struct Mtrx_3x3 R_c
以接收从函数返回的值,并且必须记住使用{{访问该数组1}}。
R_c.mx
C标准不仅没有定义这个常量,而是规定一致的实现必须默认不定义它。这意味着如果特定实现确实定义了M_PI
,则它是必须明确启用的扩展。作为公共扩展,定义了此常量。例如,如果使用M_PI
进行编译,则无需显式启用gcc -std=gnu11
。但是,如果使用其中一个更严格的选项,例如M_PI
,则必须明确启用gcc -std=c11
。 Here is an SO question that discusses the issue
现在,M_PI
适用于Microsoft实现,但不适用于Linux中的GCC(据我所知)。为了更具便携性,note that M_PI
is defined in POSIX。可以使用功能测试宏_USE_MATH_DEFINES
启用此功能。要么添加为源文件中的第一行:
_XOPEN_SOURCE 700
或在编译时使用命令行启用:
#define _XOPEN_SOURCE 700
请注意,使用gcc -std=c11 -D_XOPEN_SOURCE=700
启用功能时,它必须位于源文件的最开头才能工作。当然,此处也可以使用#define
或-std=c99
代替-std=c89
。
这将适用于与POSIX密切相关的Linux系统,但我不确定它是否适用于与POSIX紧密相关的Microsoft系统。为了获得最大的可移植性,最好使用:
显式定义常量std=c11
这是一个程序,说明了上述每种方法:
#define M_PI 3.14159265358979323846
节目输出:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#define M_PI 3.14159265358979323846
typedef double (*Matrix_3x3)[3];
struct Mtrx_3x3 {
double mx[3][3];
};
void rot_3x3_a(int angle, Matrix_3x3 mtrx);
Matrix_3x3 rot_3x3_b(int angle);
struct Mtrx_3x3 rot_3x3_c(int angle);
void print_3x3_matrix(Matrix_3x3);
int main(void)
{
int angle = 30;
/* Allocate for matrix in caller */
puts("Method a: pass an array");
double R_a[3][3];
rot_3x3_a(angle, R_a);
print_3x3_matrix(R_a);
putchar('\n');
/* Use dynamic allocation in function; must remember to free()! */
puts("Method b: use dynamic allocation");
Matrix_3x3 R_b = rot_3x3_b(angle);
if (R_b == NULL) {
perror("Allocation failure in rot_3x3_b()");
} else {
print_3x3_matrix(R_b);
putchar('\n');
}
/* Return the array inside a struct from the function */
puts("Method c: wrap the array in a struct");
struct Mtrx_3x3 R_c = rot_3x3_c(angle);
print_3x3_matrix(R_c.mx); // remember the array is R_c.mx
putchar('\n');
/* Cleanup */
free(R_b);
return 0;
}
/* Takes an array as an argument */
void rot_3x3_a(int angle, Matrix_3x3 mtrx)
{
/* Zero the array first */
memset(mtrx, 0, sizeof *mtrx * 3);
double cang = cos(angle * M_PI / 180);
double sang = sin(angle * M_PI / 180);
mtrx[0][0] = cang;
mtrx[1][1] = cang;
mtrx[1][0] = -sang;
mtrx[0][1] = sang;
}
/* Returns a pointer to a dynamically allocated array which must be
* deallocated by the caller with free(), or returns NULL */
Matrix_3x3 rot_3x3_b(int angle)
{
Matrix_3x3 mtrx = calloc(3, sizeof *mtrx);
if (mtrx) {
double cang = cos(angle * M_PI / 180);
double sang = sin(angle * M_PI / 180);
mtrx[0][0] = cang;
mtrx[1][1] = cang;
mtrx[1][0] = -sang;
mtrx[0][1] = sang;
}
return mtrx;
}
/* Returns a Mtrx_3x3 struct with a 3x3 array in the mx field */
struct Mtrx_3x3 rot_3x3_c(int angle)
{
struct Mtrx_3x3 mtrx = { .mx = {{ 0 }} };
double cang = cos(angle * M_PI / 180);
double sang = sin(angle * M_PI / 180);
mtrx.mx[0][0] = cang;
mtrx.mx[1][1] = cang;
mtrx.mx[1][0] = -sang;
mtrx.mx[0][1] = sang;
return mtrx;
}
void print_3x3_matrix(Matrix_3x3 mtrx)
{
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
printf("%10.5f", mtrx[i][j]);
}
putchar('\n');
}
}