在 C 中读取文件并将内容传递给 main()

Reading a file in C and passing the contents to main()

我是 C 的新手。我在访问从文件中读入的数据时遇到问题。我想要做的事情背后的想法是获取一个文本文件,读入它,创建一个数组并将该数组的内容设置为等于文件的内容(字符)。

现在,这就是我感到困惑的地方。要在 main 方法中操作 tStr,我需要能够访问其在 read 方法中设置的内容。如果我尝试访问主 class 中的 tStr 数组,根据我的理解,您将无法认为您只设置了它的大小但没有向其中传递任何值。

如果我想编辑应该包含文本文件内容的数组 tStr,我该如何将数据从 readFile() 获取到 main()

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

    #define size 1000

    int readFile(char fn[], char tStr[]);

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

        char tStr[size];
        return 0;
    }

    int readFile(char fn[], char tStr[])
    {
        FILE *fptr;
        char c;
        int i = 0;

        if ((fptr=fopen(fn, "r")) == NULL){
            printf("Error: unknown file %s\n", fn);
            exit(1);
        }

        while ((c = fgetc(fptr)) != EOF)
            tStr[i++] = c;

        tStr[i] = '[=10=]';

        return i;   
    }

只需调用 readFile 并将文件路径和要填充文件内容的数组传递给它。

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

    #define size 1000

    int readFile(char fn[], char tStr[]);

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

        char tStr[size];
        readFile("file.txt",tStr);
        printf("%s", tStr);
        return 0;
    }

    int readFile(char fn[], char tStr[])
    {
        FILE *fptr;
        char c;
        int i = 0;

        if ((fptr=fopen(fn, "r")) == NULL){
            printf("Error: unknown file %s\n", fn);
            exit(1);
        }

        while ((c = fgetc(fptr)) != EOF)
            tStr[i++] = c;

        tStr[i] = '[=10=]';

        return i;   
    }

请注意,数组必须足够大以容纳文件内容,否则将出现未定义的行为。

传递数组时的正常 c 习惯用法是同时传递一个 int 或 size_t 参数来指示缓冲区的大小,并且只将那么多的字符写入缓冲区。

同时传递一个已经打开的 FILE* 可能比传递文件路径更好。减轻指示文件相关错误的负担的功能。

有时,有充分的理由能够简单地调用一个函数来读取文件,并让函数 return 指向一个已分配的字符串数组,该数组保存文件的内容。当您不知道文件的长度时尤其如此。虽然您可以传递一个指针,但它需要一个 *** 参数来处理 realloc 在重新分配时更改指针地址。

将函数声明为 char ** 并使其 return 指向已分配数组的指针是处理这种情况的标准方法。此外,选择一些合理数量的指针进行初始分配并遵循标准的重新分配方案(在 realloc 上,分配 2X 当前指针的数量)避免了对 realloc 的昂贵且相对昂贵的调用为文件中的每一行调用 realloc 时。

当你动态分配内存时,由你来跟踪内存,保存一个指向内存块开始的指针(这样你就可以 free 它),并且 free 不再需要时的内存。

下面用一个简短的例子将所有这些拼图拼凑在一起。该示例使用 getline 从文件中读取行,并使用 strdup(分配内存和副本)将 getline 读取的行复制到字符串数组中。如果您有任何问题,请告诉我:

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

#define NMAX 256

char **readtxtfile (char *fn, size_t *idx);
void prn_chararray (char **ca);
void free_chararray (char **ca);

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

    size_t file_size = 0;   /* placeholders to be filled by readtxtfile */
    char *fn = argc > 1 ? argv[1] : NULL;

    /* read each file into an array of strings,
    number of lines read, returned in file_size */
    char **file = readtxtfile (fn, &file_size);

    /* output number of lines read and from where  */
    printf ("\n read '%zu' lines from file: %s\n\n", file_size, fn ? fn : "stdin");

    /* simple print function */
    if (file) prn_chararray (file);

    /* simple free memory function */
    if (file) free_chararray (file);

    return 0;
}

char **readtxtfile (char *fn, size_t *idx)
{
    char *ln = NULL;                /* NULL forces getline to allocate  */
    size_t n = 0;                   /* size of ln, 0 - getline decides  */
    ssize_t nchr = 0;               /* number of chars actually read    */
    size_t nmax = NMAX;             /* check for reallocation           */
    char **array = NULL;            /* array to hold lines read         */
    FILE *fp = NULL;                /* file pointer to open file fn     */

    /* open / validate file or read stdin */
    if (fn) {
        if (!(fp = fopen (fn, "r"))) {
            fprintf (stderr, "%s() error: file open failed '%s'.", __func__, fn);
            return NULL;
        }
    }
    else
        fp = stdin;

    /* allocate NMAX pointers to char* */
    if (!(array = calloc (NMAX, sizeof *array))) {
        fprintf (stderr, "%s() error: memory allocation failed.", __func__);
        return NULL;
    }

    /* read each line from stdin - dynamicallly allocated   */
    while ((nchr = getline (&ln, &n, fp)) != -1)
    {
        /* strip newline or carriage rtn    */
        while (nchr > 0 && (ln[nchr-1] == '\n' || ln[nchr-1] == '\r'))
            ln[--nchr] = 0;

    array[*idx] = strdup (ln);  /* allocate/copy ln to array        */

        (*idx)++;                   /* increment value at index         */

        if (*idx == nmax) {         /* if lines exceed nmax, reallocate */
            char **tmp = realloc (array, nmax * 2);
            if (!tmp) {
                fprintf (stderr, "%s() error: reallocation failed.\n", __func__);
                exit (EXIT_FAILURE); /* or return NULL; */
            }
            array = tmp;
            nmax *= 2;
        }
    }

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

    return array;
}

/* print an array of character pointers. */
void prn_chararray (char **ca)
{
    register size_t n = 0;
    while (ca[n])
    {
        printf (" arr[%3zu]  %s\n", n, ca[n]);
        n++;
    }
}

/* free array of char* */
void free_chararray (char **ca)
{
    if (!ca) return;
    register size_t n = 0;
    while (ca[n])
        free (ca[n++]);
    free (ca);
}

输出

$ /bin/getline_readfile_function <~/tmp/fc-list-fonts-sorted-no-path.txt

 read '187' lines from file: stdin

 arr[  0]  andalemo.ttf: Andale Mono - Regular
 arr[  1]  arialbd.ttf: Arial - Bold
 arr[  2]  arialbi.ttf: Arial - Bold Italic
 arr[  3]  ariali.ttf: Arial - Italic
 arr[  4]  arialnbi.ttf: Arial
 arr[  5]  arialnb.ttf: Arial
 arr[  6]  arialni.ttf: Arial
 arr[  7]  arialn.ttf: Arial
 arr[  8]  arial.ttf: Arial - Regular
 arr[  9]  ARIALUNI.TTF: Arial Unicode MS - Regular
 arr[ 10]  ariblk.ttf: Arial
 arr[ 11]  Bailey Script Regular.ttf: Bailey Script - Regular
 arr[ 12]  Bailey_Script_Regular.ttf: Bailey Script - Regular
 arr[ 13]  Belwe Gotisch.ttf: Belwe Gotisch - Regular
 arr[ 14]  Belwe_Gotisch.ttf: Belwe Gotisch - Regular
<snip>

内存检查

$ valgrind ./bin/getline_readfile_function <~/tmp/fc-list-fonts-sorted-no-path.txt
==20259== Memcheck, a memory error detector
==20259== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==20259== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==20259== Command: ./bin/getline_readfile_function
==20259==

 read '187' lines from file: stdin

 arr[  0]  andalemo.ttf: Andale Mono - Regular
 arr[  1]  arialbd.ttf: Arial - Bold
 arr[  2]  arialbi.ttf: Arial - Bold Italic
 arr[  3]  ariali.ttf: Arial - Italic
<snip>

==20259==
==20259== HEAP SUMMARY:
==20259==     in use at exit: 0 bytes in 0 blocks
==20259==   total heap usage: 189 allocs, 189 frees, 9,831 bytes allocated
==20259==
==20259== All heap blocks were freed -- no leaks are possible
==20259==
==20259== For counts of detected and suppressed errors, rerun with: -v
==20259== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)

注意:如果传递给readtxtfile的指针fnNULL,那么输入是从stdin读取的。 (这只是增加了输入例程的灵活性)上面的调用可以很容易地成为:

./bin/getline_readfile_function ~/tmp/fc-list-fonts-sorted-no-path.txt