2016-01-07 99 views
0

所以我想从这样的文件加载信息:读取字符串和INT

TREE 1 2 
BURN 5 6 
... 

在我的代码一切工作很好,但是当它涉及到的读取文件的一部分,它读取第一行,然后卡在那里。这是我在做什么:

int lines=0, columns=0, MAX=5; 
FILE *file=NULL; 
char *string; 

... 

string=(char *)malloc(sizeof(char)*MAX); 

while ((fscanf(file, "%s %d %d", string, &lines, &colums))!=EOF) { 
    matrix[lines][colums]=string; 
    string=NULL; 
} 

这是代码的工作不正常,一切工作正常的唯一部分。文件打开,矩阵正确分配。它只会在1行上被阻塞。 “...”只是分配40x40矩阵的一部分。

预先感谢您!

+2

不要将'fscanf()'与'EOF'进行比较,请阅读文档。这样做是假设它已经读取,在这种格式说明符中,空白也没有意义,“%s%d%d”就可以。 –

+1

不要使用'fscanf'读取格式化输入。用'fgets'读取文本行,然后从'fgets'缓冲区读取格式化的数据并返回'sscanf'。 –

回答

0

将文件中的信息加载到矩阵中并不困难,但是您的代码有许多方面令人困惑。首先,看起来您正在创建一个40 x 40矩阵,然后在您的40 x 40矩阵中读取一个4字符字符串及其预期的rowcolumn位置。创建部分填充矩阵没有任何问题,但您的方法采取了几个麻烦点。

正如指出的那样,检查fscanf(...) != EOF)是不正确的。 Xscaf函数系列返回的匹配计数等于根据您的格式字符串发生的成功转换次数。例如,具有的"%s %d %d"格式字符串,所述匹配计数(因此的fscanfreturn),用于成功的读取和线路转换成stringlinescolumns3return的正确使用将检查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); 

(你还需要确认是否linescolumns从文件中读取是基或一个基)

最后,没有必要动态申报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的目的是,linescolumns永远不能。选择合适的类型允许编译器提供额外的警告)

编译

始终编译警告启用。例如:

gcc -Wall -Wextra -o bin/matrix_strings matrix_strings.c 

(如果不使用gcc,你编译器将有类似的选项)

例/输出

使用您的示例输入文件将导致如下:

$ ./bin/matrix_strings ../dat/tb.txt 

    TREE 



     BURN 

让我知道,如果你还有其他问题。

0
while ((fscanf(file, "%s %d %d", string, &lines, &colums))!=EOF) { 
    matrix[lines][colums]=string; 
    string=NULL; 
} 

您应该将字符串指针未设置为NULL。这样它就变成了NULL pointer,并且在下一个循环中你试着将fscanf()转换为NULL指针,并且还会泄漏分配的内存。

linescolum(n)s读可能比你40x40 matrix更高。检查一下会更好。

另外:中fscanf()返回值可以比EOF别的东西:

如果读数错误发生时或 阅读,适当的指标设置到达档案结尾(FEOF或恐怖)。并且,如果在成功读取任何数据之前发生了 ,则返回EOF。

matrix[lines][colums]=string; 

在这里,您将可以存储matrix[][]pointer,不是字符串的内容。你需要在这里使用像strcpy()这样的东西。

你需要检查你的变量的名字太:

columns=0 
, &colums) 
matrix[lines][colums] 

colums VS科拉姆ñ秒。

+1

为什么不建议检查'fscanf(file,“%s%d%d”,string,&lines,&colums))!= 3)'表示转换失败?这是返回*匹配计数*的主要目的。 –

0

只能使用=才能复制字符串。使用strcpy()代替:

#include <stdio.h> 
#include <string.h> 

int main() 
{ 
    int lines = 0, columns = 0; 
    char string[5]; 
    char matrix[40][40][5]; 
    FILE *file = NULL; 
    if ((file = fopen("source.txt", "r")) == NULL) 
    { 
     perror("fopen"); 
     return 1; 
    } 
    while ((fscanf(file, "%s %d %d", string, &lines, &columns)) != EOF) 
    { 
     strcpy(matrix[lines][columns], string); 
     printf("matrix[%d][%d]:%s\n", lines, columns, matrix[lines][columns]); 
    } 
    return 0; 
}