How to append strings using sprintf? - c

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.

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.

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

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

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

Use the return value of sprintf()
Buffer += sprintf(Buffer,"Hello World");
Buffer += sprintf(Buffer,"Good Morning");
Buffer += sprintf(Buffer,"Good Afternoon");

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?

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

I find the following method works nicely.
sprintf(Buffer,"Hello World");
sprintf(&Buffer[strlen(Buffer)],"Good Morning");
sprintf(&Buffer[strlen(Buffer)],"Good Afternoon");

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

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.

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.

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

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

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

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

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!

Related

Writing concise code in C

strcat(msg, ": ");
strcat(msg, buf);
Is there a way to do this in one line? I want to make my code cleaner and reduce clutter
Instead of doing multiple concatenations, try creating a formatted string. Try something like this:
#include <stdio.h>
#include <string.h>
int main()
{
char *before_colon = "Text before colon";
char *after_colon = "Text after colon";
// Make a string that is the size of both formatted strings, plus a
// character for the space, colon, and null character.
char final_string[strlen(before_colon) + strlen(after_colon) + 3];
// This works just like any other C formatted function (i.e printf, scanf)
sprintf(final_string, "%s: %s", before_colon, after_colon);
printf("%s\n", final_string);
}
output:
Text before colon: Text after colon
Here's a modified code of Charlie Sale with its own function to count characters in the string. Thus, StrLen is called in array declaration.
#include <stdio.h>
#include <string.h>
int StrLen(char* PtrFirstChar)
{
int n = 0;
while(*(PtrFirstChar++)) // will evaluate to FALSE when '\0' reached
n++;
return n;
}
int main()
{
char *before_colon = "Text before colon";
char *after_colon = "Text after colon";
// Make a string that is the size of both formatted strings, plus a
// character for the space, colon, and null character.
char final_string[StrLen(before_colon) + StrLen(after_colon) + 3];
// This works just like any other C formatted function (i.e printf, scanf)
sprintf(final_string, "%s: %s", before_colon, after_colon);
printf("%s\n", final_string);
}
You could write your own variant of strcat!
I'm going to use strncat as a basis because strcat is a really bad idea:
#include <stddef.h> /* for size_t */
#include <stdarg.h> /* for va_* */
char *
mstrncat(char *d, size_t maxlen, ...)
{
va_list ap;
va_start(ap, maxlen);
char *ret = d;
/* Fast-forward */
for (; *d && maxlen; ++d, --maxlen);
/* Reserve a space for the terminator */
if (maxlen)
--maxlen;
const char *p;
/* Concatenate parameters one by one */
while (maxlen && (p = va_arg(ap, const char *))) {
while (*p && maxlen--)
*d++ = *p++;
}
/* Terminate the string */
*d = 0;
va_end(ap);
return ret;
}
You can use it like this:
#include <stdio.h>
int
main()
{
char test[128]="test";
mstrncat(test, sizeof(test), "1", "two", "3", NULL);
puts(test);
return 0;
}

How to use format specifiers with strdup?

How to use format specifier with strdup?
I am trying to do something like this.
char arr[10] = "acbde";
char* s = strdup("Hello..I am %s", arr);
But this does not work.
You can't use the function strdup for this. Instead you should use snprintf. Here is a basic example on how you should do it.
char *arr = "acbde";
char str[100]; // set this to your maximum length
snprintf(str, sizeof(str), "Hello..I am %s", arr);
Here is a more complete example on how it can be used.
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
int main(void) {
char *arr = "acbde";
char *str;
int length = snprintf(NULL, 0, "Hello..I am %s", arr);
assert(length >= 0); // TODO add proper error handling
str = malloc(sizeof(char) * (length + 1));
snprintf(str, length+1, "Hello..I am %s", arr);
printf("%s [%d]\n", str, length);
free(str);
}
Try use g_strdup_printf().
But should understand - you must free memory after using this function.

Similar to vsprintf, implemented to use dynamically created array of strings instead of a va_list

String interpolation with n-variables commonly involve variadic functions. In C, is there an alternative similar to vsprintf that can take a dynamically created array of strings instead of a va_list?
int foo (char *s, const char *format, char **strs );
No, there is no such function in the C standard library.
Given that your format string will be quite limited (only supporting %s and perhaps width modifiers), you might be able to implement this yourself by parsing the format string.
There is not, but you can write your own function, e.g.:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
extern char *strdup(const char *);
int foo(char *str, const char *fmt, char **arr)
{
int cnt = 0, len = 0, bit = 0;
char *buf, *ptr, *tmp;
/* fmt must be writable */
buf = ptr = strdup(fmt);
if (buf == NULL) {
perror("strdup");
exit(EXIT_FAILURE);
}
while ((tmp = ptr)) {
while ((ptr = strchr(ptr, '%'))) {
/* Support for %% */
if (ptr[1] == '%') {
ptr += 2;
continue;
}
/* Skip first % */
if (bit ^= 1) {
ptr += 1;
continue;
} else break;
}
if (ptr) *ptr = '\0'; /* Tokenize */
len += sprintf(str + len, tmp, arr[cnt++]);
if (ptr) *ptr = '%'; /* Untokenize */
}
free(buf);
return len;
}
int main(void)
{
char *arr[] = {"one", "two", "three"};
char str[100];
foo(str, "%s, %s, %s", arr);
printf("%s\n", str);
return 0;
}

How do I concatenate two strings in C?

How do I add two strings?
I tried name = "derp" + "herp";, but I got an error:
Expression must have integral or enum type
C does not have the support for strings that some other languages have. A string in C is just a pointer to an array of char that is terminated by the first null character. There is no string concatenation operator in C.
Use strcat to concatenate two strings. You could use the following function to do it:
#include <stdlib.h>
#include <string.h>
char* concat(const char *s1, const char *s2)
{
char *result = malloc(strlen(s1) + strlen(s2) + 1); // +1 for the null-terminator
// in real code you would check for errors in malloc here
strcpy(result, s1);
strcat(result, s2);
return result;
}
This is not the fastest way to do this, but you shouldn't be worrying about that now. Note that the function returns a block of heap allocated memory to the caller and passes on ownership of that memory. It is the responsibility of the caller to free the memory when it is no longer needed.
Call the function like this:
char* s = concat("derp", "herp");
// do things with s
free(s); // deallocate the string
If you did happen to be bothered by performance then you would want to avoid repeatedly scanning the input buffers looking for the null-terminator.
char* concat(const char *s1, const char *s2)
{
const size_t len1 = strlen(s1);
const size_t len2 = strlen(s2);
char *result = malloc(len1 + len2 + 1); // +1 for the null-terminator
// in real code you would check for errors in malloc here
memcpy(result, s1, len1);
memcpy(result + len1, s2, len2 + 1); // +1 to copy the null-terminator
return result;
}
If you are planning to do a lot of work with strings then you may be better off using a different language that has first class support for strings.
#include <stdio.h>
int main(){
char name[] = "derp" "herp";
printf("\"%s\"\n", name);//"derpherp"
return 0;
}
David Heffernan explained the issue in his answer, and I wrote the improved code. See below.
A generic function
We can write a useful variadic function to concatenate any number of strings:
#include <stdlib.h> // calloc
#include <stdarg.h> // va_*
#include <string.h> // strlen, strcpy
char* concat(int count, ...)
{
va_list ap;
int i;
// Find required length to store merged string
int len = 1; // room for NULL
va_start(ap, count);
for(i=0 ; i<count ; i++)
len += strlen(va_arg(ap, char*));
va_end(ap);
// Allocate memory to concat strings
char *merged = calloc(sizeof(char),len);
int null_pos = 0;
// Actually concatenate strings
va_start(ap, count);
for(i=0 ; i<count ; i++)
{
char *s = va_arg(ap, char*);
strcpy(merged+null_pos, s);
null_pos += strlen(s);
}
va_end(ap);
return merged;
}
Usage
#include <stdio.h> // printf
void println(char *line)
{
printf("%s\n", line);
}
int main(int argc, char* argv[])
{
char *str;
str = concat(0); println(str); free(str);
str = concat(1,"a"); println(str); free(str);
str = concat(2,"a","b"); println(str); free(str);
str = concat(3,"a","b","c"); println(str); free(str);
return 0;
}
Output:
// Empty line
a
ab
abc
Clean-up
Note that you should free up the allocated memory when it becomes unneeded to avoid memory leaks:
char *str = concat(2,"a","b");
println(str);
free(str);
I'll assume you need it for one-off things. I'll assume you're a PC developer.
Use the Stack, Luke. Use it everywhere. Don't use malloc / free for small allocations, ever.
#include <string.h>
#include <stdio.h>
#define STR_SIZE 10000
int main()
{
char s1[] = "oppa";
char s2[] = "gangnam";
char s3[] = "style";
{
char result[STR_SIZE] = {0};
snprintf(result, sizeof(result), "%s %s %s", s1, s2, s3);
printf("%s\n", result);
}
}
If 10 KB per string won't be enough, add a zero to the size and don't bother, - they'll release their stack memory at the end of the scopes anyway.
You should use strcat, or better, strncat. Google it (the keyword is "concatenating").
You cannot add string literals like that in C. You have to create a buffer of size of string literal one + string literal two + a byte for null termination character and copy the corresponding literals to that buffer and also make sure that it is null terminated. Or you can use library functions like strcat.
Concatenate Strings
Concatenating any two strings in C can be done in atleast 3 ways :-
1) By copying string 2 to the end of string 1
#include <stdio.h>
#include <string.h>
#define MAX 100
int main()
{
char str1[MAX],str2[MAX];
int i,j=0;
printf("Input string 1: ");
gets(str1);
printf("\nInput string 2: ");
gets(str2);
for(i=strlen(str1);str2[j]!='\0';i++) //Copying string 2 to the end of string 1
{
str1[i]=str2[j];
j++;
}
str1[i]='\0';
printf("\nConcatenated string: ");
puts(str1);
return 0;
}
2) By copying string 1 and string 2 to string 3
#include <stdio.h>
#include <string.h>
#define MAX 100
int main()
{
char str1[MAX],str2[MAX],str3[MAX];
int i,j=0,count=0;
printf("Input string 1: ");
gets(str1);
printf("\nInput string 2: ");
gets(str2);
for(i=0;str1[i]!='\0';i++) //Copying string 1 to string 3
{
str3[i]=str1[i];
count++;
}
for(i=count;str2[j]!='\0';i++) //Copying string 2 to the end of string 3
{
str3[i]=str2[j];
j++;
}
str3[i]='\0';
printf("\nConcatenated string : ");
puts(str3);
return 0;
}
3) By using strcat() function
#include <stdio.h>
#include <string.h>
#define MAX 100
int main()
{
char str1[MAX],str2[MAX];
printf("Input string 1: ");
gets(str1);
printf("\nInput string 2: ");
gets(str2);
strcat(str1,str2); //strcat() function
printf("\nConcatenated string : ");
puts(str1);
return 0;
}
Without GNU extension:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
const char str1[] = "First";
const char str2[] = "Second";
char *res;
res = malloc(strlen(str1) + strlen(str2) + 1);
if (!res) {
fprintf(stderr, "malloc() failed: insufficient memory!\n");
return EXIT_FAILURE;
}
strcpy(res, str1);
strcat(res, str2);
printf("Result: '%s'\n", res);
free(res);
return EXIT_SUCCESS;
}
Alternatively with GNU extension:
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
const char str1[] = "First";
const char str2[] = "Second";
char *res;
if (-1 == asprintf(&res, "%s%s", str1, str2)) {
fprintf(stderr, "asprintf() failed: insufficient memory!\n");
return EXIT_FAILURE;
}
printf("Result: '%s'\n", res);
free(res);
return EXIT_SUCCESS;
}
See malloc, free and asprintf for more details.
#include <string.h>
#include <stdio.h>
int main()
{
int a,l;
char str[50],str1[50],str3[100];
printf("\nEnter a string: ");
scanf("%s",str);
str3[0]='\0';
printf("\nEnter the string which you want to concat with string one: ");
scanf("%s",str1);
strcat(str3,str);
strcat(str3,str1);
printf("\nThe string is %s\n",str3);
}
using memcpy
char *str1="hello";
char *str2=" world";
char *str3;
str3=(char *) malloc (11 *sizeof(char));
memcpy(str3,str1,5);
memcpy(str3+strlen(str1),str2,6);
printf("%s + %s = %s",str1,str2,str3);
free(str3);
my here use asprintf
sample code:
char* fileTypeToStr(mode_t mode) {
char * fileStrBuf = NULL;
asprintf(&fileStrBuf, "%s", "");
bool isFifo = (bool)S_ISFIFO(mode);
if (isFifo){
asprintf(&fileStrBuf, "%s %s,", fileStrBuf, "FIFO");
}
...
bool isSocket = (bool)S_ISSOCK(mode);
if (isSocket){
asprintf(&fileStrBuf, "%s %s,", fileStrBuf, "Socket");
}
return fileStrBuf;
}
In C, you don't really have strings, as a generic first-class object. You have to manage them as arrays of characters, which mean that you have to determine how you would like to manage your arrays. One way is to normal variables, e.g. placed on the stack. Another way is to allocate them dynamically using malloc.
Once you have that sorted, you can copy the content of one array to another, to concatenate two strings using strcpy or strcat.
Having said that, C do have the concept of "string literals", which are strings known at compile time. When used, they will be a character array placed in read-only memory. It is, however, possible to concatenate two string literals by writing them next to each other, as in "foo" "bar", which will create the string literal "foobar".

C string append

I want to append two strings. I used the following command:
new_str = strcat(str1, str2);
This command changes the value of str1. I want new_str to be the concatanation of str1 and str2 and at the same time str1 is not to be changed.
You need to allocate new space as well. Consider this code fragment:
char * new_str ;
if((new_str = malloc(strlen(str1)+strlen(str2)+1)) != NULL){
new_str[0] = '\0'; // ensures the memory is an empty string
strcat(new_str,str1);
strcat(new_str,str2);
} else {
fprintf(STDERR,"malloc failed!\n");
// exit?
}
You might want to consider strnlen(3) which is slightly safer.
Updated, see above. In some versions of the C runtime, the memory returned by malloc isn't initialized to 0. Setting the first byte of new_str to zero ensures that it looks like an empty string to strcat.
do the following:
strcat(new_str,str1);
strcat(new_str,str2);
Consider using the great but unknown open_memstream() function.
FILE *open_memstream(char **ptr, size_t *sizeloc);
Example of usage :
// open the stream
FILE *stream;
char *buf;
size_t len;
stream = open_memstream(&buf, &len);
// write what you want with fprintf() into the stream
fprintf(stream, "Hello");
fprintf(stream, " ");
fprintf(stream, "%s\n", "world");
// close the stream, the buffer is allocated and the size is set !
fclose(stream);
printf ("the result is '%s' (%d characters)\n", buf, len);
free(buf);
If you don't know in advance the length of what you want to append, this is convenient and safer than managing buffers yourself.
You'll have to strncpy str1 into new_string first then.
You could use asprintf to concatenate both into a new string:
char *new_str;
asprintf(&new_str,"%s%s",str1,str2);
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 < 10; i++) {
str_append(&json, "id-%d", i);
}
printf("%s\n", json);
if (json) free(json);
return 0;
}
I needed to append substrings to create an ssh command, I solved with sprintf (Visual Studio 2013)
char gStrSshCommand[SSH_COMMAND_MAX_LEN]; // declare ssh command string
strcpy(gStrSshCommand, ""); // empty string
void appendSshCommand(const char *substring) // append substring
{
sprintf(gStrSshCommand, "%s %s", gStrSshCommand, substring);
}
strcpy(str1+strlen(str1), str2);
man page of strcat says that arg1 and arg2 are appended to arg1.. and returns the pointer of s1. If you dont want disturb str1,str2 then you have write your own function.
char * my_strcat(const char * str1, const char * str2)
{
char * ret = malloc(strlen(str1)+strlen(str2));
if(ret!=NULL)
{
sprintf(ret, "%s%s", str1, str2);
return ret;
}
return NULL;
}
Hope this solves your purpose
You can try something like this:
strncpy(new_str, str1, strlen(str1));
strcat(new_str, str2);
More info on strncpy: http://www.cplusplus.com/reference/clibrary/cstring/strncpy/

Resources