简体   繁体   English

将文本文件读入 C 中的矩阵

[英]Reading text file into a matrix in C

I have a text file that has 200 x 150 data in it (every number is separated with a space).我有一个包含 200 x 150 数据的文本文件(每个数字都用空格分隔)。 I am trying to store these numbers into a matrix.我正在尝试将这些数字存储到矩阵中。 My code is this:我的代码是这样的:

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

int i,j, matrix[200][150];

void getMatrix(){
    FILE *file;
    file = fopen("PICTURE.txt", "r");
    char *line, *number;
    j = 0;
    while(!feof(file)){
        i = 0;
        fscanf(file, "%s", line);
        number = strtok(NULL, " ");
        while(number!= NULL){
            matrix[i][j] = atoi(number);
        }
        printf("\n");
        j++;
    }

}

void printMatrix(){
    int a, b;
    for(a=0; a<i; a++){
        for(b=0; b<j; b++){
            printf("%d", matrix[a][b]);
        }
        printf("\n");
    }
}

int main(){
    getMatrix();
    printMatrix();
}

It prints out literally nothing.它实际上什么也没有打印出来。 I don't understand why.我不明白为什么。 How can I fix my code or do you have any other suggestions for rewriting it?我该如何修复我的代码,或者您有任何其他重写它的建议?

Many problems:很多问题:

  • Never use while(!feof(file)){ .永远不要使用while(!feof(file)){ Instead check the return value of fscanf(file, ...)而是检查fscanf(file, ...)的返回值

  • Do not use "%s" with out a width limit.不要使用没有宽度限制"%s"

  • Do not use pass line to a function without initializing/assigning it first.不要在没有先初始化/分配它的情况下使用传递line到 function。

  • i never incremented. i从来没有增加过。

  • fclose(file) when done. fclose(file)完成后。

  • Check success of fopen(...);检查fopen(...);


GTG, maybe more later. GTG,也许以后会更多。

if you have a file, with 200x150 integer values (either on 200 lines, or all values on one line), then simply looping though the file with fscanf() reading and storing an integer at a time is all that is needed.如果您有一个文件,其中包含 200x150 integer 值(在 200 行上,或在一行上的所有值),那么只需使用fscanf()循环读取并存储 integer 一次即可。 You must validate each read and provide a way to communicate any failure within a function through the function return (or though a pointer updated within the function)您必须验证每次读取并提供一种方法来通过 function 返回(或通过函数内更新的指针)传达 function 内的任何故障

To begin, do not use MagicNumbers in your code and do not hardcode filenames.首先,不要在代码中使用MagicNumbers ,也不要硬编码文件名。 Instead, #define the constants you need (or use a global enum ) and pass the open FILE* pointer to your read-function as a parameter after having opened (and validated that the file is open for reading) in the calling function.相反,# #define您需要的常量(或使用全局enum )并在调用 function 中打开(并验证文件已打开以供读取)后将打开的FILE*指针作为参数传递给您的读取函数。 (If the file open fails -- there is no reason to make the read-function call to begin with) (如果文件打开失败——没有理由开始调用读取函数)

In your case, you only have two needed constants:在您的情况下,您只有两个需要的常量:

#define ROWS 200    /* if you need a constant, #define on (or more) */
#define COLS 150

Do not use global variables unless absolutely necessary (there will be virtually no case where globals are needed when you begin learning C).除非绝对必要,否则不要使用全局变量(当您开始学习 C 时,几乎没有需要全局变量的情况)。 Passing the matrix (2D array) as a parameter to your read-function, it can be written as:将矩阵(二维数组)作为参数传递给您的读取函数,它可以写成:

/* fill m[ROWS][COLS] with values read from fp.
 * returns 1 on success, 0 otherwise.
 */
int getmatrix (int (*m)[COLS], FILE *fp)
{
  for (int row = 0; row < ROWS; row++) {
    for (int col = 0; col < COLS; col++) {
      if (fscanf (fp, "%d", &m[row][col]) != 1) {
        fprintf (stderr, "error reading m[%d][%d]\n", row, col);
        return 0;
      }
    }
  }
  
  return 1;
}

( note: how the return type for the function is int where 1 (true) is returned on success and 0 (false) is returned on failure. Also note that if 200x150 values are unable to be read, failure is returned) 注意: function 的返回类型如何为int ,其中成功返回1 (true),失败返回0 (false)。另请注意,如果无法读取 200x150 值,则返回失败)

Pass the filename to read from as the 1st argument to your program (that's what int argc, char **argv parameters to main() are for).将要读取的文件名作为第一个参数传递给程序(这就是 main main()int argc, char **argv参数的用途)。 Alternatively, you can prompt the user and read the filename as input.或者,您可以提示用户并读取文件名作为输入。 You can provide a fixed filename as a default value if no filename is entered ( stdin is used as the default below), but otherwise do not hardcode filenames.如果没有输入文件名,您可以提供一个固定的文件名作为默认值( stdin用作下面的默认值),否则不要硬编码文件名。 You should not have to recompile your program simply to read from a different filename.您不必为了读取不同的文件名而重新编译程序。

With those improvements made, your main() could be:通过这些改进,您的main()可能是:

int main (int argc, char **argv) {
  
  int matrix[ROWS][COLS] = {{0}};   /* do not use global variables */
  /* use filename provided as 1st argument (stdin by default) */
  FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;

  if (!fp) {  /* validate file open for reading in caller */
    perror ("file open failed");
    return 1;
  }
  
  if (!getmatrix (matrix, fp)) {    /* pass array and open FILE*, validate */
    return 1;
  }
  fclose (fp);
  
  prnmatrix (matrix);       /* output results */
}

The complete program is:完整的程序是:

#include <stdio.h>

#define ROWS 200    /* if you need a constant, #define on (or more) */
#define COLS 150

/* fill m[ROWS][COLS] with values read from fp.
 * returns 1 on success, 0 otherwise.
 */
int getmatrix (int (*m)[COLS], FILE *fp)
{
  for (int row = 0; row < ROWS; row++) {
    for (int col = 0; col < COLS; col++) {
      if (fscanf (fp, "%d", &m[row][col]) != 1) {
        fprintf (stderr, "error reading m[%d][%d]\n", row, col);
        return 0;
      }
    }
  }
  
  return 1;
}

void prnmatrix (int (*m)[COLS])
{
  for (int row = 0; row < ROWS; row++) {
    for (int col = 0; col < COLS; col++) {
      printf (col ? " %4d" : "%4d", m[row][col]);
    }
    putchar ('\n');
  }
}

int main (int argc, char **argv) {
  
  int matrix[ROWS][COLS] = {{0}};   /* do not use global variables */
  /* use filename provided as 1st argument (stdin by default) */
  FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;

  if (!fp) {  /* validate file open for reading in caller */
    perror ("file open failed");
    return 1;
  }
  
  if (!getmatrix (matrix, fp)) {    /* pass array and open FILE*, validate */
    return 1;
  }
  fclose (fp);
  
  prnmatrix (matrix);       /* output results */
}

Example Use/Output示例使用/输出

With 200 x 150 random values less than 10000 generated and written to dat/int-200x150.txt , you would run the program as:生成小于 10000 的 200 x 150 个随机值并将其写入dat/int-200x150.txt ,您可以将程序运行为:

$ ./bin/read2darrint dat/int-200x150.txt
9240 5939 3063 5789 7401 7869 4363 3321 7788 1008 7850 ...
2760 5263 5338 6390 8146  155  324  916 4489 3718 1616 ...
...

Where the output is 200 lines of 150 numbers each.其中 output 是 200 行,每行 150 个数字。

There are many ways to do this.有很多方法可以做到这一点。 One (better) way would be to loop reading each integer values as a string and converting each string to an integer value with strtol() .一种(更好的)方法是循环读取每个 integer 值作为字符串,并使用strtol()将每个字符串转换为 integer 值。 I say "better" in a sense that strtol() provides far better error reporting in the case of a failed conversion that the simple pass/fail that can be obtained from fscanf() .我说“更好”的意思是strtol()在转换失败的情况下提供更好的错误报告,而不是可以从fscanf()获得的简单通过/失败。

The read before looping with strtol() would be with fgets() into a sufficiently sized buffer.使用strtol()循环之前的读取将使用fgets()进入足够大的缓冲区。 That way if a matching-failure occurs, the error only impacts that line of data and no offending data is left in your input stream unread (as will occur with a matching-failure and fscanf() .这样,如果发生匹配失败,则错误只会影响该数据行,并且输入 stream 未读中不会留下任何违规数据(匹配失败fscanf()将发生这种情况。

That said, with a properly formatted space-separated file full of data, there is nothing wrong with using fscanf() directly, just be aware there are more robust ways to do the read and conversion.也就是说,对于一个格式正确、以空格分隔的文件充满数据,直接使用fscanf()并没有错,只是要注意有更强大的方法来进行读取和转换。

Look things over and let me know if you have further questions.如果您还有其他问题,请仔细查看并告诉我。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM