In C (gcc, ubuntu 22.04) I’m trying to create formatted string using format string and … arguments, like a sprintf, but it would return the formatted string, e.g. char *s = myformat("Hello %s", name) but for some reason it is not working, as if the name was empty.
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
char* myformat(const char *fmt, ...) {
va_list args;
va_start(args, fmt);
size_t len = snprintf(NULL, 0, fmt, args);
if (len > 0) {
char *s = (char*)malloc(len + 1);
if (s) {
printf("len=%ld\n", len); // prints len=11 which is "hello zzz"+1
snprintf(s, len + 1, fmt, args);
} else {
fprintf(stderr, "error: create_formated_string() failed to allocate %ld chars\n", len + 1);
exit(1);
}
return s;
}
va_end(args);
return NULL;
}
int main(void) {
char *name = "John";
char *s = myformat("Hello %s zzz", name);
printf("s=%s\n", s);
free(s);
return 0;
}
It will print
s=Hello zzz
Instead of
s=Hello John zzz
I’m compiling using: "gcc test.c" on Ubuntu 22.04.
I tried using vsnprintf but it now prints random characters instead of name:
char* myformat(const char *fmt, ...) {
va_list args;
va_start(args, fmt);
size_t len = vsnprintf(NULL, 0, fmt, args);
char *s;
if (len > 0) {
s = (char*)malloc(len + 1);
if (s) {
printf("len=%ld\n", len); // prints len=11 which is "hello zzz"+1
vsnprintf(s, len + 1, fmt, args);
} else {
fprintf(stderr, "error: create_formated_string() failed to allocate %ld chars\n", len + 1);
exit(1);
}
}
va_end(args);
return s;
}
int main(void) {
char *name = "John";
char *s = myformat("Hello %s zzz", name);
printf("s=%s\n", s);
free(s);
return 0;
}
>Solution :
It does not work like this. You need to use special functions which take va_list argument.
int vsnprintf (char * s, size_t n, const char * format, va_list arg );
But it will not work without some modifications. The fist call will modify args
and you need to copy it.
char* myformat(const char *fmt, ...) {
va_list args,copy;
va_start(args, fmt);
va_copy(copy, args);
size_t len = vsnprintf(NULL, 0, fmt, args);
if (len > 0) {
char *s = malloc(len + 1);
if (s) {
printf("len=%ld\n", len); // prints len=11 which is "hello zzz"+1
vsnprintf(s, len + 1, fmt, copy);
} else {
fprintf(stderr, "error: create_formated_string() failed to allocate %zu chars\n", len + 1);
exit(1);
}
return s;
}
va_end(args);
va_end(copy);
return NULL;
}
https://godbolt.org/z/qqsz89dvz
Also %ld
is not correct to print size_t
parameter. You need to use %zu
format