Написание функций для матричных операций с указателями

Я хотел бы написать функции, которые выполняют общие матричные операции. Это можно сделать с помощью двумерных массивов или арифметики указателей. Я предпочитаю версию с указателем. Теперь с указателями я бы написал такую ​​​​функцию:

void matmult(double *a, double *b, double *c, int m, int n, int k); 

Проблема в том, что я должен использовать приведение, когда я передаю 2-мерные массивы в функцию. Есть ли хорошее решение, чтобы избежать этой проблемы?

Работает без приведения (конечно), но я хочу избежать предупреждений компилятора.

Обновление: массивы определены как 2-мерный массив, а вызывающая функция выглядит так:

// M, N, K are constants
double a[M][N];
double b[N][K];
double c[M][K];
matmult((double *)a, (double *)b, (double *)c, M, N, K);  

Функция matmult — это прямая реализация матричного умножения (три вложенных цикла for с использованием указателей).

*(c + i*k + j) += *(a + i*n + p) * *(b + p*k + j);

Я просто хочу избавиться от гипса.

ну, это зависит от того, как выглядит ваш 2d-массив, покажите код вызова и покажите код в matmult

pm100 20.11.2022 23:22

Почему бы вам не хранить размеры матрицы в самой матрице, а также в массиве чисел; это то, что делает математика.

Neil 21.11.2022 07:55

@Neil Что бы ты сделал? Обратите внимание, что размеры матрицы не являются проблемой, поскольку вызывающая сторона должна убедиться, что они имеют правильные размеры. Проблема заключается в несоответствии типов между double * и (*doube)[].

bernhard67 22.11.2022 08:09
stackoverflow.com/q/42094465/16835308
Zakk 22.11.2022 11:39
Шаблоны Angular PrimeNg
Шаблоны Angular PrimeNg
Как привнести проверку типов в наши шаблоны Angular, использующие компоненты библиотеки PrimeNg, и настроить их отображение с помощью встроенной...
Создайте ползком, похожим на звездные войны, с помощью CSS и Javascript
Создайте ползком, похожим на звездные войны, с помощью CSS и Javascript
Если вы веб-разработчик (или хотите им стать), то вы наверняка гик и вам нравятся "Звездные войны". А как бы вы хотели, чтобы фоном для вашего...
Документирование API с помощью Swagger на Springboot
Документирование API с помощью Swagger на Springboot
В предыдущей статье мы уже узнали, как создать Rest API с помощью Springboot и MySql .
Начала с розового дизайна
Начала с розового дизайна
Pink Design - это система дизайна Appwrite с открытым исходным кодом для создания последовательных и многократно используемых пользовательских...
Шлюз в PHP
Шлюз в PHP
API-шлюз (AG) - это сервер, который действует как единая точка входа для набора микросервисов.
14 Задание: Типы данных и структуры данных Python для DevOps
14 Задание: Типы данных и структуры данных Python для DevOps
проверить тип данных используемой переменной, мы можем просто написать: your_variable=100
0
4
51
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий
static void matmult(double a[][N], double (*b)[K], double c[M][K], int m, int n, int k);

Этот прототип работает для передачи двумерных массивов. См. эту запись C FAQ или Массив для уменьшения указателя и передачи многомерных массивов функциям. M в c[M][K] совершенно лишний в C, но может быть полезен в качестве самостоятельной документации (или может еще больше запутать читателя).

Однако это не очень инкапсулировано, и я бы не стал программировать с этим общий матричный алгоритм. Размер является неотъемлемой частью самой матрицы. Я мог бы использовать элемент гибкого массива C99 для хранения размера и данных вместе, если он не является частью других структур.

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <stdarg.h>
#include <limits.h>

struct matrix {
    unsigned x, y;
    double data[]; /* flexible array member */
};

/** Constructor; data is uninitialized. */
static struct matrix *matrix(const unsigned x, const unsigned y) {
    if(!x || !y || x >= UINT_MAX / y) { errno = ERANGE; return 0; }
    struct matrix *const m = malloc(offsetof(struct matrix, data)
        + sizeof *m->data * x * y);
    if(!m) return 0;
    m->x = x, m->y = y;
    return m;
}

/** Constructor; IBM has a useful extension that allows stack construction. */
static struct matrix *matrix_init(const unsigned x, const unsigned y, ...) {
    struct matrix *const m = matrix(x, y);
    if(!m) return 0;
    va_list argp;
    va_start(argp, y);
    for(unsigned i = 0, size = x * y; i < size; i++)
        m->data[i] = va_arg(argp, double);
    va_end(argp);
    return m;
}

static void matrix_print(const struct matrix *const m) {
    if(!m) { printf("null\n"); return; }
    for(unsigned y = 0; y < m->y; y++) {
        printf("[");
        for(unsigned x = 0; x < m->x; x++)
            printf("%s%4.f", x ? ", " : "", m->data[y * m->x + x]);
        printf("]\n");
    }
}

static struct matrix *matmult(const struct matrix *a,
    const struct matrix *b) {
    if(!a || !b || a->y != b->x) { errno = EDOM; return 0; }
    struct matrix *const c = matrix(b->x, a->y);
    if(!c) return 0;
    for(unsigned y = 0; y < a->y; y++)
        for(unsigned x = 0; x < b->x; x++)
            c->data[y * b->x + x] = 0.0;
    /* implement:
     *(c + i*k + j) += *(a + i*n + p) * *(b + p*k + j); */
    return c;
}

int main(void) {
    struct matrix *a = 0, *b = 0, *c = 0;
    int success = EXIT_SUCCESS;
    if(!(a = matrix_init(2, 2, 1.0, 2.0, 3.0, 4.0))
        || !(b = matrix_init(2, 2, 3.0, 20.0, 1.0, 0.0))) goto catch;
    matrix_print(a), printf("*\n"), matrix_print(b);
    if(!(c = matmult(a, b))) goto catch;
    printf("=\n"), matrix_print(c);
    goto finally;
catch:
    success = EXIT_FAILURE;
    perror("matrix");
finally:
    free(a), free(b), free(c);
    return success;
}

Вот как я наконец решил свою проблему благодаря подсказке @Neil:

void matrixmult(double (*a)[], double (*b)[], double (*c)[], int m, int n, int k)
{
   for (...)
       for (..)
          for (...)
              *((double *)c + i*k + j) = ...
}

Теперь функцию можно вызывать без приведения, и я избегаю ограничений функции C99 VLA (сначала должны быть переданы размеры).

Другие вопросы по теме