繁体   English   中英

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

[英]Reading text file into a matrix in C

我有一个包含 200 x 150 数据的文本文件(每个数字都用空格分隔)。 我正在尝试将这些数字存储到矩阵中。 我的代码是这样的:

#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();
}

它实际上什么也没有打印出来。 我不明白为什么。 我该如何修复我的代码,或者您有任何其他重写它的建议?

很多问题:

  • 永远不要使用while(!feof(file)){ 而是检查fscanf(file, ...)的返回值

  • 不要使用没有宽度限制"%s"

  • 不要在没有先初始化/分配它的情况下使用传递line到 function。

  • i从来没有增加过。

  • fclose(file)完成后。

  • 检查fopen(...);


GTG,也许以后会更多。

如果您有一个文件,其中包含 200x150 integer 值(在 200 行上,或在一行上的所有值),那么只需使用fscanf()循环读取并存储 integer 一次即可。 您必须验证每次读取并提供一种方法来通过 function 返回(或通过函数内更新的指针)传达 function 内的任何故障

首先,不要在代码中使用MagicNumbers ,也不要硬编码文件名。 相反,# #define您需要的常量(或使用全局enum )并在调用 function 中打开(并验证文件已打开以供读取)后将打开的FILE*指针作为参数传递给您的读取函数。 (如果文件打开失败——没有理由开始调用读取函数)

在您的情况下,您只有两个需要的常量:

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

除非绝对必要,否则不要使用全局变量(当您开始学习 C 时,几乎没有需要全局变量的情况)。 将矩阵(二维数组)作为参数传递给您的读取函数,它可以写成:

/* 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;
}

注意: function 的返回类型如何为int ,其中成功返回1 (true),失败返回0 (false)。另请注意,如果无法读取 200x150 值,则返回失败)

将要读取的文件名作为第一个参数传递给程序(这就是 main main()int argc, char **argv参数的用途)。 或者,您可以提示用户并读取文件名作为输入。 如果没有输入文件名,您可以提供一个固定的文件名作为默认值( stdin用作下面的默认值),否则不要硬编码文件名。 您不必为了读取不同的文件名而重新编译程序。

通过这些改进,您的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 */
}

完整的程序是:

#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 */
}

示例使用/输出

生成小于 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 ...
...

其中 output 是 200 行,每行 150 个数字。

有很多方法可以做到这一点。 一种(更好的)方法是循环读取每个 integer 值作为字符串,并使用strtol()将每个字符串转换为 integer 值。 我说“更好”的意思是strtol()在转换失败的情况下提供更好的错误报告,而不是可以从fscanf()获得的简单通过/失败。

使用strtol()循环之前的读取将使用fgets()进入足够大的缓冲区。 这样,如果发生匹配失败,则错误只会影响该数据行,并且输入 stream 未读中不会留下任何违规数据(匹配失败fscanf()将发生这种情况。

也就是说,对于一个格式正确、以空格分隔的文件充满数据,直接使用fscanf()并没有错,只是要注意有更强大的方法来进行读取和转换。

如果您还有其他问题,请仔细查看并告诉我。

暂无
暂无

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

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