在 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
的指针fn
是NULL
,那么输入是从stdin
读取的。 (这只是增加了输入例程的灵活性)上面的调用可以很容易地成为:
./bin/getline_readfile_function ~/tmp/fc-list-fonts-sorted-no-path.txt
我是 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
的指针fn
是NULL
,那么输入是从stdin
读取的。 (这只是增加了输入例程的灵活性)上面的调用可以很容易地成为:
./bin/getline_readfile_function ~/tmp/fc-list-fonts-sorted-no-path.txt