所以我的尝试是创建一个程序,该程序从.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())。
6422164 4199040
矩阵不适合乘法。(无关紧要)
所以基本上它不使用3x3。
我不知道是什么问题。
答案 0 :(得分:1)
这是我的主要评论开头。
我必须重构dim
来处理任意大的矩阵,因此我必须逐个字符地扫描文件的第一行,并计算空格字符串(得出的列数为1)。它处理/剥离前导/尾随空格[格式错误]
我有dim
然后倒带文件,并分别使用fscanf
和realloc
动态创建矩阵。
这是工作代码[请原谅免费的样式清理]:
#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:
我由您尝试了前面的2种方法,它运行非常顺利!再一次谢谢你!以及您关于使用更少的变量和东西简化我的程序的评论!
不客气!
我的编码风格/方法学来自[非常]旧书:Kernighan和Plauger撰写的“编程风格的元素”。
该书中的示例是用Fortran编写的,但其格言与Steve McConnell的“ Code Complete”相当。
第7章[效率和工具]: