2012-05-04 30 views
2

我正在写矩阵乘法的C函数。它需要两个整数的二维数组。如果我知道输入数组的维数,我可以做到这一点,但我想做一个更通用的函数。如何使用尺寸未知的二维数组?

如何找到它们的尺寸,以及如何返回一个数组的时候,我不知道该产品的编译时间维度?

+1

或者我是否需要将尺寸作为单独的参数传递? – Andreas

+1

要知道的唯一方法是将数组维度作为参数传递给函数。 – Mahesh

回答

5

你不能找出一个数组的大小如果你所有的是一个指针数组的开头。您将需要将数组的维度传递给函数。

1

您将需要传递数组的维数。然后你将不得不动态分配第三个数组来保存结果。一旦你计算出了结果矩阵,你可以返回一个指向它的指针。

尝试沿着这些线路,其中A是N×M的矩阵,B是一个米×P矩阵的东西:

int* matix_multiply(int* matrix_a, int* matrix_b, int n, m, int p){ 

    int *result = (int *) malloc(sizeof(int) * a_rows * b_cols); 
    if(result == NULL) 
     exit(EXIT_FAILURE); 
    //loops to do the actual multiplication and store the results in result[i][j] 
    return result; //returns the result array 
} 
2

您是最好关闭你的阵列创建的矩阵结构。正如@大卫注意到的,在C中,你必须自己跟踪维度。语言中没有内置任何功能,可以安全地执行此操作。

有喜欢的strlen()的字符串功能(即:与\ 0结尾字符数组),但不喜欢的事情阵列和这样。跟踪这个最简单的方法是创建自己的抽象数据类型和辅助函数。

试试这个:

typedef struct matrix { 
    int **array; 
    int rows; 
    int cols; 
} matrix_t; 


int createMatrix(matrix_t* mtx) { 
    int i; 
    if (!mtx) { 
    printf("INVALID POINTER TO MATRIX"); 
    return -1; 
    } 
    if ((mtx->rows == 0) || (mtx->cols == 0)) { 
    printf("Rows/columns cannot be zero!"); 
    return -1; 
    } 
    int status = 0; 
    // allocate the array 
    mtx->array = (int **)calloc(mtx->rows,sizeof(int*)); 
    if(mtx->array != NULL) { 
    // memory allocation succeeded 
    for(i = 0; i < mtx->rows; i++) { 
     if((mtx->array[i] = (int*)calloc(mtx->cols,sizeof(int))) == NULL) { 
     printf("Memory allocation error"); 
     status = -1; 
     break; 
     } else { 
     // Allocation successful 
     } 
    } 
    } else { 
    printf("Memory allocation error!"); 
    status = -1; 
    } 
    return status; 
} 

int destroyMatrix(matrix_t* mtx) { 
    // destroy the array 
    for(i = 0; i < mtx->rows; i++) { 
    if(mtx->array[i] != NULL) { 
     free(mtx->array[i]); 
     mtx->array[i] = NULL; 
    } 
    } 
    if(mtx->array) { 
    free(mtx->array); 
    mtx->array = NULL; 
    } 
    return 0; 
} 

现在,你可以创建一个新的矩阵结构,设置它的行/列值,调用createMatrix,和你设置:

matrix_t myMtx; 
    myMtx.array = NULL; 
    myMtx.rows = 3; 
    myMtx.cols = myMtx.cols; // Make it a square matrix 
    if(createMatrix(&myMtx) == 0) { 
    printf("Created matrix successfully"); 
    } else { 
    printf("Failed to create matrix!"); 
    } 

这些功能还亲切检查内存分配是否失败,并在使用前检查所有指针以避免程序崩溃(即:SEGFAULT)。

祝你好运!

+0

如果你采取这种方法,我至少会将rows&cols params传递给'createMatrix()',因为在你调用'createMatrix()'之前,你总是必须初始化它们。 –

+0

不同的风格选择,它似乎。我更喜欢该结构是独立的,并且创建函数会执行相应的检查。当处理大的上下文变量时,保留函数原型更小,更可读,而不是冗长的,恕我直言。 – DevNull

+0

是的,我想这是关于保持函数原型简短和甜蜜的好处。我从数据隐藏/封装的角度思考更多。 –

2

有在C.没有真正的二维数组只有数组的数组,这是不完全一样的东西。 (我知道我会被打这么说。原谅我。)

虽然差异似乎并不十分显著,它是。要使用数组,您不必在编译时知道它的维数。例如

double dot_product (double a[], double b[], int size); 
/* an A-OK function */ 

但是你必须知道任何数组元素大小。例如

void matrix_product (double a[][], double b[][], double result[][], 
        int a_rows, int a_cols, int b_cols); 
/* Bad, would not compile. You are only permitted to say "double[N][]", 
    where N is known at compile time */ 

如果你想完全通用矩阵操作代码,你需要使用一个简单的一维数组,并计算索引列的行数和列数自己的。你也必须通过尺寸。

void matrix_product (double a[], double b[], double result[], 
        int a_rows, int a_cols, int b_cols) { 
    ... 
    for (col = 0; col < a_cols; ++col) { 
    for (row = 0; row < a_rows; ++row) { 
     ... 
     ... a[row*a_cols + col] ... 
     ... 

在这个例子中,调用者分配result,而不是乘法函数。


在你将要与他们一起尺寸封装矩阵某种形式的抽象矩阵数据类型的,像这样的一些更高级别:

struct matrix { 
    double* elements; 
    int rows, cols; 
}; 

但这是一个整体“诺特尔故事。

+0

我同意一个单一的数组就是要走的路。 Dogbert的答案显示了“其他”的方式。查看我的答案,了解如何在结构中进行封装的示例。 –

4

这个答案是总的矫枉过正,但这是我的struct为基础的方法,其中。称为“一个完整的故事”。如果这是一个新程序(也就是说,你可以定义你的函数的输入/输出是什么样的),并且你打算用矩阵做很多工作,我会倾向于使用一个结构体来表示一个结构体矩阵,并传递指向该结构实例的指针。

下面的代码显示了一种可能的方法。请注意,这里有几个“技巧”。首先,数据全部存储在一个连续的块中 - 由于多种原因,这可能会提高性能。这种技术的一个潜在缺点是,调整矩阵​​的大小会变得很昂贵,因为您必须分配一个全新的实例并复制数据。但是如果你发现这是一个问题,你总是可以改变你的实现,假设你总是使用matrix_get()和matrix_set()函数来访问矩阵中的值。

此外,数据指针指向的矩阵结构和内存全部分配在一个malloc调用中。如果您使用这种技术,只需注意数据对齐问题。例如,如果您将数据更改为指向64位整数或双精度,则需要添加填充以确保所有内容均为8字节对齐。或者,只要将malloc的数据指针作为new_matrix()函数中的单独数组提供,前提是您记得将其释放到free_matrix()中。

我已经作为练习留给OP来编写乘法函数。

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

struct matrix 
{ 
    int rows; 
    int cols; 
    int * data; 
}; 

struct matrix * new_matrix(int rows, int cols) 
{ 
    struct matrix * m = NULL; 

    /* Allocate a block of memory large enough to hold the matrix 'header' struct 
    * as well as all the row/column data */ 
    m = malloc(sizeof(struct matrix) + (rows * cols * sizeof(int))); 

    if(m) 
    { 
     m->rows = rows; 
     m->cols = cols; 

     /* Some ugly pointer math to get to the first byte of data */ 
     m->data = (int*) ((char *) m + sizeof(*m)); 
    } 
    return m; 
} 

void free_matrix(struct matrix * m) 
{ 
    free(m); 
} 

int matrix_set(struct matrix * m, int row, int col, int val) 
{ 
    if(col >= m->cols || row >= m->rows) 
     return -1; 
    m->data[ m->cols * row + col ] = val; 
    return 0; 
} 

int matrix_get(struct matrix * m, int row, int col, int * val) 
{ 
    if(col >= m->cols || row >= m->rows) 
     return -1; 
    else 
    { 
     *val = m->data[ m->cols * row + col ]; 
     return 0; 
    } 
} 

void print_matrix(struct matrix * m) 
{ 
    int r,c; 
    int val; 
    for(r = 0; r < m->rows; r++) 
    { 
     for(c = 0; c < m->cols; c++) 
     { 
     matrix_get(m, r, c, &val); 
     printf("%5d%s", val, c + 1 < m->cols ? "," : ""); 
     } 
     printf("\n"); 
    } 
} 

int main (int argc, char **argv) 
{ 
    int r,c; 
    struct matrix * m = new_matrix(5, 5); 

    for( r = 0; r < m->rows; r++) 
    { 
     for(c = 0; c < m->cols; c++) 
     { 
     matrix_set(m, r, c, (r +1)* 10 + c + 1); 
     } 
    } 

    print_matrix(m); 
    free_matrix(m); 
    return 0; 
} 
0
#include <stdio.h> 

void foo(int *a, int m, int n) 
{ 
    for(int i=0; i<m; i++) 
     for(int j=0; j<n; j++) 
      printf("%d\n", *(a+i*n+j)); 
} 
int main() 
{ 
    int a[][2] = {{1,2},{3,4}}; 
    foo((int *)a,2,2); 
    return 0; 
} 

通常的2D阵列存储在行主要方式。 二维数组可以视为指向数组元素的指针数组。由于我们也通过了两个维度,因此我们可以相应地访问元素。

即使您可以尝试其他数据类型。下面我用了结构。

#include <stdio.h> 
struct abc 
{ 
    int a; 
    float b; 
    char c; 
}; 
void foo(struct abc *a, int m, int n) 
{ 
    for(int i=0; i<m; i++) 
     for(int j=0; j<n; j++) 
      printf("%d %f %c\n", (a+i*n+j)->a, (a+i*n+j)->b, (a+i*n+j)->c); 
} 
int main() 
{ 
    struct abc a[][2] = {{{1,1.0,'a'},{2,2.0,'b'}}, {{3,3.0,'c'},{4,4.0,'d'}}}; 
    foo((struct abc *)a,2,2); 
    return 0; 
} 

希望它有帮助.... !!!!!

+1

你应该添加一些注释来解释你的代码如何解决这个问题。 – moggi

+1

请详细说明您的答案 – UmarZaii

相关问题