sprintf()与自动内存分配?
我正在寻找一个sprintf() – 类似于自动分配所需内存的函数的实现。 所以我想说
char* my_str = dynamic_sprintf( "Hello %s, this is a %.*s nice %05d string", a, b, c, d );
并且my_str检索保存了sprintf()结果的分配内存的地址。
在另一个论坛上,我读到这样可以解决这个问题:
#include <stdlib.h> #include <stdio.h> #include <string.h> int main() { char* ret; char* a = "Hello"; char* b = "World"; int c = 123; int numbytes; numbytes = sprintf( (char*)NULL, "%s %d %s!", a, c, b ); printf( "numbytes = %d", numbytes ); ret = (char*)malloc( ( numbytes + 1 ) * sizeof( char ) ); sprintf( ret, "%s %d %s!", a, c, b ); printf( "ret = >%s<\n", ret ); free( ret ); return 0; }
但是,当带有NULL指针的sprintf()被调用时,立即导致段错误。
那么任何想法,解决scheme或提示? 放置在公共领域的sprintf()类似的parsing器的一个小实现已经足够了,然后我可以自己完成。
非常感谢!
这是Stack Overflow的原始答案。 正如其他人所说的,你需要snprintf
而不是sprintf
。 确保snprintf
的第二个参数是zero
。 这将阻止snprintf
写入第一个参数的NULL
string。
第二个参数是必需的,因为它告诉snprintf
足够的空间不可写入输出缓冲区。 当足够的空间不可用时, snprintf
返回它将写入的字节数,有足够的空间可用。
重现这个链接的代码在这里…
char* get_error_message(char const *msg) { size_t needed = snprintf(NULL, 0, "%s: %s (%d)", msg, strerror(errno), errno) + 1; char *buffer = malloc(needed); snprintf(buffer, needed, "%s: %s (%d)", msg, strerror(errno), errno); return buffer; }
GNU和BSD有asprintf和vasprintf,这些都是为你做的。 它会弄清楚如何为你分配内存,并在任何内存分配错误时返回null。
asprintf在分配string方面做了正确的事情 – 它首先测量大小,然后尝试使用malloc进行分配。 如果失败,则返回null。 除非你有自己的内存分配系统,不能使用malloc,asprintf是最好的工具。
代码如下所示:
#include <stdlib.h> #include <stdio.h> #include <string.h> int main() { char* ret; char* a = "Hello"; char* b = "World"; int c = 123; ret = asprintf( "%s %d %s!", a, c, b ); if (ret == NULL) { fprintf(stderr, "Error in asprintf\n"); return 1; } printf( "ret = >%s<\n", ret ); free( ret ); return 0; }
- 如果可能的话,使用
snprintf
– 它提供了一种简单的方法来衡量将生成的数据的大小,以便您可以分配空间。 - 如果你真的无法做到这一点,另一种可能是用
fprintf
打印临时文件来获得大小,分配内存,然后使用sprintf。snprintf
绝对是首选的方法。
如果你能忍受GNU / BSD的延伸,这个问题已经得到解答。 您可以使用asprintf()
(和vasprintf()
来构build包装函数)并完成。
但是,根据手册页,POSIX要求snprintf()
和vsnprintf()
,后者可以用来构build自己的简单版本的asprintf()
和vasprintf()
。
int vasprintf(char **strp, const char *fmt, va_list ap) { va_list ap1; size_t size; char *buffer; va_copy(ap1, ap); size = vsnprintf(NULL, 0, fmt, ap1) + 1; va_end(ap1); buffer = calloc(1, size); if (!buffer) return -1; *strp = buffer; return vsnprintf(buffer, size, fmt, ap); } int asprintf(char **strp, const char *fmt, ...) { int error; va_list ap; va_start(ap, fmt); error = vasprintf(strp, fmt, ap); va_end(ap); return error; }
你可以做一些预处理器的魔术,只在不支持它们的系统上使用你的函数版本。
GLib库提供了一个g_strdup_printf
函数,它完全符合你的要求,如果与GLib链接是一个选项。 从文档:
与标准的C
sprintf()
函数类似,但更安全,因为它计算所需的最大空间并分配内存来保存结果。 不再需要时,返回的string应该用g_free()
来释放。