我正在尝试将存储在这样格式化的文件中的两个矩阵相乘:
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("%c\n", 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]
未被读取,因此有足够的内存来存储所有数据。
答案 0 :(得分:1)
您的读取缓冲区只能容纳maxc
(即4
)个字符:
char buf[maxc]; /*to store each lines of file */
然后,您尝试将文件中的一行插入该缓冲区:
while (fgets (buf, maxc, fp)){
但是该缓冲区仅足够容纳2个字符,然后是换行符,然后是'\0'
终止符。
在示例文件中,最长的一行包含4个字符:"-4 1"
。因此,您的缓冲区至少需要容纳6个(包括换行符和'\0'
终止符)。
最好使缓冲区更大一些。
答案 1 :(得分:0)
问题完全在于读取数组。
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。
您在评论中发布的修订无效,因为您仅增加了缓冲区大小,但没有增加传递给size
的{{1}}参数。如果您做了fgets
,还应该char buf[2*maxc];
,它将“解决”当前问题。我宁愿重新编写整个内容,也不愿编写fgets (buf, 2 * maxc, fp)
以适应将来的更改。
请勿使用VLAs。 fgets(buf, sizeof(buf)/sizeof(buf[0]), fp)
。为简单起见,您可以为该行使用任意长缓冲区,例如。 char buf[maxc];
和#define LINE_MAX 1024
,然后char buf[LINE_MAX]
。或者使用或重写函数来动态调整内存大小并读取行,例如GNUs getline。