计算矩阵乘法C程序

vc9ivgsu  于 2022-12-03  发布在  其他
关注(0)|答案(4)|浏览(152)

我正在尝试编写一个C程序来计算MN,其中M是一个方阵,N是一个整数。但是,每次我输入N的值后,它都会崩溃。有人能识别出它的问题吗?我想这是关于指针的问题,但我不明白需要对它们做什么修改。任何帮助都将非常感激。

#include <stdio.h>
#include <math.h>
#include <stdlib.h>

double *multiply(int M, double **A, double **B) {
    double **C = (double **)malloc(M * sizeof(double));

    for (int i = 0; i < M; i++) {
        C[i] = (double *)malloc(M * sizeof(double));
    }

    for (int i = 0; i < M; i++) {
        for (int j = 0; j < M; j++) {
            for (int k = 0; k < M; k++) {
                C[i][j] += A[i][k] * B[k][j];
            }
        }
    }

    return *C;
}

void arrcpy(int M, double **A, double **B) {
    for (int i = 0; i < M; i++) {
        for (int j = 0; j < M; j++) {
            A[i][j] = B[i][j];
        }
    }
    return;
}

int main() {
    int i, j, N, M;

    printf("M = ");
    scanf("%d", &M);

    double **R = (double **)malloc(M * sizeof(double));
    for (i = 0; i < M; i++) {
        R[i] = (double *)malloc(M * sizeof(double));
    }

    for (i = 0; i < M; i++) {
        for (j = 0; j < M; j++) {
            printf("R[%d][%d] = ", i, j);
            scanf("%lf", &R[i][j]);
        }
    }

    printf("N = ");
    scanf("%d", &N);

    double **C;
    arrcpy(M, C, R);
    for (i = 1; i < N; i++) {
        *C = multiply(M, C, R);
    }

    for (i = 0; i < M; i++) {
        for (j = 0; j < M; j++) {
            printf("%lf ", C[i][j]);
        }
        printf("\n");
    }

    return 0;
}
dba5bblo

dba5bblo1#

在我看来,最好的方法是实现fast exponentiation algorithm,如下面的代码所示。
显示的代码允许您使用特殊类型的矩阵,每个矩阵只需要一个malloc()调用(我不会用代码中的问题来打扰你,这些问题已经在其他答案中得到了回答)矩阵(我提供了m_rowsm_cols字段,以便能够保存矩形矩阵,而实现的重点是要解决的问题,其是矩阵幂提升)存储在存储器的单个块中,所述存储器的单个块包括用于struct matrix本身、行阵列的指针以及行本身的空间(应该没有对准问题,因为所有的块都已经使用指针算法被适当地寻址)。它通过移动两个适当类型的指针将指针初始化到适当的位置(一个double指针用于移动到下一单元以初始化单元,而另一个double *指针用于移动到下一行,用于初始化指向行的指针)* 提供程序函数 * 的集合(所有前缀为prov_的)允许您使用相同的例程以多种不同的方式初始化矩阵。如果提供NULL作为提供程序,则不会执行单元格初始化(例如在矩阵乘法中,初始化是由乘积例程完成的)。学习它,因为它非常快。
我已经实现了矩阵创建例程(对返回值的单个free()调用就足以释放整个矩阵)和用于添加、初始化的操作(以多种方式(从一个文件、从一个数组、从一个FILE *流,......其中有些在程序中没有使用,但是无论如何都是为了说明使用提示而提供的),因此您可能会将其用作参考实现。示例代码使用了一个样本矩阵,并测试了特征多项式应用于矩阵时会产生零矩阵。对于测试用例,使用快速取幂的方法没有用,因为我们需要使用从0到4的所有幂,但无论如何都要使用mat_pow()例程来演示它是如何工作的。

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

/* structure to hold all the data for a matrix.  See discussion
 * in comments to understand this structure. */
struct matrix {
    int m_rows, m_cols;
    double **m_data;
    double  *unused_1; /* not used.  Only to warrant the 
                        * alignment to double * values. */
    double   unused_2; /* same as before. */
};

/* this are simple providers of matrix data, depending on how we
 * want to initialize the matrix. */

/* initializes each element to a constant provided by reference
 */
double prov_const(void *cb_par, int row, int col)
{
    double *val_ref = cb_par;
    return *val_ref;
}

double prov_list(void *cb_par, int row, int col)
{
    double **p = cb_par;
    return *(*p)++;
}

double prov_copy(void *cb_par, int row, int col)
{
    struct matrix *src = cb_par;

    assert(row < src->m_rows && col < src->m_cols);
    return src->m_data[row][col];
}

/* initializes kroneker matrix. Identity */
double prov_ident(void *unused, int row, int col)
{
    return row == col ? 1.0 : 0.0;
}

/* provides elements from file stream */
double prov_file(void *cb_par, int row, int col)
{
    FILE *in = cb_par;
    double ret_val;
    if (isatty(fileno(in))) {
        fprintf(stderr,
                "mat[%d][%d]: ",
                row, col);
        fflush(stderr);
    }
    int res = fscanf(in, "%lg", &ret_val);
    assert(res == 1);
    return ret_val;
}

/* this creates the whole matrix with just one malloc */
struct matrix *mat_creat(
    int rows, int cols, /* dimensions */
    double prov(void *cd, int row, int col), /* initializer */
    void *cd) /* initializer callback data */
{
    size_t total_cells = rows * cols;

    /* See discussion about alignment in the comments to
     * understand the code below. */
    struct matrix *ret_val = malloc(
        sizeof *ret_val
        + rows * sizeof *ret_val->m_data
        + total_cells * sizeof **ret_val->m_data);

    assert(ret_val != NULL);

    /* place the array with bigger element cell first,
     * to warrant the smaller data alignment */
    double **aux1; /* pointer to array of row pointers */
    double *aux2; /* pointer to array of double cells */
    if (sizeof *ret_val->m_data > sizeof **ret_val->m_data) {
        /* put the pointers to rows first, pointer is bigger */
        aux1 = (double **) (ret_val + 1); /* row pointers array */
        aux2 = (double *) (aux1 + rows); /* double row arrays */
    } else {
        /* put the cells first, double is bigger than pointer */
        aux2 = (double *) (ret_val + 1);
        aux1 = (double **) (aux2 + total_cells);
    }

    ret_val->m_rows = rows;
    ret_val->m_cols = cols;
    ret_val->m_data = aux1;

    /* start the build */
    for (int row = 0; row < rows; row++) {
        *aux1++ = aux2; /* the pointer to the row */
        if (prov) {
            for (int col = 0; col < cols; col++) {
                /* this provides each element of the row */
                *aux2++ = prov(cd, row, col);
            }
        } else {
            /* no provider, no cell initialization */
            aux2 += cols;
        }
    }
    return ret_val;
}

struct matrix *mat_add(struct matrix *dst, struct matrix *b)
{
    assert(dst->m_rows == b->m_rows
        && dst->m_cols == b->m_cols);

    for (int row = 0; row < dst->m_rows; row++) {
        for (int col = 0; col < dst->m_cols; col++) {
            dst->m_data[row][col] += b->m_data[row][col];
        }
    }
    return dst;
}

struct matrix *mat_mscalar(struct matrix *dst, double b)
{
    for (int row = 0; row < dst->m_rows; row++) {
        for (int col = 0; col < dst->m_cols; col++) {
            dst->m_data[row][col] *= b;
        }
    }
    return dst;
}

struct matrix *mat_prod(struct matrix *a, struct matrix *b)
{
    assert(a->m_cols == b->m_rows);

    struct matrix *ret_val
        = mat_creat(a->m_rows, b->m_cols, NULL, NULL);

    for(int row = 0; row < a->m_rows; row++) {
        for (int col = 0; col < b->m_cols; col++) {
            double accum = 0.0;
            for (int k = 0; k < a->m_cols; k++) {
                accum += a->m_data[row][k]
                       * b->m_data[k][col];
            }
            ret_val->m_data[row][col] = accum;
        }
    }
    return ret_val;
}

trix *mat_pow(struct matrix *a, unsigned N)
{
    /* ensure matrix is square */
    assert(a->m_rows == a->m_cols);

    struct matrix *ret_val
        = mat_creat(a->m_rows, a->m_cols,
                prov_ident, NULL);

    if (N == 0) return ret_val;  /* a**0 -> I */

    /* search for most significant bit */
    unsigned bit = 0;
    while ((1 << bit) < N) bit++;
    bit = 1 << bit;

    while (bit) {
        /* square it */
        struct matrix *aux = mat_prod(ret_val, ret_val);
        free(ret_val); /* must free after multiplying */
        ret_val = aux; /* assign the new matrix. */

        if (bit & N) { /* multiply by a */
            aux = mat_prod(ret_val, a);
            free(ret_val);
            ret_val = aux;
        }
        bit >>= 1;
    }
    return ret_val;
}

ssize_t mat_print(struct matrix *m, FILE *out, char *fmt)
{

#define ACT() do{         \
        if (n < 0) {      \
            return n;     \
        } else {          \
            ret_val += n; \
        }                 \
    } while (0)

    ssize_t ret_val = 0, n;
    char *sep1 = "{";
    for (int row = 0; row < m->m_rows; row++) {
        n = fprintf(out, "%s", sep1);
        ACT();
        sep1 = ",\n ";
        char *sep2 = "{";
        for (int col = 0; col < m->m_cols; col++) {
            n = fprintf(out, "%s", sep2);
            ACT();
            sep2 = ", ";
            n = fprintf(out, fmt, m->m_data[row][col]);
            ACT();
        }
        n = fprintf(out, "}");
        ACT();
    }
    n = fprintf(out, "}\n");
    ACT();
    return ret_val;
}

int main(int argc, char **argv)
{
    static double values[] = {
        1.0, 2.0, 3.0, 4.0,
        0.0, 1.0, 5.0, 6.0,
        0.0, 0.0, 1.0, 7.0,
        0.0, 0.0, 0.0, 1.0,
    };
    static double coefs[] = {
        1.0, -4.0, 6.0, -4.0, 1.0,
    };
    static double zero = 0.0;
    double *p = values;

    struct matrix *M = mat_creat(4, 4, prov_list, &p);
    printf("M =\n");
    mat_print(M, stdout, "%g");

    struct matrix *P = mat_creat(4, 4, prov_const, &zero);

    printf("P[M] = ");
    for (int coef = 0; coef <= 4; coef++) {
        if (coef) {
            if (coefs[coef] > 0.0) {
                printf(" +");
            } else {
                printf(" ");
            }
        }
        printf("%g * %s", coefs[coef], coef ? "A" : "I");
        if (coef > 1) {
            printf("^%d", coef);
        }
    }
    printf(" =\n");
    for (int coef = 0; coef <= 4; coef++) {
        printf("M\n");
        mat_print(M, stdout, "%g");
        printf("**%d\n", coef);
        struct matrix *TN = mat_pow(M, coef);
        mat_print(TN, stdout, "%g");
        TN = mat_mscalar(TN, coefs[coef]);
        printf("*%lg\n", coefs[coef]);
        mat_print(TN, stdout, "%g");
        P = mat_add(P, TN);
        printf("+\n");
        mat_print(P, stdout, "%g");
        free(TN);
    }
    free(P);
    free(M);
}
yeotifhr

yeotifhr2#

@tshiono给出的答案已经指出了OP代码中的一些问题,比如C未初始化使用、错误的动态分配等。
这个答案将建议一种替代的内存分配方法。
OP使用的方法是一个M个指针的数组,其中每个指针指向一个M个双精度数组。这种方法要求首先通过一个malloc调用分配M个指针的数组,然后为每个双精度数组分配一个malloc循环。也就是说,M+1个malloc调用用于单个矩阵。
通过将矩阵变量声明为一个指向M个double的数组的指针,可以将其简化为一个malloc

double (*R)[M] = malloc(M * sizeof *R);
\------------/   \-------------------/
 R is a pointer   Allocate M x M doubles
 to an array      in a single malloc call
 of M double

同样,释放此类型的对象将只需要一次free调用,而不是M+1次调用。
另一个好处是矩阵将存储在一个连续的内存块中。这允许使用memcpy复制矩阵,而不是编写自定义函数。
这可能类似于:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void multiply(int M, double (*restrict result)[M], double (*A)[M], double (*B)[M])
{
  for(int i=0; i<M; i++) {
    for(int j=0; j<M; j++) {
      result[i][j] = 0;
      for(int k=0; k<M; k++) {
        result[i][j] += A[i][k] * B[k][j];
      }
    }
  }
}

int main()
{
    int i, j, N, M;

    printf("M = ");
    if (scanf("%d",&M) != 1) exit(1);

    double (*R)[M] = malloc(M * sizeof *R);
    double (*C)[M] = malloc(M * sizeof *C);
    double (*T)[M] = malloc(M * sizeof *T);
    if (R == NULL || C == NULL || T == NULL) exit(1);

    for(i=0; i<M; i++) {
        for(j=0; j<M; j++) {
            printf("R[%d][%d] = ", i, j);
            if (scanf("%lf", &R[i][j]) != 1) exit(1);
        }
    }

    printf("N = ");
    if (scanf("%d",&N) != 1) exit(1);

    memcpy(C, R, M * sizeof *R);

    for(i = 1; i < N; i++) {
      multiply(M, T, C, R);
      memcpy(C, T, M * sizeof *R);
    }

    for(i = 0; i < M; i++) {
        for(j = 0; j < M; j++) {
            printf("%lf ", C[i][j]);
        }
        printf("\n");
    }

    free(R);
    free(C);
    free(T);

    return 0;
}

在上面的代码中,乘法的结果以T结尾,然后复制到C以供下一次循环迭代,这有点烦人。我们可以通过更改以下内容来避免这种情况:

memcpy(C, R, M * sizeof *R);

    for(i = 1; i < N; i++) {
      multiply(M, T, C, R);
      memcpy(C, T, M * sizeof *R);
    }

// Make sure that an even number of multiplications is needed after this block
    if (N > 1 && (N & 1) == 0) {
      multiply(M, C, R, R);
      --N;
    } else {
      memcpy(C, R, M * sizeof *R);
    }

    // Do two multiplications in each loop
    for(i = 1; i < N; i += 2) {
      multiply(M, T, C, R);
      multiply(M, C, T, R);
    }

有点复杂,但它避免了循环内的memcpy

uqxowvwt

uqxowvwt3#

请尝试以下操作:

#include <stdio.h>
#include <stdlib.h>

/*
 * multiply square (MxM) matrices: A = B * C
 */
void multiply(int M, double **A, double **B, double **C)
{
    for (int i = 0; i < M; i++) {
        for (int j = 0; j < M; j++) {
            A[i][j] = 0;        // initialize cells
            for(int k = 0; k < M; k++) {
                A[i][j] += B[i][k] * C[k][j];
            }
        }
    }
}

/*
 * copy square (MxM) matrix: A := B
 */
void matcpy(int M, double **A, double **B)
{
    for (int i = 0; i < M; i++) {
        for (int j = 0; j < M; j++) {
            A[i][j] = B[i][j];
        }
    }
}

int main()
{
    int i, j, N, M;
    char buf[BUFSIZ];

    printf("M = ");
    fgets(buf, sizeof buf, stdin);
    sscanf(buf, "%d", &M);

    double **R = malloc(M * sizeof(double *));
    for (i = 0; i < M; i++) {
        R[i] = malloc(M * sizeof(double));
    }

    for (i = 0; i < M; i++) {
        for (j = 0; j < M; j++) {
            printf("R[%d][%d] = ", i, j);
            fgets(buf, sizeof buf, stdin);
            sscanf(buf, "%lf", &R[i][j]);
        }
    }

    printf("N = ");
    fgets(buf, sizeof buf, stdin);
    sscanf(buf, "%d", &N);

    double **S = malloc(M * sizeof(double *));
    for (i = 0; i < M; i++) {
        S[i] = malloc(M * sizeof(double));
    }
    double **C = malloc(M * sizeof(double *));
    for (i = 0; i < M; i++) {
        C[i] = malloc(M * sizeof(double));
    }

    matcpy(M, S, R);
    for (i = 1; i < N; i++) {
        multiply(M, C, R, S);
        matcpy(M, S, C);
    }

    for (i = 0; i < M; i++) {
        for (j = 0; j < M; j++) {
            printf ("%lf ", S[i][j]);
        }
        printf("\n");
    }

    return EXIT_SUCCESS;
}
  • 崩溃的主要原因是代码arrcpy(M,C,R),其中矩阵C尚未分配。
  • 代码double **R = malloc(M * sizeof(double))应该是double **R = malloc(M * sizeof(double *)),尽管前者恰好可以工作。
  • 每次在乘法函数中分配矩阵C不是一个好主意,尤其是在执行连续乘法时。
  • 建议使用fgets()sscanf()而不是scanf(),以便对不规则输入具有鲁棒性。
0qx6xfy6

0qx6xfy64#

#include <stdio.h>
#include <stdlib.h>
#include<math.h>
int main()
{int n,P,k;
    printf (" type the number of lines and colons :  ");
scanf ("%d",&n);
    int MUL1[n][n], MUL2[n][n], MUL[n][n];
     int i,j;
     printf ("type the elements of the first matirx : \n");
     for (i=1;i<=n;i++)
    {
        for (j=1;j<=n;j++)
            {printf (" [%d,%d]: ",i,j);
             scanf ("%d",&MUL1[i][j]);}}

     printf ("type the elements of the second matirx :  \n");
    for (i=1;i<=n;i++)
    {
        for (j=1;j<=n;j++)
            {printf (" [%d,%d]: ",i,j);
             scanf ("%d",&MUL2[i][j]);}}

    for (i=1;i<=n;i++)
    {
        for (j=1;j<=n;j++)
            {
                MUL[i][j]=0; 
                for ( k=1;k<=n ; k++)
                {
                       MUL[i][j] = MUL[i][j] + MUL1[i][k] * MUL2[k][j];
                }
            }
    }
    printf ("MAT1 * MAT2 = ");
for (i=1;i<=n;i++)
    {printf ("\n");
        for (j=1;j<=n;j++)
            {printf (" %d ",MUL[i][j]);}}
   return 0;
}

相关问题