2010-04-20 103 views
46

我正面臨sprintf的嚴重問題。如何使用sprintf追加字符串?

假設我的代碼片斷是:

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

幾百衝刺....

如果我做這樣的,它覆蓋掉了。

如何避免使用sprintf進行覆蓋。如果我在最後給出一個printf,我想看看所有的行。

+9

我不會用sprintf但snprintf的, 我不會用printf(STR),但輸出( 「%s」 時,STR) – 2010-04-20 12:59:03

回答

75

您需要:

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

,當然你需要你的緩衝區足夠大。

+0

緩衝的大型足夠了...我會嘗試。 .. – user46646 2010-04-20 10:41:48

+2

+1雖然我喜歡Aeth的解決方案稍微好一點,但似乎比重新計算每次字符串長度更有效。 – extraneon 2010-04-20 10:47:13

+5

我沿着這些線看到的一個技巧是'#define eos(s)((s)+ strlen(s))',或者如果您願意,可以聲明一個函數。然後你可以使用sprintf(eos(Buffer),Stuff)' – msandiford 2010-04-20 10:47:26

55
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")); 
+0

但是如果sprintf遇到轉換失敗會發生什麼情況? – 2010-04-20 10:52:19

+2

然後你有壞事發生。爲簡潔起見,我省略了錯誤檢查。 – 2010-04-20 11:21:57

+0

+1 - 無論如何,額外的錯誤檢查應該是讀者的練習。畢竟,它的_their_代碼:) – 2010-04-20 12:28:50

7

你爲什麼要使用sprintf字符串連接時有方法有什麼需要,如strcatstrncat專意?

+11

可能是這個例子是一個微不足道的情況,只有字符串被追加。這個問題可以擴展爲包含你添加其他類型的格式化數據的情況,而這些格式化數據不適用'strcat'。 – 2010-04-20 11:41:40

-4

什麼:

char s[100] = ""; 

sprintf(s, "%s%s", s, "s1"); 

sprintf(s, "%s%s", s, "s2"); 

sprintf(s, "%s%s", s, "s3"); 

printf("%s", s); 

但考慮到可能的緩衝區ovewflows!

+0

它沒有附加.... – user46646 2010-04-20 10:53:46

+3

這可能不是一個安全的舉動,使用's'作爲源讀取以及要寫入的目的地。我將它比作調用'strcpy(s,s)'。 – 2010-04-20 11:37:58

26

爲了安全(緩衝區溢出),我建議使用的snprintf()

 
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"); 
+4

snprintf的第二個參數是unsigned(size_t),這意味着如果長度大於MAX_BUF,則MAX_BUF長度將下溢,並且snprintf將愉快地寫入緩衝區之外,從而創建緩衝區溢出。請注意,如果有足夠的空間可用,snprintf的返回值等於寫入的字節數,而不是真正寫入的字節數。 – 2016-12-14 17:18:23

3

你只需追加字符串文字?或者你會追加各種數據類型(整數,浮點數等)?

這可能是更容易抽象了這一點到其自身的功能(以下假定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的值,在大多數實現中該值是寫入目標的字節數。在這個實現中有一些漏洞,但它應該給你一些想法。

+0

爲什麼不把sizeof target放在函數內部?你爲什麼需要參數? – 2014-07-25 08:58:33

+0

@hellomyfriends:因爲在函數中,'target'是一個指向'char'的指針,而不是'char'的數組,而'sizeof'只會返回指針的大小,而不是它指向的數組的大小至。 – 2014-07-25 13:54:40

12

一個snprintfcat()包裝爲snprintf()

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; 
} 
4

我發現下面的方法工作得很好。

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

''''在'strlen'周圍?它應該是「(...)」嗎? – CodyChan 2015-07-08 02:42:48

+0

太多蟒蛇:D – Niko 2017-07-25 07:32:56

1

您可以使用如下所示追加串在一個緩衝區中的簡單行:

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

我認爲你正在尋找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; 
} 
+1

這正是我正在尋找的。在man fmemopen的建議下,我發現open_memstream更適合我的應用程序。有關示例,請參見[GNU手冊](https://www.gnu.org/software/libc/manual/html_node/String-Streams.html)。 – Liam 2017-02-01 03:59:42

+0

@Liam真棒,感謝關於'open_memstream'的提示。我也爲此添加了一個例子。 – wkz 2017-02-01 17:22:36

+0

很棒,除了'fmemopen'和'open_memstream'都不可用於Windows。 – 7vujy0f0hy 2017-10-07 13:10:18

3

使用sprintf()

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

使用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. 
-2

使用strcatbufferYour new string...here」)的返回值,作爲一個選項。

+0

這複製了一個更完整的現有答案http://stackoverflow.com/a/40316229/874188 – tripleee 2017-02-17 07:10:39

0

我寫了一個函數支持動態變量字符串append,就像PHP str append:str一樣。 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; 
}