这种字符串检索方法的任何缺点?

时间:2012-08-22 14:44:57

标签: 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;
}

4 个答案:

答案 0 :(得分:2)

是的,主要的问题是realloc非常慢并且每个角色重复调用它通常是一个坏主意。

尝试开始分配固定数量的内存,比如N=100个字符,当您需要更多时,请获取2*N,然后4*N等内容。你的内存最多只能占用两倍,但在运行时间内可以节省很多

答案 1 :(得分:2)

  1. 这完全取决于'\ n'=='0xa'和'\ r'=='\ 0d'没有充分理由。如果您的意思是\r\n,请使用它们。
  2. 对于你读过的每一个角色来说,重新分配可能会非常慢。
  3. sizeof(char)保证为1,所以没有意义。
  4. 如果你已经分配了一块内存,那么realloc就会失败,你将返回NULL而不返回或释放str,从而泄漏内存。
  5. 界面无法指示部分失败,如#4中所示。您所能做的就是返回一个字符串。给定一个巨大的输入字符串,你无法表明你已经阅读了部分而不是全部。

答案 2 :(得分:2)

以下是前几个观察结果,其他答案包括更多:

  1. 它一次增加缓冲区1个字节,从而不必要地进行多次realloc()次呼叫。
  2. 如果realloc()失败,则前一个缓冲区将丢失。
  3. 它不是getline(),虽然它当然更便携。
  4. 使用'\n''\r'代替换行和回车的硬编码也不是很方便。

答案 3 :(得分:2)

这是过分节俭的IMO,并且为了节省无限量的内存而犯了牺牲性能的错误,我认为这在大多数情况下毫无意义。像realloc这样的分配调用对系统来说可能很费力,而且每个字节都会这样做。

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

我认为初学者常常误以为通过逐字接近来最小化堆分配。甚至KB by KB也有点小;系统以页面(4 KB)分配,您也可以与之对齐。

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