gpt4 book ai didi

c - 如何找出分配一个字符数组的空间大小

转载 作者:太空宇宙 更新时间:2023-11-04 06:54:49 25 4
gpt4 key购买 nike

我正在编写一个程序,它接受用户提供的文件并继续读取它。但是,我也想使用尽可能少的内存,因此除非完全有必要,否则不想为数组分配 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));
}

有什么建议吗?

最佳答案

有几种方法可以解决这个问题。传统的方法是动态分配一个指针指向每一行,并为每一行分配内存。该方案非常简单。在 read_input 中分配一些初始数量的指针,连续读取每一行,为每一行分配存储空间并将内存块的地址分配给下一个可用指针,跟踪使用的指针数量,根据需要重新分配指针的数量,并在函数结束时最后一次调用 realloc 以调整分配给所需数量的指针数量。

当你消化这个方案时,它基本上分配的内存不会超过保存文件所需的内存(每行+一个指针)。它与读取包含未知长度行的未知大小文件的内存效率差不多。

话虽如此,read_input 需要做一些调整。通常,文件在调用函数(此处为 main())中打开,并将文件流指针(或文件描述符)作为参数传递给 read_input。您还应该将指向 size_t 的指针作为第二个参数传递给 read_input,并用 read_input 中读取的行数更新指针,以便值在调用者中可用。

(您还可以在末尾分配一个额外的指针作为哨兵 NULL 允许您确定读取的行数而无需将指针传递给 大小_t)

您将从 read_input 返回一个指向 char 的指针(例如,char** 而不是 char*) 使所有行对调用函数可用。

要处理文件操作,您可以自由使用文件描述符和低级 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.

内存使用/错误检查

您必须使用内存错误检查程序来确保您不会尝试写入超出/超出分配的内存块边界、尝试读取或基于未初始化值的条件跳转,最后,确认您释放了所有已分配的内存。

对于 Linux 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)

始终确认您已释放所有分配的内存并且没有内存错误。

检查一下,如果您还有其他问题,请告诉我。

关于c - 如何找出分配一个字符数组的空间大小,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46480902/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com