簡體   English   中英

C從文件中解析數據

[英]C parsing data from files

所以我試圖將文本文件中給出的一些數據解析為 C 程序。 文本文件包括:

4 4
1 1 0 0
1 1 0 0
0 0 1 1
0 0 1 1

前兩個數字是二維數組存儲整數所需的行數和長度。 到目前為止,我的代碼是:

        file = fopen(argv[1], "r");
        if (file == NULL)
        {
            perror("File IO error\n");
        }
        else
        {
            while(fgets(line, sizeof(line), file) != NULL)
            {        
                
                if(sscanf(line, "%d %d %d %d", &a, &b, &c, &d) == 4)
                {
                    printf("%d %d %d %d\n", a, b, c, d);
                }
                else
                {
                    sscanf(line, "%d %d", &ROW, &COL);
                    printf("ROW: %d COL: %d\n", ROW, COL);
                }

我遇到的問題是需要輸入其他文本文件。 它們與上面的行和列不同。 例如:

15 15
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 1 1 1 0 0 0 1 1 1 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 1 0 0 0 0 1 0 1 0 0 0 0 1 0
0 1 0 0 0 0 1 0 1 0 0 0 0 1 0
0 1 0 0 0 0 1 0 1 0 0 0 0 1 0
0 0 0 1 1 1 0 0 0 1 1 1 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 1 1 1 0 0 0 1 1 1 0 0 0
0 1 0 0 0 0 1 0 1 0 0 0 0 1 0
0 1 0 0 0 0 1 0 1 0 0 0 0 1 0
0 1 0 0 0 0 1 0 1 0 0 0 0 1 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 1 1 1 0 0 0 1 1 1 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

由於我的代碼每行僅適用於 4 個整數,因此它不適用於更大或更小的文件。 我將如何使其動態並根據大小進行解析。 謝謝

一次將數據讀取一個整數到緩沖區中。 如果您真的想要一個二維數組,您將不得不復制數據或注意前 2 個數據點並在讀取它們后分配數組。 但是,將數據流中的元素數量作為數據流前綴的做法是一種反模式,您並不真正想要二維數組。 您只希望能夠寫入data[i][j]來訪問緩沖區中的數據,就好像它是一個二維數組一樣。 另外,不要打擾文件 I/O。 從輸入流中讀取並寫入輸出流並讓 shell 處理重定向。 (例如,代替cmd input-file ,執行cmd < input-file )。 動態增加緩沖區是您應該練習的一項基本任務。 例如:

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

struct int_buf {
    int *data;
    size_t cap;
    size_t len;
};


void *xrealloc(void *b, size_t num, size_t siz);
static void
push(struct int_buf *b, int v)
{
    while( b->cap <= b->len ){
        b->data = xrealloc(b->data, b->cap += 128, sizeof *b->data);
    }
    b->data[b->len++] = v;
}


static void
die(const char *msg)
{
    fputs(msg, stderr);
    exit(EXIT_FAILURE);
}


int
main(int argc, char **argv)
{
    struct int_buf b = {NULL, 0, 0};
    int v;
    int rows, columns;

    if( scanf("%d %d", &rows, &columns) != 2 ){
        die("invalid row/column count\n");
    }
    while( scanf("%d", &v) == 1 ){
        push(&b, v);
    }
    if( ! feof(stdin) ){
        die(ferror(stdin) ? "input error\n" : "invalid data\n");
    }
    if( b.len != rows * columns ){
        die("inconsistent data\n");
    }
    int (*data)[columns] = (void *)b.data;

    for( int r = 0; r < rows; r += 1 ){
        printf(" row %3d: ", r);
        for( int c = 0; c < columns; c += 1 ){
            printf(" %3d", data[r][c]);
        }
        putchar('\n');
    }
}


void *
xrealloc(void *b, size_t num, size_t siz)
{
    b = realloc(b, num * siz);
    if( b == NULL ){
        perror("realloc");
        exit(EXIT_FAILURE);
    }
    return b;
}

在此特定用例中,不需要前兩個數據點。 對於這個示例,我們使用了它們,這樣我們就不必擔心輸入流中的換行符,這樣我們就可以使用scanfscanf是一個永遠不應該使用的糟糕工具,但這是一個不同的討論。這里我'會指出,在某些輸入上,上面的程序會表現出未定義的行為。你可以用"%12d"或類似的東西來避免這種情況,但是你需要知道一個整數的最大大小來決定使用什么值。語言保證非常保守,因此除非您想動態構建格式字符串或生成特定於平台的代碼,否則您將不得不使用諸如%4d之類的小得可笑的東西)。 我們可以像讀取流一樣輕松地計算換行符並丟棄前 2 個數據點。

如果您的文本文件已格式化。 你可以使用strtokstrtol

#include<stdio.h>
#include<string.h>
#include <stdlib.h>
int main() {
    char payload[] = {"1 2 3 4"};
    char *token = strtok(payload, " ");
    while (token) {
        int v = (int)strtol(token,NULL,10);
        printf("%d\n",v);
        token = strtok(NULL, " ");
    }
    return 0;
}

您可以像這樣在循環中運行 scanf:

int rows, cols;
if(fscanf(file, "%d %d", &rows, &cols) != 2) {
    // error
}

int num;
for(int i = 0; i<rows; ++i) {
    for(int j = 0; j < (cols - 1); ++j) {
        if(fscanf(file, "%d", &num) == 1) {
            printf("%d ", num);
        }
        else { /* error */ }
    }
    if(fscanf(file, "%d", &num) == 1) {
        printf("%d\n", num); // last col handled differently
    } 
    else { /* error */ }
}

如果你想一次接收整行,你可以使用 int 數組(不需要字符串,就像你的例子一樣)

int* row = malloc(sizeof(int) * cols); // allocate memory for array
if(row == NULL) {/* error */}
for(int i = 0; i<rows; ++i) {
    for(int j = 0; j < cols; ++j) {
        if(fscanf(file, "%d", &row[j]) != 1) { /* error */}
    }
    // do what you want with your row
}
free(row); // release array memory

為了讀取具有不同行數和列數的文件,我建議您在讀取包含行數和列數的第一行后動態分配內存。

例子:

#include <stdio.h>
#include <stdlib.h> // malloc/free

int main(int argc, char* argv[]) {
    if(argc != 2) return 1;

    FILE *file = fopen(argv[1], "r");
    if (file == NULL) {
        perror("fopen");
        return 1;
    }

    int ROW, COL;
    if(fscanf(file, "%d %d", &ROW, &COL) != 2 || ROW < 1 || COL < 1) {
        fprintf(stderr, "invalid file format\n");
        return 1;
    }

    // allocate the needed memory to store the data:
    int (*arr)[COL] = malloc(ROW * sizeof *arr);
    if(arr == NULL) {
        perror("malloc");
        return 1;
    }

    // read the data from file into your dynamically allocated array:
    for(int row = 0; row < ROW; ++row) {
        for(int col = 0; col < COL; ++col) {
            if(fscanf(file, " %d", &arr[row][col]) != 1) {
                fprintf(stderr, "invalid file format\n");
                fclose(file);
                free(arr);
                return 1;
            }
        }
    }
    fclose(file);

    // display the result:
    printf("ROW: %d COL: %d\n", ROW, COL);
    for(int row = 0; row < ROW; ++row) {
        for(int col = 0; col < COL; ++col) {
            printf("%d ", arr[row][col]);
        }
        putchar('\n');
    }

    free(arr); // release the memory allocated dynamically
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM