我正在编写一个程序,该程序接收用户提供的文件并继续阅读。但是,我还想尽可能少地使用内存,因此不希望为数组分配100000个字符,除非它是完全必要的。这是我目前要读取文件的代码。
char *read_input(const char *file)
{
int fd;
int read_stat;
int i;
char tmp[1000000];
char buffer[1];
i = 0;
if ((fd = open(file, O_RDONLY)) == -1)
printf("Error");
while ((read_stat = read(fd, buffer, 1)))
{
tmp[i++] = buffer[0];
if (i > 1000000)
printf("Error");
}
tmp[i] = '\0';
if (close(fd) == -1)
printf("Error");
return (ft_strdup(tmp));
}
有什么建议吗?
答案 0 :(得分:1)
您可以使用stat()并根据动态分配内存到tmp来确定文件的大小。像 -
这样的东西 struct stat st;
off_t filesize;
if (stat(filename, &st) == 0)
filesize = st.st_size;
获得文件大小后,将大量内存分配给tmp。
答案 1 :(得分:1)
试试这个:
#include <sys/stat.h>
struct stat st;
stat(filename, &st);
int size = st.st_size;
printf("size = %d\n", size);
它应该为您提供size
中读取的陨石坑数量。
尼古拉斯
答案 2 :(得分:1)
有几种方法可以解决这个问题。传统方法是动态分配指针以指向每条线的每条线和内存。该计划非常简单。在read_input
中分配一些初始指针数,不断读取每一行,为每一行分配存储空间,并将内存块的地址分配给下一个可用指针,跟踪所用指针的数量,重新分配数字根据需要指针,并在函数结束时最后一次调用realloc
来调整分配给所需数字的指针数量。
当你消化该方案时,它基本上不分配比保存文件绝对必要的内存(每行+一个指针)。它与读取包含未知长度行的未知大小的文件一样,具有内存效率。
话虽如此,对read_input
进行一些调整。通常,文件在调用函数(此处为main()
)中打开,文件流指针(或文件描述符)作为参数传递给read_input
。您还应该将指向size_t
的指针作为第二个参数传递给read_input
,并使用read_input
中读取的行数更新指针,以便在调用者中返回值。
(您还可以在末尾分配一个额外的指针作为 sentinel NULL
,允许您确定读取的行数而不将指针传递给size_t
)
您将从 要处理文件操作,您可以自由使用文件描述符和低级 将所有这些放在一起,你可以做类似下面的事情,它将读取作为第一个参数给出的文件(如果没有提供参数,则默认来自 示例输入文件 示例使用/输出 内存使用/错误检查 您必须使用内存错误检查程序,以确保您不会尝试在已分配的内存块的范围之外/之外进行写入,尝试读取或基于未初始化值的条件跳转,最后,确认您释放了已分配的所有内存。 对于Linux 始终确认已释放已分配的所有内存并且没有内存错误。 仔细看看,如果您有其他问题,请告诉我。read_input
(例如char**
而不是char*
)返回指向char 指针的指针,使所有行都可用于调用函数。< / p>
read
/ write
函数,但C具有可用于读取/处理文本文件的文件流功能更容易一点。 (例如,使用fgets
或POSIX getline
阅读,如下所示)stdin
)。它将读取任意大小的文件,其长度为任意长度,直到达到文件末尾为止(除非在文件结束之前内存耗尽)#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXPTRS 32
char **read_input (FILE *fp, size_t *ndx)
{
size_t maxp = MAXPTRS, /* initial number of pointers */
n = 0; /* initial memory for line (0, getline decides) */
ssize_t nchr = 0; /* number of chars read by getline */
char *line = NULL, /* buffer to read each line */
**lines = NULL; /* pointer to pointer to all stored lines */
*ndx = 0; /* zero index pointer passed from caller */
if (!(lines = calloc (maxp, sizeof *lines))) { /* allocate pointers */
fprintf (stderr, "read_input: memory exhausted.\n");
return NULL;
}
/* read each line (into line) */
while ((nchr = getline (&line, &n, fp)) != -1) {
if (nchr && line[nchr - 1] == '\n') /* chk/trim trailing '\n' */
line[--nchr] = 0;
lines[*ndx] = strdup (line); /* duplicate line (belongs to getline) */
if (++(*ndx) == maxp) { /* check if reallocation of ptrs req'd */
void *tmp = realloc (lines, sizeof *lines * maxp * 2);
if (!tmp) { /* if realloc fails, bail */
fprintf (stderr, "read_input: memory exhausted - realloc.\n");
goto memlimit;
}
lines = tmp; /* assign reallocted block to lines */
/* zero all new memory (optional) */
memset (lines + maxp, 0, maxp * sizeof *lines);
maxp *= 2; /* increment number of allocated pointers */
}
}
/* final realloc to reduce to exact number of pointers */
void *tmp = realloc (lines, *ndx * sizeof *lines);
if (tmp)
lines = tmp;
if (*ndx == 0) { /* protect against realloc returning NULL or a */
free (lines); /* pointer suitable to be passed to free ambiguity */
lines = NULL;
}
memlimit:; /* label for goto */
free (line); /* free line (it belongs to getline) */
return lines;
}
int main (int argc, char **argv) {
size_t n = 0; /* number of lines read by read_input */
char **lines = NULL; /* ptr to ptr to char for lines returned */
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) { /* validate file open for reading */
fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
return 1;
}
/* call read_input/validate return */
if (!(lines = read_input (fp, &n)) || n == 0) {
fprintf (stderr, "error: read_input failed.\n");
return 1;
}
if (fp != stdin) fclose (fp); /* close file if not stdin */
for (size_t i = 0; i < n; i++) { /* iterate over each line */
printf ("line[%3zu] : %s\n", i, lines[i]);
free (lines[i]); /* free memory for line */
}
free (lines); /* free pointers */
return 0;
}
$ cat ../dat/captnjack.txt
This is a tale
Of Captain Jack Sparrow
A Pirate So Brave
On the Seven Seas.
$ ./bin/getline_read_input <../dat/captnjack.txt
line[ 0] : This is a tale
line[ 1] : Of Captain Jack Sparrow
line[ 2] : A Pirate So Brave
line[ 3] : On the Seven Seas.
valgrind
是正常的选择。每个平台都有类似的记忆检查器。它们都很简单易用,只需通过它运行程序即可。$ valgrind ./bin/getline_read_input <../dat/captnjack.txt
==20213== Memcheck, a memory error detector
==20213== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==20213== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==20213== Command: ./bin/getline_read_input
==20213==
line[ 0] : This is a tale
line[ 1] : Of Captain Jack Sparrow
line[ 2] : A Pirate So Brave
line[ 3] : On the Seven Seas.
==20213==
==20213== HEAP SUMMARY:
==20213== in use at exit: 0 bytes in 0 blocks
==20213== total heap usage: 7 allocs, 7 frees, 484 bytes allocated
==20213==
==20213== All heap blocks were freed -- no leaks are possible
==20213==
==20213== For counts of detected and suppressed errors, rerun with: -v
==20213== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
答案 3 :(得分:0)
你可以使用malloc,像这样的东西
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
char *read_input(const char *file) {
int fd;
char *buffer;
if ((fd = open(file, O_RDONLY)) == -1)
printf("Error");
int size = lseek(fd, 0, SEEK_END);
lseek(fd, 0, SEEK_SET);
buffer = (char*)malloc(size+1);
read(fd, buffer, size);
close(fd);
return buffer;
}
int main() {
char *r = read_input("test.txt");
//printf("%s\n",r);
free(r);
return 0;
}