104

I am facing a serious issue with sprintf.

Suppose my code snippet is:

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

Some hundred sprints....

If I do like this, it's getting overwritten.

How can I avoid overwriting using sprintf? If I give a printf at the end I want to see all the lines.

1
  • 20
    I shall not use sprintf but snprintf, I shall not use printf( str ) but printf( "%s" , str ) Commented Apr 20, 2010 at 12:59

16 Answers 16

154

You need:

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

and of course you need your buffer to be big enough.

Sign up to request clarification or add additional context in comments.

5 Comments

+1 although I like Aeth's solution a bit better, it seems a bit more efficient than recalculating the string length every time.
A trick I've seen along these lines is to #define eos(s) ((s)+strlen(s)), or declare a function if you prefer. Then you can use sprintf(eos(Buffer), "Stuff")
Simpler still, you can just use sprintf(strchr(s, '\0'), "...").
What is the + strlen(Buffer) appending to the actual Buffer for?
This is pointer arithmetic. It's like adding the current length of the string to the start address of the 'Buffer'. This operation is not safe for mbs and unicode strings. Like for instance, getting length of unicode string "Hello" would return 5, but actually Buffer + 5 * sizeof(wchar_t) is required in this case
87
int length = 0;
length += sprintf(Buffer+length, "Hello World");
length += sprintf(Buffer+length, "Good Morning");
length += sprintf(Buffer+length, "Good Afternoon");

Here is a version with some resistance to errors. It is useful if you do not care when errors happen so long as you can continue along your merry way when they do.

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

4 Comments

But what happens if sprintf experiences a conversion failure?
Then you have bad things that happen. I omitted the error checking for the sake of brevity.
+1 - Additional error checking should be an exercise for the reader anyway. After all, its their code :)
I guess make sense to report error and errono in case of negative result of sprintf.
39

For safety (buffer overflow) I recommend to use 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");

1 Comment

The second argument of snprintf is unsigned (size_t), it means that if length > MAX_BUF, then MAX_BUF-length will underflow and snprintf will happily write outside of the buffer creating a buffer overflow. Note that the return of snprintf is equal to the number of bytes which would have been written if enough space had been available and NOT the number of bytes really written.
18

A snprintfcat() wrapper for 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;
}

Comments

13

Use the return value of sprintf()

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

2 Comments

This is the best solution, no need to strlen
Note that you also need to save the starting address of the buffer for further reference.
6

I find the following method works nicely.

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

2 Comments

[...] around strlen? Should it be (...)?
too much python :D
5

Why do you want to use sprintf for string concatenation when there are methods intended specifically for what you need such as strcat and strncat?

1 Comment

It could be that the example was the trivial case only strings are being appended. The problem can be extended to include cases where you are appending other types of formatted data for which strcat would not apply.
5

Small full code example

Using flat plain stdio standard library only

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

OUTPUT: We Love Coding

Comments

4

I think you are looking for 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;
}

If dynamic storage is more suitable for you use-case you could follow Liam's excellent suggestion about using 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;
}

3 Comments

This is just what I was looking for. At the suggestion of man fmemopen, I found open_memstream to be a little more suitable for my application. See the GNU manual for an example.
@Liam awesome, thanks for the tip about open_memstream. I added an example for that as well.
Fantastic, except neither fmemopen nor open_memstream are available on Windows.
3

Are you simply appending string literals? Or are you going to be appending various data types (ints, floats, etc.)?

It might be easier to abstract this out into its own function (the following assumes 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;
}

And you would use it like so:

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

etc.

The function returns the value from vsprintf, which in most implementations is the number of bytes written to the destination. There are a few holes in this implementation, but it should give you some ideas.

2 Comments

Why don't you put sizeof target inside the function? Why do you need it in parameters?
@hellomyfriends: Because in the function, target is a pointer to char, not an array of char, and sizeof will only return the size of the pointer, not the size of the array that it points to.
2

Use 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. 

Comments

1

You can use the simple line shown below to append strings in one buffer:

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

Comments

1
char string1[] = "test";
char string2[] = "string";
int len = sizeof(string1) + sizeof(string2);
char totalString[len];
sprintf(totalString, "%s%s",string1,string2);

Comments

0

I write a function support dynamic variable string append, like PHP str append: str . str . ... etc.

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

Comments

-2

Using strcat(buffer,"Your new string...here"), as an option.

1 Comment

This duplicates a more complete existing answer stackoverflow.com/a/40316229/874188
-4

What about:

char s[100] = "";

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

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

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

printf("%s", s);

But take into account possible buffer ovewflows!

1 Comment

It is probably not a safe move to be using s as a source to be read from as well as a destination to be written to. I would liken it to calling strcpy(s, s).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.