我正在编写一个用于矩阵乘法的 C 函数。它需要两个 2D 整数数组。如果我知道输入数组的维度,我可以做到这一点,但我想做一个更通用的函数。
当我在编译时不知道产品的尺寸时,如何找到它们的尺寸,以及如何返回一个数组?
我正在编写一个用于矩阵乘法的 C 函数。它需要两个 2D 整数数组。如果我知道输入数组的维度,我可以做到这一点,但我想做一个更通用的函数。
当我在编译时不知道产品的尺寸时,如何找到它们的尺寸,以及如何返回一个数组?
如果你只有一个指向数组开头的指针,你就无法找出数组的维度。您需要将数组的维度传递给函数。
这个答案完全是矫枉过正,但这是我struct
的基础方法,nm 称之为“一个完整的'另一个故事”。
如果这是一个新程序(即您可以定义函数的输入/输出是什么样的)并且您打算对矩阵做很多工作,我会倾向于使用结构来表示矩阵,并且只是传递指向该结构实例的指针。
下面的代码显示了一种可能的方法。请注意,这里有几个“技巧”。首先,数据都存储在一个连续的块中——这可能出于多种原因提高性能。这种技术的一个潜在缺点是调整矩阵的大小变得昂贵,因为您必须分配一个全新的实例并复制数据。但是如果你发现这是一个问题,你总是可以改变你的实现,假设你总是使用 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;
}
你最好为你的数组创建一个 MATRIX 结构。正如@David 所指出的,在 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)。
祝你好运!
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;
};
但那完全是另一回事了。
您将需要传递数组的维度。然后你将不得不动态分配第三个数组来保存结果。一旦你计算了结果矩阵,你就可以返回一个指向它的指针。
沿着这些线尝试一些东西,其中 A 是一个 nxm 矩阵, B 是一个 mxp 矩阵:
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
}
#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;
}
通常二维数组以行主要方式存储。二维数组可以被认为是指向元素数组的指针数组。由于我们还传递了两个维度,因此我们可以相应地访问元素。
即使您可以尝试其他数据类型。下面我使用了结构。
#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;
}
希望能帮助到你....!!!!!