57
#define SIZE 9
int number=5;
char letters[SIZE]; /* this wont be null-terminated */
... 

char fmt_string[20];
sprintf(fmt_string, "%%d %%%ds", SIZE);
/* fmt_string = "%d %9d"... or it should be */

printf(fmt_string, number, letters);

Is there a better way to do this?

4
  • You seem to be building a format string. But you should be assigning the string returned by sprintf to fmt_string and fmt_string shouldn't be in the parameter list. Commented May 9, 2011 at 3:41
  • Is there any particular reason you say that letters won't be null-terminated? Commented May 9, 2011 at 3:53
  • 1
    @AndrewKeeton this was for a search problem with a large dataset where I couldn't afford the space to hold null characters. Commented Oct 11, 2014 at 19:46
  • NOTE: this is a duplicity of stackoverflow.com/questions/2239519/… Commented Sep 2, 2016 at 8:31

2 Answers 2

136

There is no need to construct a special format string. printf allows you to specify the precision using a parameter (that precedes the value) if you use a .* as the precision in the format tag.

For example:

printf ("%d %.*s", number, SIZE, letters);

Note: there is a distinction between width (which is a minimum field width) and precision (which gives the maximum number of characters to be printed). %*s specifies the width, %.s specifies the precision. (and you can also use %*.* but then you need two parameters, one for the width one for the precision)

See also the printf man page (man 3 printf under Linux) and especially the sections on field width and precision:

Instead of a decimal digit string one may write "*" or "*m$" (for some decimal integer m) to specify that the precision is given in the next argument, or in the m-th argument, respectively, which must be of type int.

Sign up to request clarification or add additional context in comments.

5 Comments

Had them mixed up... scanf is the one that doesn't have that option.
It also works with 2 lengths like "%*.*s", minlength, maxlength, letters.
Note: "*m$" is not standard C.
Is there a way to get the "%.*s" format to accept size_t instead of int?
make a cast to (int)var_size_t
6

A somewhat unknown function is asprintf. The first parameter is a **char. This function will malloc space for the string so you don't have to do the bookkeeping. Remember to free the string when done.

char *fmt_string;

asprintf(&fmt_string, "%%d %%%ds", SIZE);
printf(fmt_string, number, letters);
free(fmt_string);

is an example of use.

2 Comments

Although asprintf is indeed an interesting function, it is important to note that it is a gnu extention. Also, I'm not sure how this addresses the question.
@Trent, it's true that it started as a GNU extension, but in the mean time OpenBSD, FreeBSD and NetBSD have implemented it. Even Mac OS X has it now.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.