簡體   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