How to append strings using sprintf?
我面临sprintf的严重问题。
假设我的代码段是:
几百冲刺...
如果我这样做,它就会被覆盖。
如何避免使用sprintf覆盖过多。 如果我在最后给出一个printf,我想查看所有行。
-
我将不使用sprintf而是snprintf,我将不使用printf(str)而是printf("%s",str)
你需要:
当然,您需要缓冲区足够大。
-
缓冲区足够大...我会尝试...
-
+1尽管我更喜欢Aeths解决方案,但它似乎比每次重新计算字符串长度都有效。
-
我看到的一个窍门是#define eos(s) ((s)+strlen(s)),或者根据需要声明一个函数。然后您可以使用sprintf(eos(Buffer),"Stuff")
-
更简单的是,您可以只使用sprintf(strchr(s, \0),"...")。
-
附加到实际Buffer的+ strlen(Buffer)是什么?
-
这是指针算法。就像将字符串的当前长度添加到Buffer的起始地址一样。此操作对于mbs和unicode字符串不安全。例如,获取Unicode字符串" Hello"的长度将返回5,但是在这种情况下,实际上需要Buffer + 5 * sizeof(wchar_t)
1 2 3 4
| int length = 0;
length += sprintf(Buffer +length ,"Hello World");
length += sprintf(Buffer +length ,"Good Morning");
length += sprintf(Buffer +length ,"Good Afternoon"); |
这是对错误有一定抵抗力的版本。如果您不关心何时会发生错误,这将很有用,只要您可以继续按照自己的喜好继续操作即可。
1 2 3 4 5 6 7 8 9
| int bytes_added ( int result_of_sprintf )
{
return (result_of_sprintf > 0) ? result_of_sprintf : 0;
}
int length = 0;
length += bytes_added (sprintf(Buffer +length ,"Hello World"));
length += bytes_added (sprintf(Buffer +length ,"Good Morning"));
length += bytes_added (sprintf(Buffer +length ,"Good Afternoon")); |
-
但是,如果sprintf遇到转换失败怎么办?
-
然后,您会发生坏事。为了简洁起见,我省略了错误检查。
-
+1-无论如何,额外的错误检查应该是读者的一项练习。毕竟,它们的代码是:)
-
我认为在sprintf结果否定的情况下报告错误和错误是有意义的。
为了安全(缓冲区溢出),我建议使用snprintf()
1 2 3 4 5 6 7
| const int MAX_BUF = 1000;
char* Buffer = malloc(MAX_BUF );
int length = 0;
length += snprintf(Buffer +length , MAX_BUF -length ,"Hello World");
length += snprintf(Buffer +length , MAX_BUF -length ,"Good Morning");
length += snprintf(Buffer +length , MAX_BUF -length ,"Good Afternoon"); |
-
snprintf的第二个参数是无符号的(size_t),这意味着如果length> MAX_BUF,则MAX_BUF-length将下溢,并且snprintf将愉快地写入缓冲区之外,从而造成缓冲区溢出。请注意,如果有足够的可用空间,则snprintf的返回值等于将要写入的字节数,而不是实际写入的字节数。
snprintf()的snprintfcat()包装器:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| size_t
snprintfcat (
char* buf ,
size_t bufSize ,
char const* fmt ,
... )
{
size_t result ;
va_list args ;
size_t len = strnlen ( buf , bufSize );
va_start( args , fmt );
result = vsnprintf ( buf + len , bufSize - len , fmt , args );
va_end( args );
return result + len ;
} |
使用sprintf()的返回值
1 2 3
| Buffer += sprintf(Buffer ,"Hello World");
Buffer += sprintf(Buffer ,"Good Morning");
Buffer += sprintf(Buffer ,"Good Afternoon"); |
-
这是最好的解决方案,无需费劲
-
注意,您还需要保存缓冲区的起始地址,以备将来参考。
当有专门针对您需要的方法(例如strcat和strncat)时,为什么要使用sprintf进行字符串连接?
-
该示例可能是仅附加字符串的琐碎情况。该问题可以扩展到包括附加其他类型的格式化数据的情况,而strcat对此格式不适用。
我认为您正在寻找fmemopen(3):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| #include
#include <stdio.h>
int main (void)
{
char buf [128] = { 0 };
FILE *fp = fmemopen (buf , sizeof(buf ),"w");
assert(fp );
fprintf(fp ,"Hello World!
");
fprintf(fp ,"%s also work, of course.
","Format specifiers");
fclose(fp );
puts(buf );
return 0;
} |
如果动态存储更适合您的用例,则可以遵循Liam关于使用open_memstream(3)的出色建议:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| #include
#include <stdio.h>
#include <stdlib.h>
int main (void)
{
char *buf ;
size_t size ;
FILE *fp = open_memstream (&buf , &size );
assert(fp );
fprintf(fp ,"Hello World!
");
fprintf(fp ,"%s also work, of course.
","Format specifiers");
fclose(fp );
puts(buf );
free(buf );
return 0;
} |
-
这就是我想要的。在man fmemopen的建议下,我发现open_memstream更适合我的应用程序。有关示例,请参见GNU手册。
-
@Liam很棒,感谢您提供有关open_memstream的技巧。我也为此添加了一个示例。
-
妙极了,除了Windows上fmemopen和open_memstream都不可用。
您是否只是在附加字符串文字?还是要追加各种数据类型(int,float等)?
将其抽象到其自己的函数中可能会更容易(以下假设为C99):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| #include <stdio.h>
#include <stdarg.h>
#include <string.h>
int appendToStr (char *target , size_t targetSize , const char * restrict format , ... )
{
va_list args ;
char temp [targetSize ];
int result ;
va_start(args , format );
result = vsnprintf (temp , targetSize , format , args );
if (result != EOF )
{
if (strlen(temp ) + strlen(target ) > targetSize )
{
fprintf(stderr ,"appendToStr: target buffer not large enough to hold additional string");
return 0;
}
strcat(target , temp );
}
va_end(args );
return result ;
} |
您将像这样使用它:
1 2 3 4 5
| char target[100] = {0};
...
appendToStr(target, sizeof target,"%s %d %f
","This is a test", 42, 3.14159);
appendToStr(target, sizeof target,"blah blah blah"); |
等等
该函数从vsprintf返回值,在大多数实现中,该值是写入目标的字节数。此实现中有一些漏洞,但是应该给您一些想法。
-
为什么不将sizeof目标放在函数中?为什么在参数中需要它?
-
@hellomyfriends:因为在函数中,target是指向char的指针,而不是char的数组,并且sizeof将仅返回指针的大小,而不是其指向的数组的大小。
我发现以下方法很好用。
-
strlen周围的[...]?应该是(...)吗?
-
太多的Python:D
使用strcat http://www.cplusplus.com/reference/cstring/strcat/
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| int main ()
{
char str [80];
strcpy (str ,"these");
strcat (str ,"strings");
strcat (str ,"are");
strcat (str ,"concatenated.");
puts (str );
return 0;
}
Output :
these strings are concatenated. |
您可以使用下面显示的简单行将字符串追加到一个缓冲区中:
1
| sprintf(Buffer ,"%s %s %s","Hello World","Good Morning","Good Afternoon"); |
小完整代码示例
仅使用平面stdio标准库
1 2 3 4 5 6 7 8 9 10 11 12
| #include <stdio.h>
int main ()
{
char c [1024];
int i =0;
i +=sprintf(c +i ,"We" );
i +=sprintf(c +i ,"Love" );
sprintf(c +i ,"Coding");
printf("%s",c );
} |
输出:我们喜欢编码
我编写了一个函数支持动态变量字符串附加,例如PHP str append:str。海峡...等
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| #include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
int str_append (char **json , const char *format , ... )
{
char *str = NULL ;
char *old_json = NULL , *new_json = NULL ;
va_list arg_ptr ;
va_start(arg_ptr , format );
vasprintf (&str , format , arg_ptr );
// save old json
asprintf (&old_json ,"%s", (*json == NULL ?"" : *json ));
// calloc new json memory
new_json = (char *)calloc(strlen(old_json ) + strlen(str ) + 1, sizeof(char));
strcat(new_json , old_json );
strcat(new_json , str );
if (*json ) free(*json );
*json = new_json ;
free(old_json );
free(str );
return 0;
}
int main (int argc , char *argv [])
{
char *json = NULL ;
/*
str_append(&json,"name: %d, %d, %d", 1, 2, 3);
str_append(&json,"sex: %s","male");
str_append(&json,"end");
str_append(&json,"");
str_append(&json,"{"ret":true}");
*/
int i ;
for (i = 0; i < 100; i ++) {
str_append (&json ,"id-%d", i );
}
printf("%s
", json );
if (json ) free(json );
return 0;
} |
使用strcat(buffer," Your new string...here")作为选项。
-
这复制了一个更完整的现有答案stackoverflow.com/a/40316229/874188
关于什么:
1 2 3 4 5 6 7 8 9
| char s [100] ="";
sprintf(s ,"%s%s", s ,"s1");
sprintf(s ,"%s%s", s ,"s2");
sprintf(s ,"%s%s", s ,"s3");
printf("%s", s ); |
但是要考虑可能的缓冲区卵流!
-
它没有附加...
-
将s用作要读取的源以及要写入的目标可能不是安全的举动。我希望它调用strcpy(s, s)。