hee*_*une 5 c arrays matrix return-value
这是我的代码如下.
#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;
}
Run Code Online (Sandbox Code Playgroud)
目前,函数rot本身不返回任何值.但由于R是静态双倍,我能够打印出由rot函数改变的R. 我想改变函数rot以返回R [3] [3](二维数组).所以我想在main上使用rot函数
double R1=rot(30);
double R2=rot(60);
Run Code Online (Sandbox Code Playgroud)
有什么方法可以实现吗?
C 不允许从函数返回数组。可以在调用函数中分配数组,也可以在函数中动态分配数组并返回指向数组的指针。请注意,在函数中定义的数组是局部的,返回指向此类数组的指针是无用的,因为局部变量在函数返回后不再存在。另一方面,动态分配仍然存在。第三种选择是利用这样一个事实:虽然数组不能从 C 中的函数返回,但structs可以从函数返回并赋值。
一个简单的解决方案是在调用函数中定义一个数组。该数组将在函数中被修改rot_3x3_a()。请注意,不要依赖函数的用户记住对数组进行零初始化,而是在函数内使用memset()(在 中定义)对数组进行零初始化。string.h
使用这种方法的优点是可以避免动态分配,并且需要稍后释放以避免内存泄漏。所有方法都需要在调用函数中声明一个变量来接收旋转矩阵,但该方法还要求将数组传递给函数,因此这可能不满足OP要求。
更复杂的解决方案是使用动态分配。正如 OP 示例所示,该rot_3x3_b()函数仅接受一个int参数,但返回一个指向 3double数组的指针(这是 3x3 数组在大多数表达式中衰减到的指针类型)。typedef这里已经使用了A ,所以Matrix_3x3也是一个指向3的double数组的指针;这使得编写函数原型变得更容易。
在这里,本来memset()可以与 一起使用malloc(),但实际上calloc()已经使用了,这会自动将分配清零初始化。请注意,在rot_3x3_b()函数中,如果分配失败,则不会发生任何其他情况,并返回空指针。调用者必须检查这一点并适当地处理错误。
使用这种方法的优点是,生成的矩阵分配可以简单地索引为二维数组,并且函数的参数符合 OP 要求。缺点是,这比其他解决方案的代码稍微复杂一些,并且更容易出错,并且该函数的用户必须记住free分配的内存以避免内存泄漏。
虽然 C 不允许将一个数组分配给另一个数组,但struct可以将 a 分配给另一个数组struct。此外,astruct是可以从函数返回的左值。因此,解决该问题的一种方法是在函数内创建一个struct包含 3x3 数组的数组rot_3x3_c()。可以在从函数struct返回 之前填充的数组成员。struct在这种情况下,指定的初始化程序已用于对 的数组成员进行零初始化struct。
这里的优点是实现简单。没有动态分配,所以不用担心内存泄漏。缺点是数组必须作为struct成员来访问,因此该函数的使用者必须声明struct Mtrx_3x3 R_c接收函数返回的值,并且必须记住使用 来访问数组R_c.mx。
M_PIC 标准不仅没有定义这个常量,而且规定一致的实现默认情况下不得定义它。这意味着如果特定的实现确实定义了M_PI,那么它就是一个必须显式启用的扩展。作为一个通用的扩展,定义了这个常量。例如,如果使用 进行编译gcc -std=gnu11,则无需显式启用M_PI。但如果使用更严格的选项之一,例如 ,则gcc -std=c11必须M_PI显式启用。这是一个讨论该问题的 SO 问题。
现在,_USE_MATH_DEFINES可以与 Microsoft 实现一起使用,但不能与 Linux 中的 GCC 一起使用(据我所知)。为了获得更多的可移植性,请注意M_PIPOSIX 中定义的。这可以通过使用功能测试宏来启用_XOPEN_SOURCE 700。添加为源文件中的第一行:
#define _XOPEN_SOURCE 700
Run Code Online (Sandbox Code Playgroud)
或在编译时从命令行启用:
gcc -std=c11 -D_XOPEN_SOURCE=700
Run Code Online (Sandbox Code Playgroud)
请注意,当使用 a#define来启用功能时,它必须位于源文件的最开头才能起作用。当然,这里也可以用-std=c99or来代替。-std=c89std=c11
这适用于严格遵循 POSIX 的 Linux 系统,但我不确定它是否适用于遵循 POSIX 不太严格的 Microsoft 系统。为了获得最大的可移植性,最好简单地显式定义常量,使用:
#define M_PI 3.14159265358979323846
Run Code Online (Sandbox Code Playgroud)
这是一个说明上述每种方法的程序:
#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');
}
}
Run Code Online (Sandbox Code Playgroud)
程序输出:
#define _XOPEN_SOURCE 700
Run Code Online (Sandbox Code Playgroud)