【问题标题】:C: pass a 2D array as a function argument and get the results stored in the argument addressC:将二维数组作为函数参数传递,并获取存储在参数地址中的结果
【发布时间】:2020-08-01 18:24:36
【问题描述】:

Short:如何将二维数组作为函数参数传递,并将结果存储在参数地址中?

更长:我有代码(如下),它从main() 调用一个初始化函数,然后打印内容。但是,我希望将malloc 给出的指针存储到变量A 中后,结果将保存在参数中,但事实并非如此。当用一维数组做类似的事情时,它可以顺利运行,但不适用于二维数组。

为简单起见,在本例中,我将其设为 3x3,但我希望拥有不固定数量的 GB 数据。然后,我必须使用malloc,并且无法在编译时声明矩阵大小。

#include <stdio.h>
#include <stdlib.h>

void print_matrix(int n, double **A) {
    int i, j;
    for(i=0; i<n; i++) {
        for(j=0;j<n;j++) {
            printf("%0.2f ",A[i][j]);
        }
        printf("\n");
    }
}

void init(int n, double **A) {
    int i;
    A = (double **)malloc(n * n * sizeof(double *)); 
    for(i=0; i<n; i++) {
         A[i] = (double *)malloc(n * sizeof(double)); 
    }
    A[0][0] = 9.0;
    A[0][1] = 6.0;
    A[0][2] = -3.0;
    A[1][0] = 6.0;
    A[1][1] = 13.0;
    A[1][2] = -5.0;
    A[2][0] = -3.0;
    A[2][1] = -5.0;
    A[2][2] = 18.0;
    print_matrix(n, A);
}

int main() {
    int i;
    int n=3;
    double **A;
    init(n, A);
    print_matrix(n, A);
    for(i=0; i<n; i++)
        free(A[i]);
    free(A);
    return 0;
}

编译后,我可以在init() 函数内打印矩阵的内容,但不能从main() 打印而不会出现分段错误,这当然意味着A 指向未分配的内存,甚至A[0][0] 也不是指向矩阵的根。我正在使用 GCC 和标准 C99。

$ gcc --version
gcc (Ubuntu 9.2.1-9ubuntu2) 9.2.1 20191008
$ gcc main.c -o main -std=c99
$ ./main
9.00 6.00 -3.00 
6.00 13.00 -5.00 
-3.00 -5.00 18.00 
Segmentation fault (core dumped)

关于传递二维数组还有其他有用的问题,但它们并没有解决我的观点,因为它们没有解决在参数中返回结果的问题。

编辑:这是一个简单的例子,但我需要传递几个矩阵作为函数参数。因此,我不能简单地返回矩阵A的地址,因为我需要保存几个矩阵的地址。

【问题讨论】:

  • 在 C 函数中,参数是按值传递的。 main 中的 A 未初始化。
  • 这能回答你的问题吗? Update (int) variable in C inside a function
  • @KamilCuk 谢谢,但这不是我需要的。
  • 这就是你需要的。

标签: c arrays gcc multidimensional-array malloc


【解决方案1】:

我愿意这样做

#include <stdio.h>
#include <stdlib.h>

void print_matrix(int n, double **A) {
    int i, j;
    for(i=0; i<n; i++) {
        for(j=0;j<n;j++) {
            printf("%0.2f ",A[i][j]);
        }
        printf("\n");
    }
}

double ** init(int n) {
    int i;
    double **A;
    A = (double **)malloc(n * n * sizeof(double *));
    for(i=0; i<n; i++) {
         A[i] = (double *)malloc(n * sizeof(double));
    }
    A[0][0] = 9.0;
    A[0][1] = 6.0;
    A[0][2] = -3.0;
    A[1][0] = 6.0;
    A[1][1] = 13.0;
    A[1][2] = -5.0;
    A[2][0] = -3.0;
    A[2][1] = -5.0;
    A[2][2] = 18.0;
    print_matrix(n, A);
    return A;
}

int main() {
    int i;
    int n=3;
    double **A;
    A = init(n);
    print_matrix(n, A);
    for(i=0; i<n; i++)
        free(A[i]);
    free(A);
    return 0;
}

在 init() 函数中分配内存并返回指针。

[ronald@ocelot tmp]$ ./x
9.00 6.00 -3.00 
6.00 13.00 -5.00 
-3.00 -5.00 18.00 
9.00 6.00 -3.00 
6.00 13.00 -5.00 
-3.00 -5.00 18.00 

原始问题的答案是(仅更改的代码)

void init(int n, double ***A) {
    int i;
    *A = (double **)malloc(n * n * sizeof(double *));
    for(i=0; i<n; i++) {
         (*A)[i] = (double *)malloc(n * sizeof(double));
    }
    (*A)[0][0] = 9.0;
    (*A)[0][1] = 6.0;
    (*A)[0][2] = -3.0;
    (*A)[1][0] = 6.0;
    (*A)[1][1] = 13.0;
    (*A)[1][2] = -5.0;
    (*A)[2][0] = -3.0;
    (*A)[2][1] = -5.0;
    (*A)[2][2] = 18.0;
    print_matrix(n, *A);
}

int main() {
    int i;
    int n=3;
    double **A;
    init(n, &A);
    print_matrix(n, A);
    for(i=0; i<n; i++)
        free(A[i]);
    free(A);
    return 0;
}

【讨论】:

  • 感谢您的快速回答,但它并没有解决我的问题,因为它没有解决我需要的问题。我在问题末尾添加了“编辑”部分以澄清我的情况:我需要保存几个矩阵的信息。
  • 您可以使用任一代码初始化任意数量的矩阵。而且因为取消引用的 A 很难阅读,我仍然会选择第一个解决方案。 double **A1 = init(n); double **A2 = init(n);double **A1, **A2; init(n, &amp;A1); init(n, &amp;A2); 一样好用
【解决方案2】:

通过指针传递矩阵。因为没有人想成为three star programmer,所以为您的数据创建一个结构并传递一个指向该结构的指针。请记住,代码的可读性、适当的封装和可读的面向对象编程将使您走得更远。记住错误处理,为了简洁起见,我希望你在你的问题中省略了。 Do not cast result of malloc。使用size_t 类型表示数组中的元素个数。

也就是说,我会这样做:

// Represents a n x n dynamically allocated matrix.
struct matrix_s {
   double **a;
   size_t n;
};

// Forward declaration for `matrix_init`.
void matrix_free(struct matrix_s *m);

int matrix_init(struct matrix_s *m, size_t n) {
    assert(n > 2); // as you seem to access indices at least 2
    m->a = calloc(n * n, sizeof(*m->a));
    if (m->a == NULL) {
        goto ERROR;
    }
    m->n = 0;
    for(size_t i = 0; i < n; i++) {
         m->a[i] = calloc(n, sizeof(*A[i])); 
         m->n++;
         if (m->a[i] == NULL) {
            goto ERROR;
         }
    }

    // fill the array

    // SUCCESS
    return 0;

    ERROR:
    matrix_free(m);
    return ENOMEM;
}

void matrix_print(struct matrix_s *m) {
   for (size_t i = 0; i < m->n; ++i) {
       printf(....);
   }
}

void matrix_free(struct matrix_s *m) {
   for (size_t i = 0; i < m->n; ++i) {
      free(m->a[i]);
   }
   free(m->a);
   m->a = NULL;
   m->n = 0;
}

int main() {
    struct matrix_s m;
    if (matrix_init(&m, 3) != 0) {
       abort();
    }
    matrix_print(&m);
    matrix_free(&m);
    return 0;
}

不过,如果您愿意,您也可以成为 3 星级程序员,并通过几乎没有任何变化的指针从 main 传递指针 A

void init(int n, double ***A0) {
    double **A = malloc(n * n * sizeof(*A)); 

    // same your code without any modification

    *A0 = A; // asing the outer pointer to A
}

int main() {
    double **A;
    init(3, &A); // pass `A` by a pointer
    // ...
}

因为您的矩阵似乎每行具有相同的行大小,通过适当的封装,您可以考虑只为 n * n 双打分配一个内存块并自己计算要导航到的索引。您还可以使用像double (*array)[n] 这样的可变长度数组以类似数组的无缝方式访问您的数据。但是调整数组的大小可能会变得更加困难。

struct matrix_s {
    double *a;
    size_t n;
};

double *matrix_getp(struct matrix_s *m, size_t i, size_t j) {
     return &m->a[i * m->n + j];
}

int matrix_init(struct matrix_s *m, size_t n) {
     m->a = malloc(n * n * sizeof(*m->a)); // only a single allocation
     // ...

     // access to matrix at A[0][0]  
     *matrix_getp(m, 0, 0) = 1;
     // or the same using a VLA variable:
     double (*a)[n] = (void*)m->a;
     a[0][0] = 1;

     // ...
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-10-17
    • 2023-03-30
    • 2012-01-22
    • 2020-10-04
    • 1970-01-01
    相关资源
    最近更新 更多