前段时间我在这个网站上看到了一个功能,我采用了一些功能并对其进行了改编。
这是一个使用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;
}
答案 0 :(得分:2)
是的,主要的问题是realloc
非常慢并且每个角色重复调用它通常是一个坏主意。
尝试开始分配固定数量的内存,比如N=100
个字符,当您需要更多时,请获取2*N
,然后4*N
等内容。你的内存最多只能占用两倍,但在运行时间内可以节省很多。
答案 1 :(得分:2)
\r
和\n
,请使用它们。sizeof(char)
保证为1,所以没有意义。str
,从而泄漏内存。答案 2 :(得分:2)
以下是前几个观察结果,其他答案包括更多:
realloc()
次呼叫。realloc()
失败,则前一个缓冲区将丢失。getline()
,虽然它当然更便携。'\n'
和'\r'
代替换行和回车的硬编码也不是很方便。答案 3 :(得分:2)
这是过分节俭的IMO,并且为了节省无限量的内存而犯了牺牲性能的错误,我认为这在大多数情况下毫无意义。像realloc这样的分配调用对系统来说可能很费力,而且每个字节都会这样做。
最好只有一个本地缓冲区(比如4KB)来读入,然后根据实际读取的长度分配返回字符串。请记住,正常系统上的堆栈*无论如何都是4-8MB,无论你是否使用它。如果读取的字符串长度超过4KB,则可以编写一个类似的循环,分配并复制到返回字符串中。所以类似的想法,但堆分配将每4096个字节而不是每个字节发生,因此,例如,你有4096的初始缓冲区,当你用尽了malloc 4096的返回字符串并复制进来,继续读入缓冲区(从头开始),如果读取另外1000个字节,则重新分配到5097并返回。
我认为初学者常常误以为通过逐字接近来最小化堆分配。甚至KB by KB也有点小;系统以页面(4 KB)分配,您也可以与之对齐。
*为函数内的本地存储提供的内存。