C语言 读取文件时输出错误



我正试图将文件的内容读取到矩阵中。由于我将有几个具有未知行数和列数的文件,因此我动态地为矩阵分配内存。

我的代码到现在为止。

#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
char** map, chr;
int column = 0, row = 0, columns = 0, rows = 0, total_elements = 0;
FILE* file = fopen("file.txt", "r+");
// count numbers of rows and columns
while (chr != EOF)
{   
if (chr == 'n')
{
rows = rows + 1;
}
chr = getc(file);
total_elements+=1;
}
rows += 1;

//Dividing the total number of elements by the number of rows to find the number of columns
columns = (total_elements/rows) - 1;
// alocate space for matrix
map = (char **) malloc(rows * sizeof(char *));
// allocating space for each column of each row
for (row = 0; row < rows; row++) {
map[row] = (char *) malloc(columns * sizeof(char));
}
// file reading
for (row = 0; row < rows; row++) {
for (column = 0; column < columns; column++) {
if (!fscanf(file, "%c", &map[row][column]))
break;
printf("%c", map[row][column]);
}
printf("n");
}
fclose(file);
free(map);

return 0;

这是文件:

....*.....................
..........................
........*........*........
.....*....................
...............*....*.....
..*.......*...............
............*.............
..........................
..............*...........
..................*.......
..*.......*......*........
....*..*..................
...**.....................
..........*...............
....................*.....
..........................
....**....................
......................*...

-预期的输出将是文件的内容,但我得到的输出格式错误。

?Å É/Å @Q▓v            @Q
­?Å É/Å             xA¢v
­?Å É/Å  ÊÐ C Å └ Å µ
­?Å É/Å     
­?Å É/Å
­?Å É/Å         T(Å     P(
­?Å É/Å @Q▓v            @Q
­?Å É/Å             xA¢vx(
­?Å É/Å ╩  ╩ÈÐ  └ Å É&Å ug
­?Å É/Å ┼  ┼═Ð  └ Å É&Å ├
­?Å É/Å     
­?Å É/Å  H
­?Å É/Å 
­?Å É/Å 
­?Å É/Å 
░Å É/Å
ä
H

我真不知道我在哪里犯了错误,使这一切发生了。

对于正在读取的文件类型和分配内存的方式,不需要读取整个文件两次:

.....*....................
...............*....*.....
..*.......*...............
............*.............

数据是面向行的,而且——我想——所有的行都有相同的列数。数据将存储在

char **map;

是指针数组,因此每个map[i]都是char*,并且可以保存一行数据。

fscanf()是为消费表格数据而编写的,可以使用分隔符和不同的字段类型,例如csv文件,其中许多intfloat数据被#分隔。使用fscanf()读取字符没有多大意义,您可以使用fgetc()fread()来代替。

关于你的代码

  • 如前所述,您需要rewind文件以再次读取数据
  • 也,正如所说,你需要测试'n',因为它不是数据
  • 总是测试fscanf()返回说明符的数量

考虑到我上面所说的,下面的循环将消耗你的文件

rewind(file);
row = 0;
column = 0;
while (1 == fscanf(file, "%c", &map[row][column]))
{
if (map[row][column] == 'n')
{   row += 1, column = 0;
printf("n");
}
else
{   printf("%c", map[row][column]);
column += 1;
}
};  // while();
fclose(file);

一般来说,在平面内存区域中使用地图数据更容易管理,只使用char*,以C的方式,逐行存储地图,而不是使用char**

更灵活的方式

使用char**方式,您可以按行读取数据,并将映射保持为字符串,因为它可能对显示和使用有用,同时仍然使用

map[][]

供参考。

我给你看一个例子

另外,既然你说你有很多文件大小,你应该考虑将文件名作为参数传递

为了有更多的控制,你可以使用一些封装,把数据放在struct中,如

typedef struct
{
int    cols;
int    rows;
int    size;
char** map;
} Grid;

这样你就可以有一个像

这样的函数
int   show_grid(Grid*,const char*);

和写

char title[100];
sprintf(title, "n    Map for %sn",file_name);
show_grid(&gr, title);

在屏幕上看到


Map for file.txt
[18 rows, 26 columns]
....*.....................
..........................
........*........*........
.....*....................
...............*....*.....
..*.......*...............
............*.............
..........................
..............*...........
..................*.......
..*.......*......*........
....*..*..................
...**.....................
..........*...............
....................*.....
..........................
....**....................
......................*...

代码可以简单为4行:

void show_grid(Grid* g, const char* msg)
{
if (msg != NULL) printf("%sn", msg);
printf("[%d rows, %d columns]n",
g->rows, g->cols);
for (int i = 0; i < g->rows; i+=1)
printf("%sn", g->map[i]);
printf("n");
}

决定列大小

int ch = 0;
for (gr.cols = 0; ch != 'n'; gr.cols += 1)
{
ch = fgetc(F);
if (feof(F)) return -2;
}

您只需要找到第一行的末尾,因为所有行都有相同的大小,并且内存是按行分配的。

在使用char*和平面区域的情况下,使用statftell来获取文件大小,而不是读取文件两次,可能更简单地分配一个与文件一样大的区域。

按行块分配内存

使用这种方式更快,并且使用fgets()读取数据以每次调用消耗一整行。此外,由于数据不是平面的,因此可以将行保留为字符串以简化显示。看到:

// blocksize in lines
int row = 0;
while (!feof(F))
{
gr.map[row] = (char*)malloc(gr.cols);  // new row
fgets(gr.map[row], gr.cols, F);
gr.map[row][gr.cols - 2] = 0;
row += 1;
if (row == gr.size)
{  // expand block
int    new_size = gr.size + BLKSIZE;
char** temp = (char**)realloc(gr.map, sizeof(char*)*new_size);
if (temp == NULL) break;
gr.map  = temp;
gr.size = new_size;
};
};
fclose(F);

你可以有一个合适的BLKSIZE不调整多次。

在命令行上传递文件名

这样,您可以有一个默认值,但也可以在命令行中传递文件名,以便在脚本中使用它。由于显示函数方便地显示文件名,您可以轻松地检查任意数量的文件,如

// open file as 'F'
const char* default_file_name = "file.txt";
char        file_name[80];
FILE*       F            = NULL;
if (argc > 1) 
strcpy(file_name, argv[1]);
else
strcpy(file_name, default_file_name);
F = fopen(file_name, "r");
if (F == NULL)
{
perror("Could not open file");
return -1;
}

例子
SO> .f0-0922
Map for file.txt
[18 rows, 26 columns]
....*.....................
..........................
........*........*........
.....*....................
...............*....*.....
..*.......*...............
............*.............
..........................
..............*...........
..................*.......
..*.......*......*........
....*..*..................
...**.....................
..........*...............
....................*.....
..........................
....**....................
......................*...
SO> .f0-0922 other.txt
Map for other.txt
[5 rows, 5 columns]
....*
...*.
..*..
.*...
*....
示例的代码
#define BLKSIZE 20
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct
{
int    cols;
int    rows;
int    size;
char** map;
} Grid;
void  show_grid(Grid*,const char*);
void  free_grid(Grid*);
int main(int argc, char** argv)
{
// open file as 'F'
const char* default_file_name = "file.txt";
char        file_name[80];
FILE*       F            = NULL;
if (argc > 1) 
strcpy(file_name, argv[1]);
else
strcpy(file_name, default_file_name);
F = fopen(file_name, "r");
if (F == NULL)
{
perror("Could not open file");
return -1;
}
// define grid
Grid gr = {0, 0, 0, NULL};
// set 'cols' to column size
int ch = 0;
for (gr.cols = 0; ch != 'n'; gr.cols += 1)
{
ch = fgetc(F);
if (feof(F)) return -2;
}
gr.cols = gr.cols + 1;  // add space to a terminating 0
rewind(F);              // roll back 1st line
gr.map = (char**)malloc((BLKSIZE * gr.cols) * sizeof(char*));  // initial size
gr.size = BLKSIZE;
// blocksize in lines
int row = 0;
while (!feof(F))
{
gr.map[row] = (char*)malloc(gr.cols);  // new row
fgets(gr.map[row], gr.cols, F);
gr.map[row][gr.cols - 2] = 0;
row += 1;
if (row == gr.size)
{  // expand block
int    new_size = gr.size + BLKSIZE;
char** temp = (char**)realloc(gr.map, sizeof(char*)*new_size);
if (temp == NULL) break;
gr.map  = temp;
gr.size = new_size;
};
};
fclose(F);
gr.rows = row;
gr.cols -= 2;
char title[100];
sprintf(title, "n    Map for %sn",file_name);
show_grid(&gr, title);
free_grid(&gr);
return 0;
}
void show_grid(Grid* g, const char* msg)
{
if (msg != NULL) printf("%sn", msg);
printf("[%d rows, %d columns]n", g->rows, g->cols);
for (int i = 0; i < g->rows; i += 1) printf("%sn", g->map[i]);
printf("n");
}
void free_grid(Grid* g)
{
for (int i = 0; i < g->rows; i += 1) free(g->map[i]);
free(g->map);
g->map = NULL;
return;
}
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
char **map, chr;
int column = 0, row = 0, columns = 0, rows = 0, total_elements = 0;
FILE *file = fopen("file.txt", "r+");
// count numbers of rows and columns
while (1) {
chr = (char) getc(file);
if (chr == EOF)
break;
if (chr == 'n') {
rows = rows + 1;
} else {
//n is not part of matrix
total_elements += 1;
}
}
rows += 1;
printf("%d,%dn", total_elements, rows); //no need -1 since did not counted n
//Dividing the total number of elements by the number of rows to find the number of columns
columns = (total_elements / rows);
// alocate space for matrix
map = (char **) malloc(rows * sizeof(char *));
// allocating space for each column of each row
for (row = 0; row < rows; row++) {
map[row] = (char *) malloc(columns * sizeof(char));
}
//fix offset
rewind(file);
// file reading
for (row = 0; row < rows; row++) {
for (column = 0; column < columns; column++) {
chr = (char) getc(file);
map[row][column] = chr;
}
chr = (char) getc(file); //read n but not write to array
}
row = 0;
for (row = 0; row < rows; row++) {
for (column = 0; column < columns; column++) {
printf("%c", map[row][column]);
}
printf("n");
}
fclose(file);
free(map);

return 0;
}

最新更新