簡體   English   中英

從C中的文本文件讀取值流

[英]Reading a stream of values from text file in C

我有一個文本文件,其中可能包含一個或最多400個數字。 每個數字用逗號分隔,分號用於表示數字流的結尾。 目前,我正在使用fget逐行讀取文本文件。 因此,我使用的是1024個元素的固定數組(文本文件每行的最大字符數)。 這不是實現此方法的理想方法,因為如果在文本文件中僅輸入一個數字,則我們將毫無意義地使用1024個元素的數組。 有沒有一種方法可以將fgets與malloc函數(或任何其他方法)一起使用以提高內存效率?

如果您想在生產代碼中使用它,那么我將請您遵循注釋部分中的建議。

但是,如果您對學習或學校的要求更高,那么這是一種復雜的方法。

偽代碼

1. Find the size of the file in bytes, you can use "stat" for this.
2. Since the file format is known, from the file size, calculate the number of items.
3. Use the number of items to malloc.

瞧! :p

如何查找文件大小

您可以使用stat ,如下所示:

#include <sys/stat.h>
#include <stdio.h>

int main(void)
{
    struct stat st;

    if (stat("file", &st) == 0) {
        printf("fileSize: %d  No. of Items: %d\n", (st.st_size), (st.st_size/2));
        return st.st_size;
    }

    printf("failed!\n");
    return 0;
}

該文件在運行時將返回文件大小:

$> cat file
1;
$> ./a.out
fileSize: 3  No. of Items: 1

$> cat file
1,2,3;
$> ./a.out
fileSize: 7  No. of Items: 3

免責聲明 :這種將預分配內存最小化的方法是否是最佳方法? 天上沒有路! :)

動態地為您的數據分配空間是使用C語言工作的基本工具。您不妨為此付出代價。 要記住的主要事情是,

“如果分配內存,則您有責任跟蹤其使用並保留指向該內存塊起始地址的指針,以便在完成處理后可以釋放它。否則,您的代碼就會像篩子一樣泄漏。”

動態分配是直接的。 您分配一些初始的內存塊,並跟蹤添加的內容。 您必須測試每個分配是否成功。 您必須測試使用了多少內存塊,並在內存已滿時重新分配或停止寫入數據,以防止寫入超出內存塊末尾的情況。 如果您都無法測試,則將破壞與代碼關聯的內存。

重新分配時,請始終使用臨時指針進行重新分配,因為重新分配失敗會釋放原始的內存塊。 (造成該區塊中所有先前資料的遺失)。 使用臨時指針可使您以需要的方式處理故障,以保留該塊。

考慮到這一點,下面我們首先為64個long值分配空間(您可以輕松地更改代碼以處理任何類型,例如intfloatdouble ...)。 然后,代碼讀取每行數據(使用getline為每行動態分配緩沖區)。 strtol用於解析將值分配給array的緩沖區。 idx用作索引以跟蹤已讀取的值,並且idx達到當前nmax ,將重新分配array ,大小是以前的兩倍,並且nmax會更新以反映更改。 繼續讀取,解析,檢查和重新分配文件中每一行數據。 完成后,將這些值打印到stdout,顯示從測試文件讀取的400個隨機值,格式為353,394,257,...293,58,135;

為了保持讀取循環邏輯的整潔,我將strtol轉換的錯誤檢查放入了xstrtol函數中,但是您可以隨意在main()包括該代碼。 realloc_long函數也是realloc_long 要查看重新分配的時間,可以使用-DDEBUG定義編譯代碼。 例如:

gcc -Wall -Wextra -DDEBUG -o progname yoursourcefile.c

該程序希望將數據文件名作為第一個參數,並且您可以提供一個可選的轉換基礎作為第二個參數(默認為10)。 例如:

./progname datafile.txt [base (default: 10)]

查看它,對其進行測試,如果您有任何問題,請告訴我。

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

#define NMAX 64

long xstrtol (char *p, char **ep, int base);
long *realloc_long (long *lp, unsigned long *n);

int main (int argc, char **argv)
{

    char *ln = NULL;                /* NULL forces getline to allocate  */
    size_t n = 0;                   /* max chars to read (0 - no limit) */
    ssize_t nchr = 0;               /* number of chars actually read    */
    size_t idx = 0;                 /* array index counter              */
    long *array = NULL;             /* pointer to long                  */
    unsigned long nmax = NMAX;      /* initial reallocation counter     */
    FILE *fp = NULL;                /* input file pointer               */
    int base = argc > 2 ? atoi (argv[2]) : 10; /* base (default: 10)    */

    /* open / validate file */
    if (!(fp = fopen (argv[1], "r"))) {
        fprintf (stderr, "error: file open failed '%s'.", argv[1]);
        return 1;
    }

    /* allocate array of NMAX long using calloc to initialize to 0 */
    if (!(array = calloc (NMAX, sizeof *array))) {
        fprintf (stderr, "error: memory allocation failed.");
        return 1;
    }

    /* read each line from file - separate into array       */
    while ((nchr = getline (&ln, &n, fp)) != -1)
    {
        char *p = ln;      /* pointer to ln read by getline */ 
        char *ep = NULL;   /* endpointer for strtol         */

        while (errno == 0)
        {   /* parse/convert each number in line into array */
            array[idx++] = xstrtol (p, &ep, base);

            if (idx == nmax)        /* check NMAX / realloc */
                array = realloc_long (array, &nmax);

            /* skip delimiters/move pointer to next digit   */
            while (*ep && *ep != '-' && (*ep < '0' || *ep > '9')) ep++;
            if (*ep)
                p = ep;
            else
                break;
        }
    }

    if (ln) free (ln);              /* free memory allocated by getline */
    if (fp) fclose (fp);            /* close open file descriptor       */

    int i = 0;
    for (i = 0; i < idx; i++)
        printf (" array[%d] : %ld\n", i, array[i]);

    free (array);

    return 0;
}

/* reallocate long pointer memory */
long *realloc_long (long *lp, unsigned long *n)
{
    long *tmp = realloc (lp, 2 * *n * sizeof *lp);
#ifdef DEBUG
    printf ("\n  reallocating %lu to %lu\n", *n, *n * 2);
#endif
    if (!tmp) {
        fprintf (stderr, "%s() error: reallocation failed.\n", __func__);
        // return NULL;
        exit (EXIT_FAILURE);
    }
    lp = tmp;
    memset (lp + *n, 0, *n * sizeof *lp); /* memset new ptrs 0 */
    *n *= 2;

    return lp;
}

long xstrtol (char *p, char **ep, int base)
{
    errno = 0;

    long tmp = strtol (p, ep, base);

    /* Check for various possible errors */
    if ((errno == ERANGE && (tmp == LONG_MIN || tmp == LONG_MAX)) ||
        (errno != 0 && tmp == 0)) {
        perror ("strtol");
        exit (EXIT_FAILURE);
    }

    if (*ep == p) {
        fprintf (stderr, "No digits were found\n");
        exit (EXIT_FAILURE);
    }

    return tmp;
}

樣本輸出(帶有-DDEBUG以顯示重新分配)

$ ./bin/read_long_csv dat/randlong.txt

  reallocating 64 to 128

  reallocating 128 to 256

  reallocating 256 to 512
 array[0] : 353
 array[1] : 394
 array[2] : 257
 array[3] : 173
 array[4] : 389
 array[5] : 332
 array[6] : 338
 array[7] : 293
 array[8] : 58
 array[9] : 135
<snip>
 array[395] : 146
 array[396] : 324
 array[397] : 424
 array[398] : 365
 array[399] : 205

內存錯誤檢查

$ valgrind ./bin/read_long_csv dat/randlong.txt
==26142== Memcheck, a memory error detector
==26142== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==26142== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==26142== Command: ./bin/read_long_csv dat/randlong.txt
==26142==

  reallocating 64 to 128

  reallocating 128 to 256

  reallocating 256 to 512
 array[0] : 353
 array[1] : 394
 array[2] : 257
 array[3] : 173
 array[4] : 389
 array[5] : 332
 array[6] : 338
 array[7] : 293
 array[8] : 58
 array[9] : 135
<snip>
 array[395] : 146
 array[396] : 324
 array[397] : 424
 array[398] : 365
 array[399] : 205
==26142==
==26142== HEAP SUMMARY:
==26142==     in use at exit: 0 bytes in 0 blocks
==26142==   total heap usage: 7 allocs, 7 frees, 9,886 bytes allocated
==26142==
==26142== All heap blocks were freed -- no leaks are possible
==26142==
==26142== For counts of detected and suppressed errors, rerun with: -v
==26142== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)

暫無
暫無

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

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