C 如何通过指针处理矩阵中的子矩阵?
我有一个大小为n的矩阵。例如: 我的递归函数对位于矩阵边界的元素进行处理。现在我想在内部平方矩阵上调用它(递归调用): 这是我的递归函数的原型:C 如何通过指针处理矩阵中的子矩阵?,c,recursion,matrix,C,Recursion,Matrix,我有一个大小为n的矩阵。例如: 我的递归函数对位于矩阵边界的元素进行处理。现在我想在内部平方矩阵上调用它(递归调用): 这是我的递归函数的原型: void rotate(int** mat, size_t n); 我知道2D数组是数组中的数组。我知道*(mat+1)+1)将给出应该是新矩阵基址的内存地址。这就是我所尝试的: rotate((int **)(*(mat+1) + 1), n-2) 但是它不起作用,当我尝试使用[][]访问它时,我得到一个segfault,您不能取消对mat+
void rotate(int** mat, size_t n);
我知道2D数组是数组中的数组。我知道*(mat+1)+1)
将给出应该是新矩阵基址的内存地址。这就是我所尝试的:
rotate((int **)(*(mat+1) + 1), n-2)
但是它不起作用,当我尝试使用
[][]
访问它时,我得到一个segfault,您不能取消对mat+1的引用,并将其重新解释为指向整个矩阵的指针。而是将偏移量作为参数提供给函数(我假设n
-by-n
方阵):
我不确定您的应用程序,但我想知道使用#定义矩阵大小是否有帮助
#define X_SIZE 4
#define Y_SIZE 4
甚至
#define N_SIZE 4
。。。因为这样您就可以在函数中使用X_SIZE和Y_SIZE(或N_SIZE),而不必显式地传递它们
大体上你可以把
int matrix[X_SIZE * Y_SIZE];
或
然后您可以使用调用第i行和第j列元素
*(pmatrix + X_SIZE*j + i)
或
或
或
其中,pmatrix和pmatrix2是指向矩阵和矩阵x2的指针
我敢肯定,要想轻松地将内方2x2矩阵传递给一个函数,没有什么聪明的办法,除非你要将矩阵中心的元素复制到一个新矩阵中,然后再复制回结果。这不是对上述问题的回答,但这是一个基本问题的答案:用最少的努力管理矩阵和矩阵视图
这将赢得否决票,但无论何时,只要有人问OP提出的问题类型,它在解决潜在问题方面都非常有用,我觉得在这里展示这种替代方法是值得的。
对于小的、固定大小的矩阵来说,这并不有趣,因为只有当大小较大或不同时,这些特性才会显示出它们的优点
我使用以下两种结构来描述矩阵。为了简单起见,我将省略内存池支持(它允许一个人将一组矩阵作为一个池来管理,一次释放它们,而不必单独管理每个矩阵)以及与多线程操作和线程安全相关的一切
代码可能包含拼写错误;如果您注意到任何问题,请留下评论,我会解决它们
typedef int data_t; /* Matrix element data type */
struct owner {
long refcount; /* Number of referenced to this data */
size_t size; /* Number of elements in data[] */
data_t data[]; /* C99 flexible array member */
};
typedef struct {
int rows; /* Number of rows in this matrix */
int cols; /* Number of columns in this matrix */
long rowstride;
long colstride;
data_t *origin; /* Pointer to element at row 0, col 0 */
struct owner *owner; /* Owner structure origin points to */
} matrix;
#define MATRIX_INIT { 0, 0, 0L, 0L, NULL, NULL }
矩阵m
第r
行、第c
列的元素是m.origin[r*m.rowstride+c*m.colstride]
,假设0 cols=0;
m->rowstride=0升;
m->colstride=0L;
m->origin=NULL;
m->owner=NULL;
如果(第一行+行>src->行||
firstcol+cols>src->cols)
返回errno=EINVAL;
如果(src==NULL | | src->owner==NULL)
返回errno=EINVAL;
如果(src->owner.refcount<1L | | src->owner.size==0)
返回errno=EINVAL;
否则{
++(src->owner.refcount);
m->owner=src->owner;
}
m->origin=src->origin+src->rowstride*第一行
+src->colstride*firstcol;
m->行=行;
m->cols=cols;
m->rowstride=src->rowstride;
m->colstride=src->colstride;
返回0;
}
int矩阵转置自(矩阵*常数m,常数矩阵*常数src)
{
if(m==NULL | | m==src)
返回errno=EINVAL;
m->rows=0;
m->cols=0;
m->rowstride=0升;
m->colstride=0L;
m->origin=NULL;
m->owner=NULL;
如果(src==NULL | | src->owner==NULL)
返回errno=EINVAL;
如果(src->owner.refcount<1L | | src->owner.size==0)
返回errno=EINVAL;
否则{
++(src->owner.refcount);
m->owner=src->owner;
}
m->origin=src->origin;
m->rows=src->cols;
m->cols=src->行;
m->rowstride=src->colstride;
m->colstride=src->rowstride;
返回0;
}
使用与上面类似的代码,您可以创建描述任何行、列或对角线的单行或单列矩阵视图。(对角线在某些情况下特别有用。)
子矩阵可以镜像或旋转,等等。
您可以安全地释放只需要子矩阵或其他视图的矩阵,因为所有者结构引用计数跟踪何时可以安全地丢弃数据
矩阵乘法和其他类似的大型矩阵的复杂操作对缓存局部性问题非常敏感。这意味着您最好将源矩阵数据复制到紧凑的数组中(数组正确对齐,元素的顺序与操作数的顺序正确)。行和列都有一个单独的步幅(而不是像典型的那样只有一个步幅)所造成的开销实际上是最小的;在我自己的测试中,可以忽略不计
然而,这种方法的最佳特性是,它允许您编写高效的代码,而不必担心什么是“真实”矩阵,什么是“视图”,以及实际底层数据如何存储在数组中,除非您在意。
最后,对于任何掌握C语言基本动态内存管理的人来说,它非常简单,完全可以理解。一个“指向类型的指针数组”不是一个2D数组。2D数组是“类型数组的数组”(而不是“数组中的数组”-不管是什么)。您可能需要一个额外的参数来指定正在操作的子矩阵的大小。@IanAbbott可能是,但这不是问题的一部分-可能函数应该在隐式块大小上工作,我不想做任何超出必要的假设。哇,这确实是我要找的!我的实际任务(问题中未提及)是将矩阵旋转90度。但后来我试着用问题中描述的方法去做,结果失败了。我想知道像openCV这样的库是如何实现我的目标的,尽管我知道它涉及到使用指向适当lo的结构
int matrix2[N_SIZE * N_SIZE];
*(pmatrix + X_SIZE*j + i)
matrix[X_SIZE*j + i]
*(pmatrix2 + N_SIZE*j + i)
matrix2[N_SIZE*j + i]
typedef int data_t; /* Matrix element data type */
struct owner {
long refcount; /* Number of referenced to this data */
size_t size; /* Number of elements in data[] */
data_t data[]; /* C99 flexible array member */
};
typedef struct {
int rows; /* Number of rows in this matrix */
int cols; /* Number of columns in this matrix */
long rowstride;
long colstride;
data_t *origin; /* Pointer to element at row 0, col 0 */
struct owner *owner; /* Owner structure origin points to */
} matrix;
#define MATRIX_INIT { 0, 0, 0L, 0L, NULL, NULL }
void matrix_free(matrix *const m)
{
if (m != NULL) {
if (m->owner != NULL && --(m->owner.refcount) < 1L) {
m->owner.size = 0;
free(m->owner);
}
m->rows = 0;
m->cols = 0;
m->rowstride = 0L;
m->colstride = 0L;
m->origin = NULL;
m->owner = NULL;
}
}
int matrix_new(matrix *const m, const int rows, const int cols)
{
const size_t size = (size_t)rows * (size_t)cols;
struct owner *o;
if (m == NULL)
return errno = EINVAL;
m->rows = 0;
m->cols = 0;
m->rowstride = 0L;
m->colstride = 0L;
m->origin = NULL;
m->owner = NULL;
if (rows < 1 || cols < 1)
return errno = EINVAL;
o = malloc(sizeof (struct owner) + size * sizeof (data_t));
if (o == NULL) {
return errno = ENOMEM;
o->refcount = 1L;
o->size = size;
m->rows = rows;
m->cols = cols;
m->origin = o->data;
m->owner = o;
#if DEFAULT_COLUMN_MAJOR > 0
/* Default to column-major element order */
m->rowstride = 1L;
m->colstride = (long)rows;
#else
/* Default to row-major element order */
m->rowstride = (long)cols;
m->colstride = 1L;
#endif
return m;
}
void matrix_transpose(matrix *const m)
{
if (m->rows > 0 && m->cols > 0) {
const int rows = m->rows;
const int cols = m->cols;
const long rowstride = m->rowstride;
const long colstride = m->colstride;
m->rows = cols;
m->cols = rows;
m->rowstride = colstride;
m->colstride = rowstride;
}
}
int matrix_submatrix_from(matrix *const m, const matrix *const src,
const int firstrow, const int firstcol,
const int rows, const int cols)
{
if (m == NULL || m == src)
return errno = EINVAL;
m->rows = 0;
m->cols = 0;
m->rowstride = 0L;
m->colstride = 0L;
m->origin = NULL;
m->owner = NULL;
if (firstrow + rows > src->rows ||
firstcol + cols > src->cols)
return errno = EINVAL;
if (src == NULL || src->owner == NULL)
return errno = EINVAL;
if (src->owner.refcount < 1L || src->owner.size == 0)
return errno = EINVAL;
else {
++(src->owner.refcount);
m->owner = src->owner;
}
m->origin = src->origin + src->rowstride * firstrow
+ src->colstride * firstcol;
m->rows = rows;
m->cols = cols;
m->rowstride = src->rowstride;
m->colstride = src->colstride;
return 0;
}
int matrix_transposed_from(matrix *const m, const matrix *const src)
{
if (m == NULL || m == src)
return errno = EINVAL;
m->rows = 0;
m->cols = 0;
m->rowstride = 0L;
m->colstride = 0L;
m->origin = NULL;
m->owner = NULL;
if (src == NULL || src->owner == NULL)
return errno = EINVAL;
if (src->owner.refcount < 1L || src->owner.size == 0)
return errno = EINVAL;
else {
++(src->owner.refcount);
m->owner = src->owner;
}
m->origin = src->origin;
m->rows = src->cols;
m->cols = src->rows;
m->rowstride = src->colstride;
m->colstride = src->rowstride;
return 0;
}