Printing a variable number of arguments to a format string

Gabriel Saul :

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.

Mohith Reddy :

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

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related