我是c的新手,我在访问从文件读取的数据时遇到了问题。我试图做的事情背后的想法是获取一个文本文件,读入它,创建一个数组,并设置该数组的内容等于文件的内容(字符)。
现在,这就是我困惑的地方。要在main方法中操作tStr
,我需要能够访问它在read方法中的内容集。如果我试图访问主类中的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 %sn", fn);
exit(1);
}
while ((c = fgetc(fptr)) != EOF)
tStr[i++] = c;
tStr[i] = ' ';
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 %sn", fn);
exit(1);
}
while ((c = fgetc(fptr)) != EOF)
tStr[i++] = c;
tStr[i] = ' ';
return i;
}
注意数组必须足够大以容纳文件内容,否则会有未定义的行为。
在传递数组时,正常的c语言习惯是同时传递一个int或size_t形参,指示缓冲区的大小,并且只向缓冲区写入一定数量的字符。
传递一个已经打开的FILE*
可能比传递文件路径更好。减轻了文件相关错误指示功能的负担。
有时,有很好的理由能够简单地调用一个函数来读取文件,并让该函数返回一个指针,该指针指向保存文件内容的已分配字符串数组。当您不知道文件有多长时尤其如此。虽然你可以传递一个指针,但它需要一个***
参数来处理realloc
在重新分配时改变指针地址。
将函数声明为char **
并让它返回一个指向已分配数组的指针是处理这种情况的标准方法。此外,选择一些合理数量的指针进行初始分配,并遵循标准的重新分配方案(在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: %snn", 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] %sn", 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
读取input。(这只是增加了输入例程的灵活性)上面的调用也可以很容易地是:
./bin/getline_readfile_function ~/tmp/fc-list-fonts-sorted-no-path.txt