如何使用 sprintf 附加字符串?

Posted

技术标签:

【中文标题】如何使用 sprintf 附加字符串?【英文标题】:How to append strings using sprintf? 【发布时间】:2011-02-10 02:03:19 【问题描述】:

我正面临sprintf 的严重问题。

假设我的代码 sn-p 是:

sprintf(Buffer,"Hello World");
sprintf(Buffer,"Good Morning");
sprintf(Buffer,"Good Afternoon");
.
.
.

几百个冲刺....

如果我这样做,它就会被覆盖。

如何避免使用sprintf 覆盖?如果我在最后给出printf,我想看到所有的行。

【问题讨论】:

我不会使用 sprintf 而使用 snprintf,我不会使用 printf( str ) 而使用 printf( "%s" , str ) 【参考方案1】:

你需要:

sprintf(Buffer,"Hello World");
sprintf(Buffer + strlen(Buffer),"Good Morning");
sprintf(Buffer + strlen(Buffer),"Good Afternoon");

当然你需要你的缓冲区足够大。

【讨论】:

+1 虽然我更喜欢 Aeth 的解决方案,但它似乎比每次都重新计算字符串长度更有效。 我在这些方面看到的一个技巧是#define eos(s) ((s)+strlen(s)),或者如果您愿意,可以声明一个函数。然后你可以使用sprintf(eos(Buffer), "Stuff") 更简单,你可以使用sprintf(strchr(s, '\0'), "...") 附加到实际 Buffer 的 + strlen(Buffer) 是做什么用的? 这是指针运算。这就像将字符串的当前长度添加到“缓冲区”的起始地址。此操作对 mbs 和 unicode 字符串不安全。例如,获取 unicode 字符串“Hello”的长度将返回 5,但实际上在这种情况下需要 Buffer + 5 * sizeof(wchar_t)【参考方案2】:
int length = 0;
length += sprintf(Buffer+length, "Hello World");
length += sprintf(Buffer+length, "Good Morning");
length += sprintf(Buffer+length, "Good Afternoon");

这是一个对错误有一定抵抗力的版本。如果您不在乎何时发生错误,只要您可以在错误发生时继续愉快地前进,这很有用。

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 的结果为负的情况下报告错误和 errono 是有意义的。【参考方案3】:

为了安全(缓冲区溢出)我建议使用 snprintf()

常量 int MAX_BUF = 1000; char* 缓冲区 = malloc(MAX_BUF); 整数长度 = 0; 长度+= snprintf(缓冲区+长度,MAX_BUF-长度,“Hello World”); length += snprintf(Buffer+length, MAX_BUF-length, "早安"); length += snprintf(Buffer+length, MAX_BUF-length, "下午好");

【讨论】:

snprintf 的第二个参数是无符号的 (size_t),这意味着如果 length > MAX_BUF,那么 MAX_BUF-length 将下溢,并且 snprintf 将愉快地写入缓冲区之外创建缓冲区溢出。请注意,snprintf 的返回值等于如果有足够的空间可用时将写入的字节数,而不是实际写入的字节数。【参考方案4】:

snprintf()snprintfcat() 包装器:

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;

【讨论】:

【参考方案5】:

使用sprintf()的返回值

Buffer += sprintf(Buffer,"Hello World");
Buffer += sprintf(Buffer,"Good Morning");
Buffer += sprintf(Buffer,"Good Afternoon");

【讨论】:

这是最好的解决方案,不用s​​trlen 注意,还需要保存缓冲区的起始地址以供进一步参考。【参考方案6】:

当有专门针对您需要的方法(例如strcatstrncat)时,为什么要使用sprintf 进行字符串连接?

【讨论】:

可能是该示例是简单的情况,仅附加了字符串。该问题可以扩展到包括您正在附加其他类型的格式化数据的情况,strcat 不适用。【参考方案7】:

我想你在找fmemopen(3):

#include <assert.h>
#include <stdio.h>

int main(void)

    char buf[128] =  0 ;
    FILE *fp = fmemopen(buf, sizeof(buf), "w");

    assert(fp);

    fprintf(fp, "Hello World!\n");
    fprintf(fp, "%s also work, of course.\n", "Format specifiers");
    fclose(fp);

    puts(buf);
    return 0;

如果动态存储更适合您的用例,您可以遵循 Liam 关于使用 open_memstream(3) 的出色建议:

#include <assert.h>
#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!\n");
    fprintf(fp, "%s also work, of course.\n", "Format specifiers");
    fclose(fp);

    puts(buf);
    free(buf);
    return 0;

【讨论】:

这正是我想要的。在 man fmemopen 的建议下,我发现 open_memstream 更适合我的应用程序。有关示例,请参见 GNU manual。 @Liam 太棒了,感谢有关open_memstream 的提示。我也为此添加了一个示例。 太棒了,除了 fmemopenopen_memstream 在 Windows 上都不可用。【参考方案8】:

您只是在附加字符串文字吗?还是要附加各种数据类型(整数、浮点数等)?

将其抽象为自己的函数可能更容易(以下假设 C99):

#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;

你会像这样使用它:

char target[100] = 0;
...
appendToStr(target, sizeof target, "%s %d %f\n", "This is a test", 42, 3.14159);
appendToStr(target, sizeof target, "blah blah blah");

等等

该函数返回来自vsprintf 的值,在大多数实现中是写入目标的字节数。这个实现有一些漏洞,但它应该给你一些想法。

【讨论】:

为什么不把 sizeof 目标放在函数里面呢?为什么在参数中需要它? @hellomyfriends:因为在函数中,target是指向char的指针,而不是char的数组,而sizeof只会返回指针的大小,而不是它指向的数组的大小。【参考方案9】:

我发现下面的方法效果很好。

sprintf(Buffer,"Hello World");
sprintf(&Buffer[strlen(Buffer)],"Good Morning");
sprintf(&Buffer[strlen(Buffer)],"Good Afternoon");

【讨论】:

[...]strlen 附近?应该是(...) python 太多 :D【参考方案10】:

完整的小代码示例

仅使用纯 stdio 标准库

#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);
    

输出:我们喜欢编码

【讨论】:

【参考方案11】:

您可以使用下面显示的简单行将字符串附加到一个缓冲区中:

sprintf(Buffer,"%s %s %s","Hello World","Good Morning","Good Afternoon");

【讨论】:

【参考方案12】:

使用 strcat http://www.cplusplus.com/reference/cstring/strcat/

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. 

【讨论】:

【参考方案13】:

我写了一个支持动态变量字符串追加的函数,比如 php str append: str 。海峡...等等。

#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\n", json);

    if (json) free(json);

    return 0;

【讨论】:

【参考方案14】:
char string1[] = "test";
char string2[] = "string";
int len = sizeof(string1) + sizeof(string2);
char totalString[len];
sprintf(totalString, "%s%s",string1,string2);

【讨论】:

【参考方案15】:

使用strcat(buffer,"Your new string...here") 作为选项。

【讨论】:

这复制了一个更完整的现有答案***.com/a/40316229/874188【参考方案16】:

怎么样:

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)

以上是关于如何使用 sprintf 附加字符串?的主要内容,如果未能解决你的问题,请参考以下文章

如何解压字符串 - 使用 sprintf 创建 - 在 Perl 中具有固定宽度

使用system(),fgets和sprintf在C中将文本附加到文件的问题

C语言 sprintf函数,如何生成不规则的随机字符串?

如何使用sprintf格式化R中数据框的打印?

关于 sprintf 函数如何在 C 中工作的困惑

如何在sprintf函数中输出百分号等特殊符号