开发者

The structure of a matrix

开发者 https://www.devze.com 2023-02-05 02:31 出处:网络
I am a complete noob at C (<1 week) and I\'m trying to get a grasp how to work on it, although I\'m familiar with programming in other languages. As a first goal, I wanted to write a function to do

I am a complete noob at C (<1 week) and I'm trying to get a grasp how to work on it, although I'm familiar with programming in other languages. As a first goal, I wanted to write a function to do Gauss reduction on a matrix. I have no problem with the algorithm, but it turned out I do not know how to represent a matrix. For simplicity, let me assume that we work with float entries.

The first naif way would be to use an array of arrays like

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

The problem is that you cannot pass such an object as an argument without knowing the dimensions a priori (of course I want to be able to use matrices of arbitrary size, which is not known at compilation time). One does not see this problem when working with vectors and representing them as arrays. If I do

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

it will work, provided I declare norm like

norm(float * vector);

When vector is passed, it is converted to &vector[0], and not much information is lost (basically one has to keep track of the length). But I cannot just call

gaussReduction(naifMatrix);

and declare gaussReduction with

gaussReduction(float ** naifMatrix);

b开发者_运维问答ecause naifMatrix is converted (and rightly so) to a pointer to an array of floats, not in a pointer to a pointer. Since I do not know how big this array will be, I do not see a way to declare gaussReduction.

Of course I could cheat by passing a pointer to a void, but before dereferencing it, I would need to cast it to the right type (float[3] *), which, again, I do not know a priori. Moreover it seems to me that by abusing of void * one defeats one of the purposes of using C over other languages, which is a strict type checking.

The best solution I have found so far is to use a struct. A matrix is basically given by the list of its entries and the two dimensions. So I can do

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

and use it as

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

The problem is that this is still annoying. First it is akward to get a struct matrix from a double array, and second one has to give the dimensions explicitly. I would be happy with wrapping this with a sort of "constructor" function, like

struct matrix matrix = Matrix(naifMatrix);

but I cannot do this for two reasons. First, I have the same problem as above in passing naifMatrix as argument to a function. Second, even if I could pass it, I would get a pointer, and thus I would not be able to get information on the dimensions (in this case, that both are 3).

Is there a more sensible way to pass around and manipulate the datum of a matrix?


C99 added variable-length arrays to the language:

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

If you have the definition

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

you can get at the dimensions via

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

You can use macros to minimize repetition. Using

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

you'd end up with

gaussReduction(matrixarg(naifMatrix));

or, using a compound literal instead of a variable, with

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

Using a variable-length array has the same performance characteristics as the equivalent C90 code - the only thing you'll gain is nicer syntax:

// 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];


If you define thus:

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

You should have a pointer to an array of pointers. Then you can use

gaussReduction(float ** naifMatrix);

My C is rusty, though.

0

精彩评论

暂无评论...
验证码 换一张
取 消