C语言 用指针编写矩阵运算函数

jexiocij  于 2022-12-02  发布在  其他
关注(0)|答案(2)|浏览(149)

我想写一个执行普通矩阵运算的函数。这可以通过二维数组或指针算法来完成。我更喜欢指针版本。现在,我想用指针来写一个函数,如下所示:

void matmult(double *a, double *b, double *c, int m, int n, int k);

问题是当我把二维数组传递给函数时,我必须使用一个强制转换。有没有一个好的解决方案来避免这个问题?
工作时不需要强制转换(当然),但我希望避免编译器警告。
更新:数组被定义为二维数组,调用函数如下所示:

// M, N, K are constants
double a[M][N];
double b[N][K];
double c[M][K];
matmult((double *)a, (double *)b, (double *)c, M, N, K);

函数matmult是矩阵乘法的直接实现(使用指针的三个嵌套for循环)

*(c + i*k + j) += *(a + i*n + p) * *(b + p*k + j);

我只想摆脱掉演员阵容。

hi3rlvi2

hi3rlvi21#

static void matmult(double a[][N], double (*b)[K], double c[M][K], int m, int n, int k);

这个原型用于传递二维数组。参见C FAQ entryArray to pointer decay and passing multidimensional arrays to functionsc[M][K]中的M在C中完全是多余的,但作为自文档可能很有用(或者可能会让读者更加困惑)。
然而,这并不是很好的封装,我会犹豫用它来编写一个通用的矩阵算法。大小是矩阵本身不可分割的一部分。我可能会使用C99的 * 灵活数组成员 * 来存储大小和数据,只要它不是其他结构的一部分。

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <stdarg.h>
#include <limits.h>

struct matrix {
    unsigned x, y;
    double data[]; /* flexible array member */
};

/** Constructor; data is uninitialized. */
static struct matrix *matrix(const unsigned x, const unsigned y) {
    if(!x || !y || x >= UINT_MAX / y) { errno = ERANGE; return 0; }
    struct matrix *const m = malloc(offsetof(struct matrix, data)
        + sizeof *m->data * x * y);
    if(!m) return 0;
    m->x = x, m->y = y;
    return m;
}

/** Constructor; IBM has a useful extension that allows stack construction. */
static struct matrix *matrix_init(const unsigned x, const unsigned y, ...) {
    struct matrix *const m = matrix(x, y);
    if(!m) return 0;
    va_list argp;
    va_start(argp, y);
    for(unsigned i = 0, size = x * y; i < size; i++)
        m->data[i] = va_arg(argp, double);
    va_end(argp);
    return m;
}

static void matrix_print(const struct matrix *const m) {
    if(!m) { printf("null\n"); return; }
    for(unsigned y = 0; y < m->y; y++) {
        printf("[");
        for(unsigned x = 0; x < m->x; x++)
            printf("%s%4.f", x ? ", " : "", m->data[y * m->x + x]);
        printf("]\n");
    }
}

static struct matrix *matmult(const struct matrix *a,
    const struct matrix *b) {
    if(!a || !b || a->y != b->x) { errno = EDOM; return 0; }
    struct matrix *const c = matrix(b->x, a->y);
    if(!c) return 0;
    for(unsigned y = 0; y < a->y; y++)
        for(unsigned x = 0; x < b->x; x++)
            c->data[y * b->x + x] = 0.0;
    /* implement:
     *(c + i*k + j) += *(a + i*n + p) * *(b + p*k + j); */
    return c;
}

int main(void) {
    struct matrix *a = 0, *b = 0, *c = 0;
    int success = EXIT_SUCCESS;
    if(!(a = matrix_init(2, 2, 1.0, 2.0, 3.0, 4.0))
        || !(b = matrix_init(2, 2, 3.0, 20.0, 1.0, 0.0))) goto catch;
    matrix_print(a), printf("*\n"), matrix_print(b);
    if(!(c = matmult(a, b))) goto catch;
    printf("=\n"), matrix_print(c);
    goto finally;
catch:
    success = EXIT_FAILURE;
    perror("matrix");
finally:
    free(a), free(b), free(c);
    return success;
}
oxf4rvwz

oxf4rvwz2#

这就是我如何最终解决我的问题,感谢@尼尔的暗示:

void matrixmult(double (*a)[], double (*b)[], double (*c)[], int m, int n, int k)
{
   for (...)
       for (..)
          for (...)
              *((double *)c + i*k + j) = ...
}

现在,可以在不强制转换的情况下调用该函数,并且我避免了C99 VLA特性的限制(必须首先传递维度)。

相关问题