【问题标题】:How to return a matrix from a function, in c? [closed]如何在c中从函数返回矩阵? [关闭]
【发布时间】:2016-04-07 08:27:17
【问题描述】:

我的矩阵加法的c代码如下:

mat(int n,int a[][5],b[][5] ){
   int i,c[5][5];

   for(i=0;i<5;i++){
       for(j=0;j<5;j++)
           c[i][j]=a[i][j]+b[i][j];

    return c;
}

当我编译这个时,我的编译器发现错误:

||warning: command line option '-Wzero-as-null-pointer-constant' is valid for C++/ObjC++ but not for C [enabled by default]|
C:\Users\Amir Khasru\Desktop\retuturn_a_matrix.c|2|warning: return type defaults to 'int' [-Wreturn-type]|
C:\Users\Amir Khasru\Desktop\retuturn_a_matrix.c|2|warning: no previous declaration for 'mat' [-Wmissing-declarations]|
C:\Users\Amir Khasru\Desktop\retuturn_a_matrix.c||In function 'mat':|
C:\Users\Amir Khasru\Desktop\retuturn_a_matrix.c|8|error: return makes integer from pointer without a cast|
||=== Build failed: 1 error(s), 3 warning(s) (0 minute(s), 0 second(s)) ===|

【问题讨论】:

  • 在您的程序中有许多与您的问题无关的其他错误。首先开始纠正它们。

标签: c


【解决方案1】:

这是您的代码(只是格式化并添加了缺少的右括号):

#include <stdio.h>

mat(int n, int a[][5], b[][5] )
{
    int i, c[5][5];

    for(i=0; i<5; i++) {
        for(j=0; j<5; j++) {
            c[i][j] = a[i][j] + b[i][j];
        }
        return c;
    }
}

我编译: $ gcc -std=c99 -Wall -Wextra -Wpedantic -Wconversion -Wno-sign-compare -Wshadow test.c -o test 我得到的第一件事是:

test.c:3:24: error: unknown type name ‘b’
 mat(int n, int a[][5], b[][5] )

让我们解决这个问题(在bj 之前添加int):

#include <stdio.h>

mat(int n, int a[][5], int b[][5] )
{
    int i, c[5][5];

    for(i=0; i<5; i++) {
        for(int j=0; j<5; j++) {
            c[i][j] = a[i][j] + b[i][j];
        }
        return c;
    }
}

现在我们得到:

test.c:3:1: warning: return type defaults to ‘int’ [-Wimplicit-int]
 mat(int n, int a[][5], int b[][5] )
 ^
test.c: In function ‘mat’:
test.c:11:10: warning: return makes integer from pointer without a cast [-Wint-conversion]
   return c;
          ^
test.c:11:10: warning: function returns address of local variable [-Wreturn-local-addr]
test.c:3:9: warning: unused parameter ‘n’ [-Wunused-parameter]
 mat(int n, int a[][5], int b[][5] )
         ^
test.c:13:1: warning: control reaches end of non-void function [-Wreturn-type]
 }
 ^

那么我们得到了什么:

  • mat() 返回 int,因为它是 C99 之前的默认回退,但没有不再是标准。不过,您似乎在 Visual Studio 上进行编译,它基本上实现了 C89 + 一些 C99 以实现 C++ 兼容性——但仍然要修复它。
  • 然后你返回c,这绝对不是int的类型。
  • 另外你不使用n,我猜它的意思是行数?
  • 您在第一个内部循环完成后返回——这可能不是我们想要的。

该怎么做:
通常,您通常希望调用者为结果留出空间,当您返回 c 时,它是 mat() 的本地地址,这是在 mat() 完成后发生的未定义行为。而是对mat() 使用以下声明:

void mat(int r, int c, int m1[r][c], int m2[r][c], int mr[r][c]);

其中r 是行,c 是列,m1m2 是输入矩阵,mr 是结果矩阵。

代码将是:

void mat(int r, int c, int m1[r][c], int m2[r][c], int mr[r][c])
{
        for(int i = 0; i < r; i++) {
                for(int j = 0; j < c; j++) {
                        mr[i][j] = m1[i][j] + m2[i][j];
                }
        }
}

你不需要返回任何东西——你写一个调用者提供的对象(希望如此)。如果你觉得勇敢,你可以在之前检查m1 == NULL || m2 == NULL || mr == NULL

让我们看看使用这个测试代码是如何工作的:

void print_mat(int r, int c, int m[r][c]);

int main() {
        int m1[2][5] = {
                {0,1,2,3,4},
                {1,2,3,4,5}
        };
        int m2[2][5] = {
                {10,11,12,13,14},
                {11,12,13,14,15}
        };

        printf("printing matrix m1:\n");
        print_mat(2,5,m1);
        printf("printing matrix m1:\n");
        print_mat(2,5,m2);

        int c[2][5];
        mat(2,5,m1,m2,c);

        printf("printing matrix m1+m2:\n");
        print_mat(2,5,c);
}

void print_mat(int r, int c, int m[r][c])
{
        for (int i = 0; i < r; i++) {
                for (int j = 0; j < c; j++) {
                        printf("\t%d", m[i][j]);
                }
                printf("\n");
        }
        return;
}

我明白了:

printing matrix m1:
        0       1       2       3       4
        1       2       3       4       5
printing matrix m1:
        10      11      12      13      14
        11      12      13      14      15
printing matrix m1+m2:
        10      12      14      16      18
        12      14      16      18      20

这正是它应该是的。

最后:

  • 具体说明类型,这会有所帮助。
  • 如果您不确定,请打开所有警告。
  • 通常不要在子函数中获取内存,让调用者来做。
  • 如果您不确定指针/数组,请尽量避免使用它们并编写易于理解的小测试用例;做研究!

【讨论】:

  • 我喜欢这种语法。不知道可以void print_mat(int r, int c, int m[r][c]);
  • @Nick 是的,很好;只要确保在数组使用它之前的声明中有rc
  • 这是原厂C99还是C11?
  • @Nick 非常肯定 C99,我使用 -std=c99 编译,我在许多编译器上使用过它,其中一些至少不支持所有 C11。
  • @Nick 是的,显然这是 C99 的一个特性,在 C11 中是可选的(见这里:stackoverflow.com/questions/25551779/…)。它也不是 C++ O.o
【解决方案2】:

你可以通过引用传递。

我不能用你的矩阵来做,因为我不认为代码是 100% 正确的。代码如下所示。

int mat(int x, int y, const int *m_a, const int *m_b, int *m_out);

地点:

  • 函数返回的int是一种状态码。
  • x 和 y 是矩阵的宽度和高度。
  • m_a, m_b 是输入矩阵。它们是常量。
  • m_out 是输出矩阵。

您可以通过像这样返回矩阵来“升级”函数:

int *mat(int x, int y, const int *m_a, const int *m_b, int *m_out){
    // do some work
    if (something is not OK)
        return NULL;
    else
        return m_out;
}

// in main()
int a[5 * 6];
int b[5 * 6];
int result[5 * 6];
mat(5, 6, a, b, result);
// use result.

第三个选项,可能更糟糕 - 分配内存,并返回分配的内存。稍后需要释放内存。

int *mat(int x, int y, const int *m_a, const int *m_b){
    int *m_out = malloc( x * y * sizeof int);

    if (m_out == NULL)
        return NULL;

    // do some work

    if (something is not OK){
        free(m_out);
        return NULL;
    }else
        return m_out;
}

// in main()
int *m = mat(5, 6, a, b);
// use m
free(m);

如果您有任何问题,请发表评论。

在所有示例中,我假设为一维数组。您可以轻松地将二维坐标转换为一维坐标,请在此处查看:

How to map the indexes of a matrix to a 1-dimensional array (C++)?

这里是完整的工作示例,按照我的方式制作。

#include <stdio.h>

int *mat(int x, int y, const int *m_a, const int *m_b, int *m_out){
    int i;
    for(i = 0; i < x * y; ++i)
        m_out[i] = m_a[i] + m_b[i];

    return m_out;
}

void print_mat(int x, int y, const int *m){
    int i, j;
    for(i = 0; i < x; ++i){
        for(j = 0; j < y; ++j)
            printf("| %4d ", m[i * y + j]);

        printf("|\n");
    }
}

#define X   2
#define Y   2

int main(){
    int a[X * Y] = { 1, 2, 3, 4 };
    int b[X * Y] = { 1, 2, 3, 4 };
    int result[X * Y];

    int *r = mat(X, Y, a, b, result);

    print_mat(X, Y, r);

    return 0;
}

这是输出:

[nmmm@zenbook HM3]$ gcc -Wall -Wpedantic x.c
[nmmm@zenbook HM3]$ ./a.out 
|    2 |    4 |
|    6 |    8 |
[nmmm@zenbook HM3]$

【讨论】:

  • 为什么是-1?我的代码没有任何问题
  • 不是我的反对意见,但int a[5, 6]; 是错误的。如果只需要这些,函数参数仍然可以是固定大小的数组,就像 OP 中一样,尽管使它们成为指针+大小确实使事情更通用。
  • 错字,已修复。这就是您需要 typedef 的原因,但我决定不添加混淆。
  • 好的,现在它甚至可以编译了。 (免费完成家庭作业)
  • 嘿尼克,我可以在 c.... 中声明可变维度数组吗?比如“int array[n][n]?”
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-12-14
  • 1970-01-01
  • 1970-01-01
  • 2021-05-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多