我正在尝试将存储在这样格式化的文件中的两个矩阵相乘:
1 2 2 3 * -4 1 1 0
我最初不知道每个矩阵的维度是多少。但是我让用户定义它,否则将采用默认值100
。
int maxc = argc > 2 ? atoi(argv[2]) * atoi(argv[2]) : 100;
我已经可以正确执行计算,但是我注意到,如果我输入维度argv[2] = "2"
以便maxc = 8
,(对于此示例来说应该足够了),则在读取或打印文件时会产生错误。但是如果我输入argv[2] = "3"
这个例子一切正常。由于maxc
用于在此处分配内存:matrix = malloc(maxc * sizeof *matrix)
,我怀疑问题可能位于该行上。我是否也应该为size_t row; size_t col;
分配内存?
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <math.h>
#include <string.h>
#define MAXNOP 50 /*Max number of operations allowed */
#define MAXNMATR 20 /*Max number of matrices */
struct m {
size_t row;
size_t col;
double *data;
};
struct m multiply(struct m *A, struct m *B);
void f(double x);
void print_matrix(struct m *A);
void read_file(int maxc, FILE *fp);
void scalar_product(double scalar, struct m *B);
void calculate(struct m *matrix, int nop, int id, char *op);
int main(int argc, char *argv[]) {
FILE *file = argc > 1 ? fopen(argv[1], "rb") : stdin;
/* define max dimension of a matrix */
int maxc = argc > 2 ? atoi(argv[2]) * atoi(argv[2]) : 100;
read_file(maxc, file);
return 0;
}
void read_file(int maxc, FILE *fp) {
struct m *matrix;
int id = 0; /* id of a matrix */
size_t ncol, nrow; /* No of columns of a matrix*/
ncol = nrow = 0;
int nop = 0; /*No of operators*/
int off = 0;
int i;
int n;
double *d;
char buf[2 * maxc]; /*to store each lines of file */
char *p = buf;
char op[MAXNOP];
for (i = 0; i < MAXNOP; i++)
op[i] = '?';
if (!(matrix = malloc(maxc * sizeof *matrix))) {
perror("malloc-matrix");
exit(1);
}
/* Read file line by line */
while (fgets(buf, maxc, fp)) {
if (nrow == 0) {
/* allocate/validate max no. of matrix */
d = matrix[id].data = malloc(sizeof(double) * MAXNMATR);
}
/* check if line contains operator */
if ((!isdigit(*buf) && buf[1] =='n')) {
op[nop++] = *buf;
matrix[id].col = ncol;
matrix[id].row = nrow;
nrow = ncol = 0;
id++;
continue;
} else {
/* read integers in a line into d */
while (sscanf(p + off, "%lf%n", d, &n) == 1) {
d++;
if (nrow == 0)
ncol++;
off += n;
}
nrow++;
off = 0;
}
} /*end of while fgets cycle */
/* Assign last matrix No of columns and rows */
matrix[id].col = ncol;
matrix[id].row = nrow;
/* Printing the matrices and operations */
for (i = 0; i <= id; i++) {
if (op[i] == '*' || op[i] == '-' || op[i] =='+') {
print_matrix(&matrix[i]);
if (op[i-1] != 'i')
printf("%cn", op[i]);
else
continue;
} else
if (op[i] == '?') {
print_matrix(&matrix[i]);
}
}
calculate(matrix, nop, id, op);
}
void calculate(struct m *matrix, int nop, int id, char *op) {
int i;
for (i = 0; i <= nop; i += 2) {
if (op[i] == '*' && op[i+1] == '?') {
if (matrix[i].row == 1 && matrix[i].col == 1)
scalar_product(matrix[i].data[0], &matrix[i + 1]); //Multiplication of Scalar per matrix
else {
matrix[i + 1] = multiply(&matrix[i], &matrix[i + 1]);
matrix[i + 2] = multiply(&matrix[i + 1], &matrix[i + 2]);
}
break;
}
}
printf("=n");
print_matrix(&matrix[id]); /* Print the result */
free(matrix);
}
struct m multiply(struct m *A, struct m *B) {
size_t i, j, k;
struct m C;
C.data = malloc(sizeof(double) * A->row * B->col);
C.row = A->row;
C.col = B->col;
for (i = 0; i < C.row; i++)
for (j= 0 ; j < C.col; j++)
C.data[i * C.col + j] = 0;
// Multiplying matrix A and B and storing in C.
for (i = 0; i < A->row; ++i)
for (j = 0; j < B->col; ++j)
for (k = 0; k < A->col; ++k)
C.data[i * C.col + j] += A->data[i * A->col + k] * B->data[k * B->col + j];
return C;
}
void f(double x) {
double i, f = modf(x, &i);
if (f < .00001)
printf("%.f ", i);
else
printf("%f ", x);
}
/* printing a Matrix */
void print_matrix(struct m *A) {
size_t i, j;
double *tmp = A->data;
for (i = 0; i < A->row; i++) {
for (j = 0; j < A->col; j++) {
f(*(tmp++));
}
putchar('n');
}
}
void scalar_product(double scalar, struct m *B) {
size_t i, j;
for (i = 0; i < B->row; i++)
for (j = 0; j < B->col; j++)
B->data[i * B->col + j] = scalar * B->data[i * B->col + j];
}
预期结果如下:https://ideone.com/Z7UtiR
这里不读取argv[2]
,因此有足够的内存来存储所有数据。
您的读取缓冲区只有空间容纳maxc
(即。4
) 字符 :
char buf[maxc]; /*to store each lines of file */
然后,您尝试将文件中的一行获取到该缓冲区中:
while (fgets (buf, maxc, fp)){
但是该缓冲区仅足够容纳 2 个字符,后跟换行符,然后是' '
终止符。
查看您的示例文件,最长的行有 4 个字符:"-4 1"
。因此,您的缓冲区至少需要能够容纳 6(包括换行符和' '
终止符)。
最好使缓冲区更大一些。
问题完全在于读取数组。
maxc = 4
和缓冲区char buf[maxc];
仅包含 3 个字符和终止字符。
所以fgets (buf, maxc, fp)
:
- 在第一个将读取
buf = "1 2"
(3个字符和零字节) - 在第二个将读取
buf = "n"
(1 个换行符,fgets 终止) - 然后读
buf = "2 3"
- 然后读取
buf = "n"
buf = "*n"
buf = "-4 "
- 等等
由于空行,在此代码中截取:
else /* read integers in a line into d */
{
while (sscanf (p + off, "%lf%n", d, &n) == 1) {
d++;
if(nrow == 0)
ncol++;
off += n;
}
nrow++;
off = 0;
}
变量nrow
将递增 4 倍(行增加 2 倍,仅读取换行符的空行递增 2 倍),这将是 2 倍。第二个矩阵将有 1 列,因为您将只读取该行的-4
,因此您的while(sscanf
循环将仅扫描一个数字,因此ncol
将仅为 1。
您在评论中发布的修复无效,因为您只增加了缓冲区大小,但没有增加传递给fgets
的参数size
。如果你做了char buf[2*maxc];
你也应该fgets (buf, 2 * maxc, fp)
,这将"解决"当前的问题。我宁愿重写整个事情,或者更确切地说fgets(buf, sizeof(buf)/sizeof(buf[0]), fp)
写以适应未来的变化。
不要使用 VLA,例如。char buf[maxc];
.为简单起见,您可以对行使用任意长缓冲区,例如。#define LINE_MAX 1024
和char buf[LINE_MAX]
然后fgets(buf, sizeof(buf)/sizeof(buf[0]), file)
.或者使用或重写函数来动态调整内存和读取行的大小,如 GNU 的 getline。