如何找出分配char数组的空间

时间:2017-09-29 02:27:54

标签: c arrays

我正在编写一个程序,该程序接收用户提供的文件并继续阅读。但是,我还想尽可能少地使用内存,因此不希望为数组分配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));
}

有什么建议吗?

4 个答案:

答案 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

您将从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.

内存使用/错误检查

您必须使用内存错误检查程序,以确保您不会尝试在已分配的内存块的范围之外/之外进行写入,尝试读取或基于未初始化值的条件跳转,最后,确认您释放了已分配的所有内存。

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

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

仔细看看,如果您有其他问题,请告诉我。

答案 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;

}