C - 读取文件时的内存分配问题



我正在尝试将存储在这样格式化的文件中的两个矩阵相乘:

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 1024char buf[LINE_MAX]然后fgets(buf, sizeof(buf)/sizeof(buf[0]), file).或者使用或重写函数来动态调整内存和读取行的大小,如 GNU 的 getline。

相关内容

  • 没有找到相关文章

最新更新