试图为任意大小的矩阵编写矩阵乘数

时间:2011-06-16 21:32:48

标签: c arrays matrix

尝试在C中为任意大小的矩阵编写矩阵乘法函数。我正在尝试以下函数签名:

void matrixMult(void *A, int Xa, int Ya, void *B, int Xb, int Yb);

(现在它在我排除故障时返回无效状态,一旦我按照我想要的方式工作,我会稍后返回)

X和Y参数用于告知函数传入数组的维度(根据我的理解,这是必要的,因为在C数组中不知道它们自己的大小)。所以我传递了两个无效指针A和B,以及它们的尺寸。

我的问题:一旦我进入函数,我该如何将void指针转换回int数组,以便我可以读取它们?我尝试了以下方法:

(int)*A[someX][someY]

,但是我收到有关“无效使用void指针”的编译器错误。


修改

以下是我现在的全部功能(更新时我正在排除故障):

#pragma warning(disable: 8057)
#include <stdio.h>

void matrixMult(int **A, int Xa, int Ya, int **B, int Xb, int Yb);

int main(int argc, char *argv[]) {
    //   [x][y] x--> row; y-->cols
    int a[3][5] = {
          {  1,  2,  3,  4,  5 }
        , { 10, 20, 30, 40, 50 }
        , {  4,  8, 15, 16, 23 }
    };
    int b[5][7] = {
          {  1,  2,  3,  4,  5,  6,  7 }
        , { 10, 20, 30, 40, 50, 60, 70 }
        , {  4,  8, 15, 16, 23, 42,  0 }
        , {  1,  2,  3,  4,  5,  6,  7 }
        , { 10, 20, 30, 40, 50, 60, 70 }
    };

    matrixMult((int **)a, 3, 5, (int **)b, 5, 7);

    printf("done\n");
    return 0;
}

void matrixMult(int **A, int Xa, int Ya, int **B, int Xb, int Yb) {
    printf("starting matrix mult\n");
    int i, j;

    for (i=0; i<Xa; i++) {
        for (j=0; j<Ya; j++) {
            //printf("%i, %i:\t", i, j);
            printf("%i\t", A[Ya*i+j]);
        }
        printf("\n");
    }
}

编辑2 感谢您的提示和资源!上面发布的版本的工作方式与我现在的预期相同,但我担心如何使用指针是一个丑陋的混蛋。现在我要去做一些关于指针的阅读(感谢cnicutar!),我稍后会再看一遍。我对最新版本的任何进一步批评表示赞赏,但我现在已经回答了这个问题并继续进行了进一步的阅读。再次感谢!

4 个答案:

答案 0 :(得分:5)

如果我理解你的问题,你可以做类似的事情

int **a = A;

为什么您要立即使用void *而不是int **A

编辑1

根据以下评论:请参阅this FAQ entryf3是您想要的)。还有this one

编辑2

声明并初始化它们(像这样):

int **a;

a = malloc(sizeof(*a) * 3);
for (i = 0; i < 3; i++) {
    a[i] = malloc(sizeof(int) * 5);
}

答案 1 :(得分:3)

原型必须是双指针。此外,您不需要取消引用(除非您的内部指针本身是指针本身),因为您将它转换为int。除非类型是int *。

void matrixMult(void **A, int Xa, int Ya, void **B, int Xb, int Yb);

无需取消引用,因为它只是一个基本的int。

(int)A[someX][someY]

如果你有,让我们说一个int *你需要取消引用它,但即使这样你也会在演员之外取消引用

*(int *)A[someX][someY]

在取消引用指针之前,必须让编译器知道类型是什么。否则,您将错误地尝试取消引用void *。

答案 2 :(得分:1)

如果您有C99,您可以简单地使用可变长度数组,它们是为它而制作的。忘记指针的指针,然后做

void matrixMult(size_t n, size_t m, size_t k, double A[n][m], double B[m][k], double C[n][k]);

重要的是,尺寸首先出现在参数列表中,以便在ABC时知道它们。在函数内部,您可以通过类似A[i][j]的内容访问各个矩阵元素。

然后要分配这样的矩阵,你必须要小心,不要在堆栈上分配它们。 E.g

double (*A)[n][m] = malloc(*A);

应该这样做。

真的试着忘记将矩阵定义为指针数组,对于每个指针,你必须分配它自己的块,依此类推。这很复杂,容易出错,并增加了不必要的间接水平。

答案 3 :(得分:0)

void*不是某种模板类型参数。由于您需要将指针强制转换为某种类型,即指针指向的数据类型,并且整个操作是针对该类型编译的,因此单独使用void*指针在这里只是意义不大。可以添加一个参数来告诉传递哪种类型,并相应地在函数中进行分支,或者更好地使用正确的类型并相应地命名函数。此外,您不应该使用双指针:根据内存分配,它可能会破坏缓存局部性。

要保存输入,请使用宏:

#define MATRIXMULT(type, typeshort) void matrixMult##typeshort(\
##type *A, int const Xa, int const Ya, ##type *B, int const Xb, int const Yb)\
{ \
    printf("starting matrix mult\n"); \
    int i, j, k; \
\
    if(Ya != Xb || Xa != Yb) \
        return; // dimensions don't match \
\
    for (i=0; i<Xa; i++) { \
        for (j=0; j<Ya; j++) { \
            A[i*Ya + j]=0; \
            for(k=0; k < Xa; k++) \
                A[i*Ya + j] += A[i*Ya + k] * B[k*Yb + j]; \
    } \
}

MATRIXMULT(double, d)
MATRIXMULT(float, f)
MATRIXMULT(int, i)

由于评论而编辑:

MATRIXMULT(double, d)扩展为

void matrixMultd(
double *A, int const Xa, int const Ya, double *B, int const Xb, int const Yb)
{ 
    printf("starting matrix mult\n"); 
    int i, j, k; 

    if(Ya != Xb || Xa != Yb) 
        return;

    for (i=0; i<Xa; i++) { 
        for (j=0; j<Ya; j++) { 
            A[i*Ya + j]=0; 
            for(k=0; k < Xa; k++) 
                A[i*Ya + j] += A[i*Ya + k] * B[k*Yb + j]; 
    } 
}

因此,使用宏可以很容易地在多个变体中获得相同的功能。通过上述宏扩展,您可以调用matrixMultdmatrixMultfmatrixMulti