Thread: multiply sections of printf format specifier?

  1. #1
    Registered User
    Join Date
    Mar 2009
    Posts
    7

    multiply sections of printf format specifier?

    Wondering if there is a built in way to multiply sections of the printf format field in cases when you want a particular part to repeat. In other words lets say you want to print 100 integers with minimum field width of 5, each separated by a tab. Is there a way to do this without typing %20d\t 100 times?

  2. #2
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,412
    Use a loop.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  3. #3
    Registered User
    Join Date
    Mar 2009
    Posts
    7
    for my case, each variable i will be printing will have a unique name (ie won't be part of an array), so not sure that a loop would be appropriate, unless i'm misunderstanding how the loop would be used?

    i'm more looking for something where i could put, for instance, 100*(%20d\t) in the format specifier, though i know it wouldn't work as i just typed.

  4. #4
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,412
    Quote Originally Posted by space_ferret
    for my case, each variable i will be printing will have a unique name (ie won't be part of an array), so not sure that a loop would be appropriate, unless i'm misunderstanding how the loop would be used?
    Yes, then a loop will not be appropriate. However, perhaps you should be using an array instead of so many separate variables.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  5. #5
    Hurry Slowly vart's Avatar
    Join Date
    Oct 2006
    Location
    Rishon LeZion, Israel
    Posts
    6,788
    Quote Originally Posted by space_ferret View Post
    for my case, each variable i will be printing will have a unique name (ie won't be part of an array), so not sure that a loop would be appropriate, unless i'm misunderstanding how the loop would be used?

    i'm more looking for something where i could put, for instance, 100*(%20d\t) in the format specifier, though i know it wouldn't work as i just typed.
    you can use loop to build the format string...

    but having so many vars with different names that should be printed with the same format... Are you sure they cannot be put into array?

    you can use enum as index to have

    a[book_price] instead of a[5] if this is the reason to call vars differently
    All problems in computer science can be solved by another level of indirection,
    except for the problem of too many layers of indirection.
    – David J. Wheeler

  6. #6
    Registered User
    Join Date
    Mar 2009
    Posts
    7
    i think using a loop to build the format string is a good solution for me, i will try that out, thanks.

    as far as putting the vars into an array, wouldn't be good for my program. (btw it's more like 40 vars than 100, just using 100 as an example)

  7. #7
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,412
    Quote Originally Posted by space_ferret
    i think using a loop to build the format string is a good solution for me, i will try that out, thanks.
    You still have the problem of listing all those variables when you actually want to write out the printf() call. You need to keep track of exactly how many variables are involved both in creating the format string and listing the variables themselves, which is potentially a maintenance nightmare. (EDIT: I suppose the use of vprintf() instead of printf() with a function can alleviate this problem, but it would not eliminate the need to explicitly list the variables.)

    Quote Originally Posted by space_ferret
    as far as putting the vars into an array, wouldn't be good for my program. (btw it's more like 40 vars than 100, just using 100 as an example)
    Why do you think so? Of course, it may also be the case that you should be defining a few structs instead.
    Last edited by laserlight; 03-20-2009 at 12:51 PM.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  8. #8
    Registered User
    Join Date
    Mar 2009
    Posts
    7
    the reason i don't want to put the vars into an array or structure is that, other than printing them out once, i don't have any reason to group them together. also many of the fields that will be printed aren't persisting variable but functions of other vars (ie a*b+c).

    vprintf() looks promising, thanks for the heads up on that. never tried it before and my ref book doesn't explain it very well, so i'll have to see if i can get it going.

    unfortunately i'm not sure there is a good way around having to explicitly list the variables, so it will be a bit of a maintenance mess

  9. #9
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,412
    Quote Originally Posted by space_ferret
    vprintf() looks promising, thanks for the heads up on that. never tried it before and my ref book doesn't explain it very well, so i'll have to see if i can get it going.
    hmm... I think that this is the best example I can come up with at the moment:
    Code:
    #include <stdio.h>
    #include <stdarg.h>
    #include <stdlib.h>
    #include <string.h>
    
    void print_all(int num, ...);
    
    int main(void)
    {
        int a = 1, b = 2, c = 3;
        print_all(3, a, b, c);
        return 0;
    }
    
    void print_all(int n, ...)
    {
        const char format_specifier[] = "%d ";
        char *format_str;
        if (n > 0 && (format_str = malloc(n * (sizeof(format_specifier) - 1) + 2)))
        {
            int i;
            va_list ap;
            va_start(ap, n);
            format_str[0] = '\0';
            for (i = 0; i < n; ++i)
            {
                strcat(format_str, format_specifier);
            }
            strcat(format_str, "\n");
            vprintf(format_str, ap);
            va_end(ap);
            free(format_str);
        }
    }
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  10. #10
    Registered User
    Join Date
    Mar 2009
    Posts
    7
    not sure if using the variable arg list saves me any work, so i ended up writing a function that builds the format string. in my case i wanted tab separated scientific notation:

    insert
    Code:
    int main(void)
    {
        double a = 1.0, b = 2.0, c = 3.0;
        int n_vars = 3, min_field_width = 15, n_dec_pts = 6;
        printf(tab_sep_sci(n_vars, min_field_width, n_dec_pts), a, b, c);
        return 0;
    }
    
    char *tab_sep_sci(int n, int min_field_width, int n_decimal)
    {
    	char *format = NULL;
    	char *field = NULL;
    	int i;
    	
    	sprintf(field, "%%%d.%de\t", min_field_width, n_decimal);
    
    	for(i=0; i<n; i++) strcat(format, field);
    
    	strcat(format, "\n");
    
    	return format;
    }
    Last edited by space_ferret; 03-20-2009 at 02:59 PM.

  11. #11
    Hurry Slowly vart's Avatar
    Join Date
    Oct 2006
    Location
    Rishon LeZion, Israel
    Posts
    6,788
    your field is NULL pointer you cannot write there
    All problems in computer science can be solved by another level of indirection,
    except for the problem of too many layers of indirection.
    – David J. Wheeler

  12. #12
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,412
    Quote Originally Posted by space_ferret
    not sure if using the variable arg list saves me any work, so i ended up writing a function that builds the format string.
    As vart has hinted and as I demonstrated, you would need to dynamically allocate space for the format string. This means that if you are going to have a function that returns a format string, you would need to use free() in the caller. Consequently, I think that my print_all() function would indeed save you work in the long run.

    Quote Originally Posted by space_ferret
    in my case i wanted tab separated scientific notation:
    Adapt my example such that the format specifier can be given at the function call:
    Code:
    #include <stdio.h>
    #include <stdarg.h>
    #include <stdlib.h>
    #include <string.h>
    
    int print_all(const char *format_specifier, int num, ...);
    
    int main(void)
    {
        double a = 1.1, b = 2.2, c = 3.3, d = 4.4;
        print_all("%15.6e\t", 4, a, b, c, d);
        return 0;
    }
    
    int print_all(const char *format_specifier, int n, ...)
    {
        int return_value = 0;
        char *format_str;
        if (n > 0 && (format_str = malloc(n * strlen(format_specifier) + 2)))
        {
            int i;
            va_list ap;
            va_start(ap, n);
            format_str[0] = '\0';
            for (i = 0; i < n; ++i)
            {
                strcat(format_str, format_specifier);
            }
            strcat(format_str, "\n");
            return_value = vprintf(format_str, ap);
            va_end(ap);
            free(format_str);
        }
        return return_value;
    }
    So, the min_field_width and n_dec_pts is handled by the "15.6" part of the format specifier, as per normal.
    Last edited by laserlight; 03-21-2009 at 10:48 AM. Reason: Gave print_all() a return value, like the printf() family of functions.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  13. #13
    Registered User
    Join Date
    Mar 2009
    Posts
    7
    thanks a lot laserlight.

    i see the benefit of your function now (and why mine was messed up). the only thing i don't like about it is that you can't mix and match format (ie 30 doubles followed by 20 ints) without doing separate calls, but no biggie.

    i was also trying to figure out how to do it using macros, but the only thing i could come up with is something like:

    #define RPT_STR2(s) s s
    #define RPT_STR3(s) s RPT_STR2(s)
    #define RPT_STR4(s) s RPT_STR3(s)
    ...
    #define RPT_STR10(s) s RPT_STR9(s)

    then if i want to print out 7 integers followed by 45 doubles in scientific notation i could write:

    fprintf(fp, RPT_STR7("%6d\t") RPT_STR9(RPT_STR5("%23.14e\t")) "\n", a, b, c, etc....)

    also instead of doing nested RPT_STR i could just extend it to say RPT_STR100, but all of this is a little clunky

  14. #14
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    If you don't want to put all the items in an array, you can at least make an array of pointers to these items, then print them:

    Code:
    int *itemsToPrint[40] = { &foo, &bar, &baz, ... };
    int i;
    for(i = 0; i < 40; ++i)
        printf("%20d\t", *itemsToPrint[i]);
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

  15. #15
    Registered User
    Join Date
    Mar 2009
    Posts
    7
    thanks brewbuck, that is a good idea. i don't think i would be able to do it quite as you wrote however, because many of the fields i will be writing aren't persistent variables, but rather functions of other variables (ie foo*bar+some_func(baz)). i could have an output array (not of pointers) as suggested above, but then i'd have to go through and assign each element individually right before the print statement. this would make the printing cleaner, but not sure it's worth the effort.

    for my case it won't be an issue b/c i'm not printing that many things (i'll maybe print to file ~50 vars ~1000 times), but for future reference, is there any substantive difference in speed between writing to a file using one statement w/ many arguments, or looping over the statement many times. or does the buffer sort of even that out. for that matter, if i was concerned with speed, should i be using fwrite instead of fprintf?
    Last edited by space_ferret; 03-27-2009 at 11:10 AM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Problems reading entered race times C
    By loopymoo26 in forum C Programming
    Replies: 12
    Last Post: 05-23-2009, 07:38 AM
  2. I have some questions :(
    By geekrockergal in forum C Programming
    Replies: 19
    Last Post: 02-01-2009, 09:44 AM
  3. saying hello and 1st question
    By darksys in forum C Programming
    Replies: 12
    Last Post: 10-31-2008, 02:58 PM
  4. Format Specifier
    By babu in forum C Programming
    Replies: 2
    Last Post: 06-27-2007, 11:17 PM
  5. Simple C question: user input to repeat a loop
    By evernaut in forum C Programming
    Replies: 2
    Last Post: 11-18-2006, 09:23 AM