【问题标题】:The structure of a matrix矩阵的结构
【发布时间】:2011-06-11 02:09:19
【问题描述】:

我是 C 的完全菜鸟(float 条目。

第一种天真的方法是使用数组数组,例如

float naifMatrix[3][3] = {
    {2, 1, 3},
    {0, -1, 4},
    {1, 3, 0}
};

问题是你不能在不知道先验维度的情况下将这样的对象作为参数传递(当然我希望能够使用任意大小的矩阵,这在编译时是未知的)。在使用向量并将它们表示为数组时,人们看不到这个问题。如果我这样做了

float vector[3] = {1, 2, 3};
norm(vector);

只要我声明 norm 喜欢,它就会起作用

norm(float * vector);

vector被传递时,它被转换为&vector[0],并且不会丢失太多信息(基本上必须跟踪长度)。但我不能只是打电话

gaussReduction(naifMatrix);

并声明gaussReduction

gaussReduction(float ** naifMatrix);

因为naifMatrix 被转换(并且正确地如此)为指向浮点数组的指针,而不是指向指针的指针。由于我不知道这个数组会有多大,所以我看不到声明 gaussReduction 的方法。

当然,我可以通过传递一个指向 void 的指针来作弊,但在取消引用它之前,我需要将它转换为正确的类型 (float[3] *),这也是我不知道先验的。此外,在我看来,滥用 void * 会破坏使用 C 而非其他语言的目的之一,即严格的类型检查。

到目前为止,我发现的最佳解决方案是使用结构。矩阵基本上由其条目列表和两个维度给出。所以我可以做

struct matrix {
    float * begin;
    int rows, columns;
};

并将其用作

struct matrix matrix = {&naifMatrix[0], 3, 3};

问题是这仍然很烦人。首先,从双精度数组中获取struct matrix 是不公平的,第二个必须明确给出尺寸。我很乐意用一种“构造函数”函数来包装它,比如

struct matrix matrix = Matrix(naifMatrix);

但我不能这样做有两个原因。首先,在将naifMatrix 作为参数传递给函数时,我遇到了与上述相同的问题。其次,即使我可以通过它,我也会得到一个指针,因此我无法获得有关维度的信息(在这种情况下,两者都是 3)。

有没有更明智的方法来传递和操作矩阵的数据?

【问题讨论】:

  • 我建议您购买一份C 中的数字食谱 并阅读。你会在那里学到你需要的一切,以及更多。
  • @David:谢谢,但这不仅仅是我想做的。 :-) 我只是在玩学C,我不期待建立一个线性代数库。
  • stackoverflow.com/questions/16004668/… 在上面你会发现一个程序,我用任何可能的方式为 C (gcc C11/C99) 分配和操作矩阵的函数。也许4u会有用...

标签: c matrix


【解决方案1】:

C99 向语言中添加了可变长度数组:

_Bool gaussReduction(size_t rows, size_t cols, float matrix[rows][cols]);

如果你有定义

float naifMatrix[3][3] = {
    {2, 1, 3},
    {0, -1, 4},
    {1, 3, 0}
};

您可以通过以下方式获取尺寸

size_t rows = sizeof naifMatrix / sizeof *naifMatrix;
size_t cols = sizeof *naifMatrix / sizeof **naifMatrix;

您可以使用宏来最大程度地减少重复。使用

#define rowsof(MATRIX) (sizeof (MATRIX) / sizeof *(MATRIX))
#define colsof(MATRIX) (sizeof *(MATRIX) / sizeof **(MATRIX))
#define matrixarg(MATRIX) rowsof(MATRIX), colsof(MATRIX), (MATRIX)

你最终会得到

gaussReduction(matrixarg(naifMatrix));

或者,使用复合文字而不是变量,

gaussReduction(matrixarg(((float [3][3]){ 
    {2, 1, 3},
    {0, -1, 4},
    {1, 3, 0}
})));

使用可变长度数组与等效的 C90 代码具有相同的性能特征 - 您将获得的唯一好处是更好的语法:

// C99:
_Bool gaussReduction(size_t rows, size_t cols, float matrix[rows][cols])
{
    // size_t i = ..., j = ...
    float x = matrix[i][j];

/* C90: */
int gaussReduction(size_t rows, size_t cols, float *matrix)
{
    /* size_t i = ..., j = ... */
    float x = matrix[i * cols + j];

【讨论】:

  • 非常感谢!我想这就是从一本关于他标准的先前版本的书中学习 C 的结果...... :-D 顺便说一句,相对于固定大小使用可变大小的数组时是否会出现性能损失?
  • @Andrea:可变长度数组仅在编译时不知道数组大小的情况下会带来性能损失 - 但是,无论如何将数组作为函数参数传递时,此信息都会丢失;我将添加一些有关 C90 的详细信息以作为我的答案...
【解决方案2】:

如果你这样定义:

float naifMatrix[][] = {
    {2, 1, 3},
    {0, -1, 4},
    {1, 3, 0}
};

您应该有一个指向指针数组的指针。然后就可以使用了

gaussReduction(float ** naifMatrix);

不过,我的 C 已经生锈了。

【讨论】:

  • C 数组不是锯齿状的 - 您不能将二维数组转换为指针到指针
  • 不能声明naifMatrix[][]这样的数组。只有第一个数组下标是可选的。应该是naifMatrix[][3]
  • 这正是我的问题。二维数组最多会转换成指向数组的指针。
  • 其实这并没有错:指向指针的指针将是完全不同类型的数据。但事实仍然是,我希望至少能够获得一个指向数据块开头的指针,我不知道该怎么做。
  • 那么不要静态声明/定义它。 gah,我不能在我的评论中插入换行符?嘘。啊,我可以复制粘贴它们。浮动 **naifMatrix;浮动 *naifMatrix1 = {2,1,3}; naifMatrix = malloc(3 * sizeof(float *)); naifMatrix[0] = naifMatrix1;类似的东西,也许?就像我说的,我的 C 生锈了。
猜你喜欢
  • 1970-01-01
  • 2017-04-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-08-14
  • 1970-01-01
  • 2011-07-21
  • 1970-01-01
相关资源
最近更新 更多