c - 这种字符串检索方法有什么缺点吗?

标签 c string dynamic input stdin

不久前我在这个网站上看到了一个功能,我把它做了一些调整以供我使用。

这是一个函数,它使用 getc 和 stdin 来检索字符串并精确分配包含该字符串所需的内存。然后它只返回一个指向已分配内存的指针,该内存填充有所述字符串。

我的问题是这个函数有什么缺点(除了以后必须手动释放分配的内存之外)吗?你会做什么来改善它?

char *getstr(void)
{
    char *str = NULL, *tmp = NULL;
    int ch = -1, sz = 0, pt = 0;

    while(ch)
    {
        ch = getc(stdin);
        if (ch == EOF || ch == 0x0A || ch == 0x0D) ch = 0;
        if (sz <= pt)
        {
            sz++; 
            tmp = realloc(str, sz * sizeof(char));
            if(!tmp) return NULL;
            str = tmp;
        }
        str[pt++] = ch;
    }

    return str;
}

在使用您的建议后,我更新了代码,我决定只使用 256 字节作为缓冲区,因为该函数用于用户输入。

char *getstr(void)
{
    char *str, *tmp = NULL;
    int ch = -1, bff = 256, pt = 0;

    str = malloc(bff);
        if(!str) 
        {
            printf(\nError! Memory allocation failed!");
            return 0x00;
        }
    while(ch)
    {
        ch = getc(stdin);
        if (ch == EOF || ch == '\n' || ch == '\r') ch = 0;
        if (bff <= pt)
        {
            bff += 256; 
            tmp = realloc(str, bff);
            if(!tmp) 
            {
                free(str);
                printf("\nError! Memory allocation failed!");
                return 0x00;
            }
            str = tmp;
        }
        str[pt++] = ch;
    }
    tmp = realloc(str, pt);
    if(!tmp)
    {
        free(str);
        printf("\nError! Memory allocation failed!");
        return 0x00;
    }
    str = tmp;

    return str;
}

最佳答案

IMO 过于节俭,并且犯了牺牲性能以节省无限量内存的错误,我认为这在大多数设置中毫无意义。像 realloc 这样的分配调用对系统来说可能很费力,这里是为每个字节完成的。

最好只有一个本地缓冲区,比如 4KB,用于读取,然后根据实际读取到的内容的长度分配返回字符串。请记住,无论您是否全部使用,普通系统上的堆栈* 都是 4-8MB。如果读取的字符串超过 4KB,您可以编写一个类似的循环来分配和复制到返回字符串中。所以一个类似的想法,但是堆分配会每 4096 个字节而不是每个字节发生一次,所以,例如,你有 4096 的初始缓冲区,当它用完时你 malloc 4096 返回字符串并复制,继续读入缓冲区(从头开始),如果再读取 1000 个字节,则重新分配到 5097 并返回它。

我认为初学者常犯的错误是沉迷于通过逐字节处理来最小化堆分配。甚至 KB by KB 也有点小;系统以页面 (4 KB) 为单位进行分配,您不妨将自己与此保持一致。

*为函数内部的本地存储提供的内存。

关于c - 这种字符串检索方法有什么缺点吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12075702/

相关文章:

铿锵C block : block function definition after call

c - "Terminated due to time out"C 中的错误,插入排序?

python - Python 文档字符串中的字符串操作

bash - Bash 中的动态变量名称

javascript - 如何使用 JavaScript 构建动态函数?

c++ - C 中是否有与 fill_n 等效的函数?

c - 使用 chdir() 从终端更改目录

php - 如何使用 distinct + 获取每个数据的总和从字符串中获取不同的数据

c++ - 如何在 C++ 中的 basic_string 中有空值

java - 新的Object.getClass()