[英]Input string without knowing the size
当我想存储我不知道大小的字符串时,有什么方法。
我喜欢这样:
#include <stdio.h>
#include <conio.h>
int main () {
char * str;
str = (char *)malloc(sizeof(char) + 1);
str[1] = '\0';
int i = 0;
int c = '\0';
do {
c = getche();
if(c != '\r'){
str[i] = c;
str[i + 1] = '\0';
i++;
str = (char *)realloc(str, sizeof(char) + i + 2);
}
} while(c != '\r');
printf("\n%s\n", str);
free(str);
return 0;
}
我找到了这个页面: 动态提示输入字符串而不知道字符串大小
正确吗? 如果是,那么:
有没有更好的办法?
有没有更有效的方法?
正确吗?
否
主要问题是realloc
的使用。 这是错误的。 使用realloc
永远不要直接分配给指向已分配内存的指针 - 始终使用临时对象来获取返回值。 像:
char * temp;
temp = realloc(str, 1 + i + 2);
if (temp == NULL)
{
// out of memory
.. add error handling
}
str = temp;
这样做的原因是realloc
可能会失败,在这种情况下它将返回 NULL。 因此,如果您直接分配给str
并且realloc
失败,则您丢失了指向已分配内存(也称为字符串)的指针。
除此之外:
1) 不要realloc
malloc
和realloc
2) sizeof(char)总是1 - 所以你不需要使用它 - 只要放 1
有没有更好的办法? 有没有更有效的方法?
与其在每个循环中按 1 重新分配 - 这在性能方面非常昂贵 - 在许多情况下最好(重新)分配更大的块。
一种策略是在调用realloc
时将分配加倍。 因此,如果您分配了 128 个字节,则下一次分配应该是 2*128=256。 另一种策略是让它以某个明显大于 1 的固定大小增长 - 例如,您可以让它每次增长 1024。
正确吗?
有点。
有没有更好的办法?
这主要是基于意见的。
有没有更有效的方法?
是关于时间还是空间?
如果你问的是空间,不。
如果你问时间,是的。
您可以为一个小数组动态分配内存,这将保留字符串一段时间。 然后,当数组无法再保存字符串时,您将重新分配该内存并将其大小加倍。 依此类推,直到读取整个字符串。 完成后,您可以再次重新分配内存,并将大小缩小为字符串所需的确切数字。
你看,调用realloc()
时间成本realloc()
,因为它可能必须移动整个内存块,因为内存必须是连续的,并且可能没有任何空间可以在不移动与内存相关的内存的情况下执行该操作字符串。
注意:当然,静态创建的固定大小的数组在时间方面会更好,但在内存方面会更糟。 一切都是权衡,这就是您发挥作用并决定最适合您的应用程序的地方。
回答这个问题的关键在于澄清“不知道大小”这个词。
你可能不知道你得到的大小,但你可能知道你会用它做什么。
一些用例:
您对所需的数据有限制,例如。 人名、地址、书名。 我猜你很擅长 1k 或最大 16k 的空间。
您会获得连续的数据流,例如。 某些传感器或其他设备每秒向您发送数据。 在这种情况下,您可以分块处理数据。
回答:
注意:请务必注意,您不能分配无限大小的内存。 在某些时候,您必须实施错误处理和/或您需要将数据存储在“磁盘”或其他地方。
注意二:如果你需要更多空间效率的解决方案,你不能使用realloc,因为它可能会复制分配的大小(如果系统不能简单地增加分配的空间,它会先分配一个新的内存块,然后复制当前内容)。 您需要创建自己的存储结构。 但这远远超出了范围,我期待您真正需要的东西。
我建议使用缓冲区来避免重复的重新分配调用。 创建一个缓冲区或任意大小,例如 1024,当它填满时,您可以将更多空间重新分配给动态分配的缓冲区,并将缓冲区内存移入其中。
这个怎么样?
char *string_name;
asprintf(&string_name, "Hello World, my name is %s & I'm %d years old!", "James Bond", 27);
printf("string is %s", string_name);
free(string_name);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.