如果你使用sprintf()或vsprintf(),你需要先分配一个缓冲区,并且你需要确保缓冲区足够大以容纳sprintf写入的内容。否则sprintf() 将愉快地覆盖缓冲区末尾之外的任何内存。
char* x = malloc(5 * sizeof(char));
// writes "123456" +null but overruns the buffer
sprintf(x,"%s%s%s", "12", "34", "56");
... 将“6”和终止的null 写入分配给x 的空间末尾之外,这可能会破坏其他一些变量,或者导致分段错误。
如果幸运的话,它会在分配的块之间践踏内存,并且不会造成任何伤害——这一次。这会导致间歇性错误——最难诊断的错误。最好使用像 ElectricFence 这样的工具,它会导致超限快速失败。
提供过长输入的非恶意用户可能会导致程序以意想不到的方式运行。恶意用户可以利用此方法将自己的可执行代码导入系统。
一个防范措施是使用snprintf(),它将字符串截断为您提供的最大长度。
char *x = malloc(5 * sizeof(char));
int size = snprintf(x, 5, "%s%s%s", "12", "34", "56"); // writes "1234" + null
返回值size 是在有可用空间的情况下应该写入的长度 -- 不包括终止的空值。
在这种情况下,如果 size 大于或等于 5,那么您知道发生了截断 - 如果您不想截断,您可以分配一个新字符串并再次尝试 snprintf()。
char *x = malloc(BUF_LEN * sizeof(char));
int size = snprintf(x, 5, "%s%s%s", "12", "34", "56");
if (size >= BUF_LEN) {
realloc(&x,(size + 1) * sizeof(char));
snprintf(x, size + 1 , "%s%s%s", "12", "34", "56");
}
(这是一个非常幼稚的算法,但它说明了这一点。其中可能还存在错误,这进一步说明了这一点——这东西很容易搞砸。)
asprintf() 为您一步完成 - 计算字符串的长度,分配相应的内存量,然后将字符串写入其中。
char *x;
int size = asprintf(&x, "%s%s%s", "12", "34", "56");
在所有情况下,一旦你完成了x,你需要释放它,否则你会泄漏内存:
free(x);
asprintf() 是一个隐含的malloc(),因此您必须检查它是否有效,就像使用malloc() 或任何其他系统调用一样。
if (size == -1 ) {
/* deal with error in some way */
}
请注意,asprintf() 是 libc 的 GNU 和 BSD 扩展的一部分 - 您不能确定它在每个 C 环境中都可用。 sprintf() 和 snprintf() 是 POSIX 和 C99 标准的一部分。