将文件中的信息加载到矩阵中并不困难,但是您的代码有许多方面令人困惑。首先,看起来您正在创建一个40 x 40
矩阵,然后在您的40 x 40
矩阵中读取一个4字符字符串及其预期的row
和column
位置。创建部分填充矩阵没有任何问题,但您的方法采取了几个麻烦点。
正如指出的那样,检查fscanf(...) != EOF)
是不正确的。 Xscaf
函数系列返回的匹配计数等于根据您的格式字符串发生的成功转换次数。例如,具有的"%s %d %d"
格式字符串,所述匹配计数(因此的fscanf
的return
),用于成功的读取和线路转换成string
,lines
和columns
将3
。 return
的正确使用将检查3
有效转换。例如:
fscanf (file, "%s %zu %zu", string, &lines, &columns) == 3)
(正如其他人指出它可能是更好使用像fgets
一个面向行输入功能,以防止在文件中杂散字符以下columns
读取文件的线,或其他格式但是,如果您确保在整个输入文件中保持一致的格式,则在此情况下,您可以非最佳地使用fscanf
)
您还有两个额外的问题应该在检查期间检查您的阅读和作业为matix
。首先,您应该跟踪行索引,以确保您现在可以写入超出matrix
的末尾(例如尝试写入41行等)。例如与idx
跟踪指数的行数读/加入并与ROWS
为常数40
你可以做类似的东西:
while (idx < ROWS && /* read each line, validate conversion */
fscanf (file, "%s %zu %zu", string, &lines, &columns) == 3) {
...
idx++;
}
其次,你需要检查的lines
值对40
,和(包括结尾符号),以确保它不会超出matix
的末尾(例如,将字符放在row or column 39
之外)。假设您的字符串的最大长度为5
(4个字符+ 1 )和定义为的常数,你可以不喜欢你读循环的开头如下:
if (lines >= ROWS) { /* validate row position for string */
fprintf (stderr, "warning: invalid row index, line '%zu'\n",
idx);
continue;
}
if (columns + MAX + 1 >= COLS) { /* validate position for string */
fprintf (stderr, "warning: invalid columns + MAX, line '%zu'\n",
idx);
continue;
}
如果您想要打印matrix
为字符串,以确认你的代码,你还必须处理0
栏和开始之间的字符string
放置在列columns
。如果需要,可以用快速memset
来处理。例如:
memset (matrix[lines], ' ', columns);
(你还需要确认是否lines
和columns
从文件中读取是零基或一个基)
最后,没有必要动态申报string
。你知道string
不能超过40
,并且为了你的示例输入的目的,它不超过5
,所以一个简单的大小为5
的字符数组的静态声明就足够了。
把所有的拼在一起,并简单地增加一个maxrow
限制的例子的打印目的,你可以这样做:
#include <stdio.h>
#include <string.h>
#define ROWS 40
#define COLS 40
#define MAX 5
int main (int argc, char **argv) {
char matrix[ROWS][COLS] = {{0}};
char string[MAX] = {0};
FILE *file = argc > 1 ? fopen (argv[1], "r") : stdin;
size_t lines, columns, idx, maxrow, i;
lines = columns = idx = maxrow = i = 0;
if (!file) { /* validate file open for reading */
fprintf (stderr, "error: file open failed '%s'\n", argv[1]);
return 1;
}
while (idx < ROWS && /* read each line, validate conversion */
fscanf (file, "%s %zu %zu", string, &lines, &columns) == 3) {
if (lines >= ROWS) { /* validate row position for string */
fprintf (stderr, "warning: invalid row index, line '%zu'\n",
idx);
continue;
}
if (columns + MAX + 1 >= COLS) { /* validate position for string */
fprintf (stderr, "warning: invalid columns + MAX, line '%zu'\n",
idx);
continue;
}
memset (matrix[lines], ' ', columns); /* set leading spaces */
strcpy (&matrix[lines][columns], string); /* copy string to matrix */
maxrow = lines > maxrow ? lines : maxrow; /* track max row filled */
idx++;
}
if (file != stdin) fclose (file);
for (i = 0; i < maxrow + 1; i++) /* simple test print of matrix */
printf (" %s\n", matrix[i]);
return 0;
}
(注:如果你的编译器无法处理输入/转换size_t
(例如%zu
),您可以更改报关单int
。在选择size_t
的目的是,lines
和columns
永远不能负。选择合适的类型允许编译器提供额外的警告)
编译
始终编译警告启用。例如:
gcc -Wall -Wextra -o bin/matrix_strings matrix_strings.c
(如果不使用gcc
,你编译器将有类似的选项)
例/输出
使用您的示例输入文件将导致如下:
$ ./bin/matrix_strings ../dat/tb.txt
TREE
BURN
让我知道,如果你还有其他问题。
不要将'fscanf()'与'EOF'进行比较,请阅读文档。这样做是假设它已经读取,在这种格式说明符中,空白也没有意义,“%s%d%d”就可以。 –
不要使用'fscanf'读取格式化输入。用'fgets'读取文本行,然后从'fgets'缓冲区读取格式化的数据并返回'sscanf'。 –