为什么 snprintf 会更改第二个字符串?
why is snprintf changing the second string?
我正在尝试使用 snprintf 连接两个字符串,它适用于非常小的字符串,例如。 1 或 2 个字符,再多一些,这种事情就会发生。第一个字符串的最后一个字符重复
int main()
{
char str1[] = "foo", str2[] = "bar", str3[]= "";
printf("%s %s\n", str1, str2);
snprintf(str3, strlen(str1) + strlen(str2) + 1, "%s %s", str1, str2);
printf("%s", str3);
return 0;
}
输出:
foo bar
foo oo
您的代码的问题是 str3
不够大,无法容纳 str1
和 str2
。
由于您使用 ""
初始化 str3
,因此 str3
的大小将设置为 1
。
这里是正确的方法:
#include <stdio.h> // snprintf
#include <stdlib.h> // malloc, free
#include <string.h> // strlen
int main() {
char str1[] = "foo";
char str2[] = "bar";
// We need to dynamically allocate the third buffer
// since its size is not determined at compile time.
// The size we need is the length of str1, str2, + 1 for a space
// and + 1 for the NUL terminator.
size_t str3_size = strlen(str1) + strlen(str2) + 2;
char *str3 = malloc(str3_size);
// NULL = out of memory
if (!str3) {
printf("oops!"); return EXIT_FAILURE;
}
snprintf(str3, str3_size, "%s %s", str1, str2);
printf("%s", str3);
// Don't forget to free malloc'd memory!
free(str3);
}
如果您使用的是 C99 编译器,则可以完全放弃 malloc 并在堆栈上分配第三个缓冲区,如下所示:
#include <stdio.h> // snprintf
#include <stdlib.h> // EXIT_FAILURE
#include <string.h> // strlen
int main() {
char str1[] = "foo";
char str2[] = "bar";
// The size we need is the length of str1, str2, + 1 for a space
// and + 1 for the NUL terminator.
size_t str3_size = strlen(str1) + strlen(str2) + 2;
char str3[str3_size];
snprintf(str3, str3_size, "%s %s", str1, str2);
printf("%s", str3);
}
但要小心,在堆栈上分配动态大小的内存可能很危险!
还有一个函数asprintf
(GNU 扩展)可以自动计算正确的大小。这里有同样的例子:
#include <stdio.h> // asprintf
#include <stdlib.h> // free
int main() {
char str1[] = "foo";
char str2[] = "bar";
char *str3 = NULL;
asprintf(&str3, "%s %s\n", str1, str2);
// str3 now contains a pointer to the allocated memory :)
// NULL = out of memory
if (!str3) {
printf("oops!"); return EXIT_FAILURE;
}
printf("%s", str3);
// Don't forget to free malloc'd memory!
free(str3);
}
我正在尝试使用 snprintf 连接两个字符串,它适用于非常小的字符串,例如。 1 或 2 个字符,再多一些,这种事情就会发生。第一个字符串的最后一个字符重复
int main()
{
char str1[] = "foo", str2[] = "bar", str3[]= "";
printf("%s %s\n", str1, str2);
snprintf(str3, strlen(str1) + strlen(str2) + 1, "%s %s", str1, str2);
printf("%s", str3);
return 0;
}
输出:
foo bar
foo oo
您的代码的问题是 str3
不够大,无法容纳 str1
和 str2
。
由于您使用 ""
初始化 str3
,因此 str3
的大小将设置为 1
。
这里是正确的方法:
#include <stdio.h> // snprintf
#include <stdlib.h> // malloc, free
#include <string.h> // strlen
int main() {
char str1[] = "foo";
char str2[] = "bar";
// We need to dynamically allocate the third buffer
// since its size is not determined at compile time.
// The size we need is the length of str1, str2, + 1 for a space
// and + 1 for the NUL terminator.
size_t str3_size = strlen(str1) + strlen(str2) + 2;
char *str3 = malloc(str3_size);
// NULL = out of memory
if (!str3) {
printf("oops!"); return EXIT_FAILURE;
}
snprintf(str3, str3_size, "%s %s", str1, str2);
printf("%s", str3);
// Don't forget to free malloc'd memory!
free(str3);
}
如果您使用的是 C99 编译器,则可以完全放弃 malloc 并在堆栈上分配第三个缓冲区,如下所示:
#include <stdio.h> // snprintf
#include <stdlib.h> // EXIT_FAILURE
#include <string.h> // strlen
int main() {
char str1[] = "foo";
char str2[] = "bar";
// The size we need is the length of str1, str2, + 1 for a space
// and + 1 for the NUL terminator.
size_t str3_size = strlen(str1) + strlen(str2) + 2;
char str3[str3_size];
snprintf(str3, str3_size, "%s %s", str1, str2);
printf("%s", str3);
}
但要小心,在堆栈上分配动态大小的内存可能很危险!
还有一个函数asprintf
(GNU 扩展)可以自动计算正确的大小。这里有同样的例子:
#include <stdio.h> // asprintf
#include <stdlib.h> // free
int main() {
char str1[] = "foo";
char str2[] = "bar";
char *str3 = NULL;
asprintf(&str3, "%s %s\n", str1, str2);
// str3 now contains a pointer to the allocated memory :)
// NULL = out of memory
if (!str3) {
printf("oops!"); return EXIT_FAILURE;
}
printf("%s", str3);
// Don't forget to free malloc'd memory!
free(str3);
}