1

所以我的尝试是创建一个程序,自动从 .txt 文件中获取两个矩阵的大小并将它们相乘。我可以制作具有给定大小的程序,所以我本身只有计算列和行的问题。

输入类似于(MxN 矩阵):

1 2 3 4

1 2 3 4

1 2 3 4

具体来说,这是我到目前为止的程序(我认为代码的开头是相关的):

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

struct mat1
{
    int cols;
    int rows;
};

struct mat2
{
    int cols;
    int rows;
};

struct mat1 dim1(const char* file)
{
    struct mat1 m1;
    int rows = 0;
    int cols = 0;
    char c;
    FILE *f = fopen(file, "r+");

    while((c = fgetc(f) != EOF))
    {
        if(c != '\n' && rows == 0)
           {
            cols++;
           }
           else if(c == '\n')
            rows++;
    }
    rows++;
    return m1;
}

struct mat2 dim2(const char* file)
{
    struct mat2 m2;
    int rows = 0;
    int cols = 0;
    char c;
    FILE *f = fopen(file, "r+");

    while((c = fgetc(f) != EOF))
    {
        if(c != '\n' && rows == 0)
           {
            cols++;
           }
           else if(c == '\n')
            rows++;
    }
    rows++;
    return m2;
}


double* alloc_matrix(int cols, int rows) {
    double* m = (double*)malloc(cols * rows * sizeof(double));
    if (m == 0) {
        printf("Memory allocation error.\n");
        exit(-1);
    }
    return m;
}

void read_matrix(FILE* f, double* m, int cols, int rows) {
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            fscanf(f, "%lf", &m[i * cols + j]);
        }
    }
}

void multiplication(double* m1, double* m2, double* m3, int cols, int rows) {
    for(int i = 0; i < rows; i++) {
        for(int j = 0; j < cols; j++) {
            m3[i * cols +j]=0;
            for(int k = 0; k < cols; k++) {
                m3[i * cols +j]+=m1[i * cols +k]*m2[k * cols +j];
            }
        }
    }
}

void write_matrix(double* m, int cols, int rows) {
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            printf("%f ", m[i * cols + j]);
        }
        printf("\n");
    }
}


int main(int argc, char* argv[])
{
    char* matrix1 = argv[1];
    char* matrix2 = argv[2];

        if (argc < 3) {
        printf("Not enough arguments.\n");
        exit(-1);
    }

    struct mat1 m1 = dim1(matrix1);
    struct mat2 m2 = dim2(matrix2);
    printf(" %d   %d \n", m1.cols, m1.rows);
    printf(" %d   %d \n", m2.cols, m2.rows);
    int c1 = m1.cols;
    int r1 = m1.rows;
    int c2 = m2.cols;
    int r2 = m2.rows;

    if (r1!=c2)
    {
        printf("Matrixes are not suitable for multiplication. \n");
        exit(-1);
    }

    double* mtx1 = alloc_matrix(c1, r1);
    double* mtx2 = alloc_matrix(c2, r2);

    FILE* f1 = fopen(matrix1, "r");
    if (f1 == 0)
    {
        printf("Cannot open file %s.", argv[1]);
        exit(-1);
    }

    FILE* f2 = fopen(matrix2, "r");
    if (f1 == 0)
    {
        printf("Cannot open file %s.", argv[1]);
        exit(-1);
    }

    read_matrix(f1, mtx1, c1, r1);
    read_matrix(f2, mtx2, c2, r2);

    double* mtx3 = alloc_matrix(c1, r2);

    multiplication(mtx1, mtx2, mtx3, c1, r2);

    write_matrix(mtx3, c1, r2);

    free(mtx1);
    free(mtx2);
    free(mtx3);
    fclose(f1);
    fclose(f2);

    return 0;
}

当我用 2 个 3x3 矩阵尝试它时,前哨:

6422164 4199040(来自我设置用于检查尺寸的 2 个 printf()s)。

6422164 4199040

矩阵不适合乘法。(这无关紧要)

所以基本上它不使用3x3。

我无法弄清楚问题是什么。

4

1 回答 1

1

这是我的热门评论的开头。

我必须重构dim以处理任意大的矩阵,所以我必须逐个字符地扫描文件的第一行,计算空白字符串(产生列数 - 1)。它处理/去除前导/尾随空格[格式错误]

然后我dim倒带文件并使用fscanfrealloc动态创建矩阵。


这是工作代码[请原谅无偿的风格清理]:

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

struct mat {
    int cols;
    int rows;
    double *m;
};

// size and read in matrix
struct mat
dim(const char *file)
{
    struct mat m;
    int rows = 0;
    int cols = 0;
    int maxcnt;
    int curcnt;
    int ret;
    int c;
    int c2;

    FILE *f = fopen(file, "r+");

    // strip leading whitespace [if any] off first line
    while (1) {
        c = fgetc(f);
        if (c == EOF)
            break;
        if (c == '\n')
            break;
        if (c != ' ')
            break;
    }

    // scan first line and count columns (number of space separaters)
    while (1) {
        c2 = ' ';
        while (1) {
            c = fgetc(f);
            if (c == EOF)
                break;

            if (c == '\n') {
                if (c2 != ' ')
                    ++cols;
                break;
            }

            if (c == ' ') {
                if (c != c2)
                    ++cols;
                break;
            }

            c2 = c;
        }

        if (c == '\n')
            break;
    }

    // convert number of whitespace separaters into number of columns
    if (cols > 0)
        ++cols;

    rewind(f);

    m.rows = 0;
    m.cols = cols;
    m.m = NULL;
    curcnt = 0;
    maxcnt = 0;

    while (1) {
        if (curcnt >= maxcnt) {
            maxcnt += m.cols * 100;
            double *tmp = realloc(m.m,sizeof(double) * maxcnt);
            if (tmp == NULL) {
                printf("dim: realloc failure\n");
                exit(1);
            }
            m.m = tmp;
        }

        ret = 0;
        for (int idx = 0;  idx < cols;  ++idx, ++curcnt) {
            ret = fscanf(f, "%lf", &m.m[curcnt]);
            if (ret != 1)
                break;
        }

        if (ret != 1)
            break;

        rows += 1;
    }

    fclose(f);

    m.rows = rows;

    // trim matrix to actual size;
    m.m = realloc(m.m,sizeof(double) * rows * cols);

    return m;
}

double *
alloc_matrix(int cols, int rows)
{
    double *m = (double *) malloc(cols * rows * sizeof(double));

    if (m == 0) {
        printf("Memory allocation error.\n");
        exit(-1);
    }
    return m;
}

void
multiplication(double *m1, double *m2, double *m3, int cols, int rows)
{
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            m3[i * cols + j] = 0;
            for (int k = 0; k < cols; k++) {
                m3[i * cols + j] += m1[i * cols + k] * m2[k * cols + j];
            }
        }
    }
}

void
write_matrix(double *m, int cols, int rows)
{
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            printf("%f ", m[i * cols + j]);
        }
        printf("\n");
    }
}

int
main(int argc, char *argv[])
{

    if (argc < 3) {
        printf("Not enough arguments.\n");
        exit(1);
    }

    struct mat m1 = dim(argv[1]);
    struct mat m2 = dim(argv[2]);

    printf(" %d   %d \n", m1.cols, m1.rows);
    printf(" %d   %d \n", m2.cols, m2.rows);

    int c1 = m1.cols;
    int r1 = m1.rows;
    int c2 = m2.cols;
    int r2 = m2.rows;

    if (r1 != c2) {
        printf("Matrixes are not suitable for multiplication.\n");
        exit(-1);
    }

    double *mtx3 = alloc_matrix(c1, r2);

    multiplication(m1.m, m2.m, mtx3, c1, r2);

    write_matrix(mtx3, c1, r2);

    free(m1.m);
    free(m2.m);
    free(mtx3);

    return 0;
}

这是我使用的两个测试文件。请注意,虽然您看不到它,但第一行有尾随空格 [作为测试]:

这是m1.txt

 1 2  3  4
5 6 7  8
9 10  11  12

这是第二个文件:

 1  2  3
 4 5 6
 7 8 9
 10 11 12

这是程序输出:

 4   3
 3   4
38.000000 44.000000 202.000000 232.000000
98.000000 116.000000 438.000000 504.000000
158.000000 188.000000 674.000000 776.000000
9.000000 10.000000 87.000000 100.000000

更新:

这是一个dim替代函数,它将第一行的[有点脆弱]逐字符扫描替换为换行符[以获取行长],然后malloc是缓冲区,fgets然后循环strtok以计算非空格行中的字符串(即列数):

// size and read in matrix
struct mat
dim(const char *file)
{
    struct mat m;
    int rows = 0;
    int cols = 0;
    int maxcnt;
    int curcnt;
    int ret;
    char *buf;
    char *bp;
    char *tok;
    int c;
    int c2;

    FILE *f = fopen(file, "r+");

    // count number of chars in first line of the file
    curcnt = 0;
    while (1) {
        c = fgetc(f);
        if (c == EOF)
            break;
        ++curcnt;
        if (c == '\n')
            break;
    }

    ++curcnt;
    buf = malloc(curcnt);
    rewind(f);
    fgets(buf,curcnt,f);

    cols = 0;
    bp = buf;
    while (1) {
        tok = strtok(bp," \n");
        if (tok == NULL)
            break;
        ++cols;
        bp = NULL;
    }
    free(buf);

    rewind(f);

    m.rows = 0;
    m.cols = cols;
    m.m = NULL;
    curcnt = 0;
    maxcnt = 0;

    while (1) {
        if (curcnt >= maxcnt) {
            maxcnt += m.cols * 100;
            double *tmp = realloc(m.m,sizeof(double) * maxcnt);
            if (tmp == NULL) {
                printf("dim: realloc failure\n");
                exit(1);
            }
            m.m = tmp;
        }

        ret = 0;
        for (int idx = 0;  idx < cols;  ++idx, ++curcnt) {
            ret = fscanf(f, "%lf", &m.m[curcnt]);
            if (ret != 1)
                break;
        }

        if (ret != 1)
            break;

        rows += 1;
    }

    fclose(f);

    m.rows = rows;

    // trim matrix to actual size;
    m.m = realloc(m.m,sizeof(double) * rows * cols);

    return m;
}

更新#2:

我不喜欢任何一种获取列数的解决方案,所以这里有一个更干净的解决方案,它与第一个解决方案一样快,但更简单且不那么麻烦:

// scan first line and count columns
int
colcalc(FILE *f)
{
    int c;
    int noncur;
    int nonprev = 0;
    int cols = 0;

    while (1) {
        c = fgetc(f);
        if (c == EOF)
            break;

        if (c == '\n')
            break;

        // only count non-whitespace chars
        switch (c) {
        case ' ':
        case '\t':
            noncur = 0;
            break;
        default:
            noncur = 1;
            break;
        }

        // column starts on _first_ char in word
        if (noncur)
            cols += (noncur != nonprev);

        nonprev = noncur;
    }

    rewind(f);

    return cols;
}

更新#3:

我尝试了你之前的两种方法,效果非常好!再一次感谢你!以及您关于用更少的变量和东西使我的程序更简单的评论!

别客气!

我的编码风格/方法来自一本 [非常] 古老的书:Kernighan 和 Plauger 的《编程风格的要素》。

该书中的示例是用 Fortran 编写的,但其中的格言与 Steve McConnell 的“代码完成”相当。

来自第 7 章 [效率和仪表]:

  • 在加快速度之前先做好。
  • 当你让它更快时,保持正确。
  • 在你让它更快之前先说清楚。
  • 不要为了“效率”的微小收益而牺牲清晰度。
  • 不要紧张地重用代码;改为重组。
  • 确保特殊情况确实很特殊。
  • 保持简单以使其更快。
  • 不要为了让它更快而欺骗代码——找到更好的算法。
  • 检测您的程序。在进行“效率”更改之前进行测量。
于 2018-12-01T23:44:30.080 回答