Given a format string, a counter variable for the number of specifiers and an array of the strings to be inputted, how could this be printed?
Here's an example:
char *format_str = "str(%s)ing(%s)";
int count = 2;
char **specs = { [0] = "rts", [1] = "gni" };
So, the list of strings aligns respectively with the ordering of specifiers. When printed, the end result would be:
"str(rts)ing(gni)"
Could a function be written to print such a string with any format string & any number of specifiers & respective arguments? I have tried to do this using strtok()
, vsprintf
, snprintf
etc, but I still cannot get it quite right.
EDIT: To clarify, format_str
contains count
number of specifiers and the array specs
contains count
number of strings. The proposed function would therefore should print count
number of strings into format_str
.
As others said there is no direct way of doing that. You can build your own function which dumps the values of strings at the correct format specifiers. Below function makes a temporary format string for each %s
and appends it to the earlier build string using snprintf()
.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXBUF 4096
char *strmaker(char* format, int num_args, char** strings)
{
char* prnt = calloc(sizeof(char), MAXBUF);
int prnt_ct = 0;
char* tmp_fmt = malloc(strlen(format) + 1); // Prepare for the worst case (format == tmp_fmt).
int fmt_ct = 0;
/* Append the strings to the prnt buffer */
for (int i = 0; i < num_args; i++) {
char* s_loc = strstr(format + fmt_ct, "%s"); // Search the format-string for string specifier (%s)
if (s_loc == NULL)
return prnt;
int tmp_fmt_len = (int) (s_loc + 2 - format - fmt_ct); // +2 for %s
strncpy(tmp_fmt, format + fmt_ct, tmp_fmt_len); // Make tmp_fmt
tmp_fmt[tmp_fmt_len] = '\0';
fmt_ct = fmt_ct + tmp_fmt_len;
int p_return = snprintf(prnt + prnt_ct, MAXBUF - prnt_ct, tmp_fmt, strings[i]); // If no error, return the number characters printed excluding nul (man page)
if (p_return >= MAXBUF - prnt_ct) // If buffer overflows (man page)
return prnt;
prnt_ct = prnt_ct + p_return; // Update the index location.
}
return prnt;
}
int main(int argc, char *argv[]) // Pass format and arguments
{
if (argc <= 1)
return -1;
char *s = strmaker(argv[1], argc - 2, argv + 2);
printf("%s\n", s);
free(s);
return 0;
}
Terminal Session:
$ ./a.out '%s %s %s' 1 2 3
1 2 3
$ ./a.out 'one %s two %s three %s' 1 2 3
one 1 two 2 three 3
$ ./a.out 'one %s two %s three' 1 2 3
one 1 two 2
$ ./a.out 'one %s two %s three %s' 1 2
one 1 two 2