我正试图将文件的内容读取到矩阵中。由于我将有几个具有未知行数和列数的文件,因此我动态地为矩阵分配内存。
我的代码到现在为止。
#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文件,其中许多int
和float
数据被#
分隔。使用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*
和平面区域的情况下,使用stat
或ftell
来获取文件大小,而不是读取文件两次,可能更简单地分配一个与文件一样大的区域。
按行块分配内存
使用这种方式更快,并且使用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;
}