Попытка написать матричный множитель для матриц произвольного размера - PullRequest
2 голосов
/ 17 июня 2011

Пытаясь написать функцию умножения матриц для матриц произвольного размера в C. Я пытаюсь сделать следующее для моей сигнатуры функции:

void matrixMult(void *A, int Xa, int Ya, void *B, int Xb, int Yb);

(пока я возвращаюсь к нему, я возвращаю void, я вернусь позже, как только он заработает так, как я хочу)

Параметры X и Y предназначены для информирования функции о размерах входящих массивов (насколько я понимаю, это необходимо, поскольку в массивах C не известны их собственные размеры). Итак, я передаю два пустых указателя A и B, а также их размеры.

Мой вопрос: Как только я нахожусь в функции, как мне перейти к приведению пустых указателей обратно к массивам int, чтобы я мог их прочитать? Я попробовал следующее:

(int)*A[someX][someY]

, но я получаю ошибку компилятора о «недопустимом использовании пустого указателя».


EDIT

Следующее - моя полная функция на данный момент (обновляется, так как я ее устраняю):

#pragma warning(disable: 8057)
#include <stdio.h>

void matrixMult(int **A, int Xa, int Ya, int **B, int Xb, int Yb);

int main(int argc, char *argv[]) {
    //   [x][y] x--> row; y-->cols
    int a[3][5] = {
          {  1,  2,  3,  4,  5 }
        , { 10, 20, 30, 40, 50 }
        , {  4,  8, 15, 16, 23 }
    };
    int b[5][7] = {
          {  1,  2,  3,  4,  5,  6,  7 }
        , { 10, 20, 30, 40, 50, 60, 70 }
        , {  4,  8, 15, 16, 23, 42,  0 }
        , {  1,  2,  3,  4,  5,  6,  7 }
        , { 10, 20, 30, 40, 50, 60, 70 }
    };

    matrixMult((int **)a, 3, 5, (int **)b, 5, 7);

    printf("done\n");
    return 0;
}

void matrixMult(int **A, int Xa, int Ya, int **B, int Xb, int Yb) {
    printf("starting matrix mult\n");
    int i, j;

    for (i=0; i<Xa; i++) {
        for (j=0; j<Ya; j++) {
            //printf("%i, %i:\t", i, j);
            printf("%i\t", A[Ya*i+j]);
        }
        printf("\n");
    }
}

РЕДАКТИРОВАТЬ 2 Спасибо за советы и ресурсы, ребята! Вышеприведенная версия работает так, как я ожидаю, но я боюсь, что это отвратительная форма того, как указатели ПРЕДЛАГАЕТСЯ использовать. Сейчас я собираюсь еще немного почитать указатели (спасибо cnicutar!), И я вернусь к этому позже. Любая дальнейшая критика моей последней версии приветствуется, но я отмечаю этот ответ и продолжаю читать дальше. Еще раз спасибо!

Ответы [ 4 ]

5 голосов
/ 17 июня 2011

Если я правильно понимаю ваш вопрос вы могли бы сделать что-то вроде

int **a = A;

Почему вы используете void *, а не int **A сразу?

РЕДАКТИРОВАТЬ 1

В свете комментария ниже: см. эту запись FAQ (f3 - это то, что вы хотите). А также этот .

Редактировать 2

Объявите и инициализируйте их (что-то) следующим образом:

int **a;

a = malloc(sizeof(*a) * 3);
for (i = 0; i < 3; i++) {
    a[i] = malloc(sizeof(int) * 5);
}
3 голосов
/ 17 июня 2011

Прототип должен быть двойным указателем. Также вам не нужно отменять ссылки (если только ваш самый внутренний указатель не является самим указателем), так как вы приводите его к типу int. Если тип не был int *.

void matrixMult(void **A, int Xa, int Ya, void **B, int Xb, int Yb);

Нет необходимости отменять ссылки, поскольку это просто базовый int.

(int)A[someX][someY]

Если бы у вас было, скажем, int *, вам нужно было бы разыменовать его, но даже тогда вы бы разыменовывали за пределами актерского состава

*(int *)A[someX][someY]

Вы должны сообщить компилятору, что это за тип, прежде чем сможете разыменовать указатель. В противном случае вы получите ошибку при попытке разыменования пустоты *.

1 голос
/ 17 июня 2011

Если у вас есть C99, вы можете просто использовать для этого массивы переменной длины, они созданы для него.Забудьте об указателях на указатели и просто выполните

void matrixMult(size_t n, size_t m, size_t k, double A[n][m], double B[m][k], double C[n][k]);

Важно, чтобы размеры были первыми в списке параметров, чтобы они были известны, когда речь идет о A, B и C.Внутри вашей функции вы можете просто получить доступ к отдельным элементам матрицы, например, A[i][j].

Затем, чтобы выделить такие матрицы, вы должны быть немного осторожны, чтобы не разместить их в стеке.Например,

double (*A)[n][m] = malloc(*A);

должно подойти.

Действительно попытайтесь забыть об определении матриц как массива указателей, где для каждого указателя вы должны выделить свой собственный блок и так далее.Это очень сложно, подвержено ошибкам и добавляет ненужный уровень косвенности.

0 голосов
/ 17 июня 2011

void* не является параметром типа шаблона. Поскольку вам нужно привести указатель к какому-либо типу, а именно к типу данных, на которые указывает указатель, и все операции скомпилированы с этим типом, использование только указателя void* имеет только очень небольшой смысл. Либо добавьте параметр, сообщающий, какой тип типа передается, и соответственно разветвите в функции, либо лучше используйте правильные типы и назовите функции соответствующим образом. Также не следует использовать двойные указатели: в зависимости от распределения памяти это может нарушить локальность кэша.

Для сохранения набора используйте макросы:

#define MATRIXMULT(type, typeshort) void matrixMult##typeshort(\
##type *A, int const Xa, int const Ya, ##type *B, int const Xb, int const Yb)\
{ \
    printf("starting matrix mult\n"); \
    int i, j, k; \
\
    if(Ya != Xb || Xa != Yb) \
        return; // dimensions don't match \
\
    for (i=0; i<Xa; i++) { \
        for (j=0; j<Ya; j++) { \
            A[i*Ya + j]=0; \
            for(k=0; k < Xa; k++) \
                A[i*Ya + j] += A[i*Ya + k] * B[k*Yb + j]; \
    } \
}

MATRIXMULT(double, d)
MATRIXMULT(float, f)
MATRIXMULT(int, i)

РЕДАКТИРОВАТЬ из-за комментария:

MATRIXMULT(double, d) расширяется до

void matrixMultd(
double *A, int const Xa, int const Ya, double *B, int const Xb, int const Yb)
{ 
    printf("starting matrix mult\n"); 
    int i, j, k; 

    if(Ya != Xb || Xa != Yb) 
        return;

    for (i=0; i<Xa; i++) { 
        for (j=0; j<Ya; j++) { 
            A[i*Ya + j]=0; 
            for(k=0; k < Xa; k++) 
                A[i*Ya + j] += A[i*Ya + k] * B[k*Yb + j]; 
    } 
}

Таким образом, используя макросы, очень легко получить одну и ту же функцию в нескольких вариантах. С вышеупомянутыми расширениями макросов вы можете звонить matrixMultd, matrixMultf и matrixMulti

...