Don't confuse %*s and %.*s

Here's a little C programming tip which would have just saved me some time: if you want to print a string which isn't NULL-terminated, you can do so with printf by passing in the number of bytes you want to print, but you have to use the precision to set the size, not the field width.

In a printf format string, a %s instruction would normally print everything up to the terminating NULL byte. You can add a number before the s to specify the field width, which will force the output to be at least that many characters. That will always print the whole string though, whether it's longer or shorter than you specify, padding it with spaces if it's not as many characters as you use for the width. If you use %.ns instead, you'll prevent printf from going past the block of characters you want it to print.

Also, if you've got the real size of the string in a variable, if you're not using NULL-terminated strings, you can use * instead of the number to tell printf to take the number from one of its extra arguments. It will expect the size to come before the char* argument pointing to the text.

Here's an example where I've got a four byte string, but the buffer it's stored in has four more bytes after the data I care about before there's a NULL byte:

#include <stdio.h>

int
main (void) {
    const char *str = "frobnitz";
    int num_bytes = 4;

    /* Set precision if string isn't NULL-terminated */
    printf("4 bytes max: [%.4s]\n",  str);
    printf("4 bytes max: [%.*s]\n",  num_bytes, str);

    /* Field width won't limit length of output... */
    printf("4 bytes min: [%4s]\n",   str);
    printf("4 bytes min: [%*s]\n",   num_bytes, str);

    /* ...but can be used to pad string with spaces */
    printf("10 bytes min: [%10s]\n", str);
    printf("10 bytes min: [%*s]\n",  10, str);

    return 0;
}

And here's the output:

4 bytes max: [frob]
4 bytes max: [frob]
4 bytes min: [frobnitz]
4 bytes min: [frobnitz]
10 bytes min: [  frobnitz]
10 bytes min: [  frobnitz]

Note that normally I use size_t to store the size of strings, but the * thing in a format string expects an int, so you might have to cast it.

< Yorkshire floods | Pocari Sweat® >

Miniblog

(nuggets of inanity)

Tuesday Apr 24th 2007, 16:54 »
Just took the annual web design survey that AListApart do. I don't realy consider myself to be a web designer, but I have been doing a lot of HTML and CSS lately.
Monday Apr 23rd 2007, 18:23 »
Strange, there appears to be a bare-knuckle boxing match going on in the field outside my flat. Wish they wouldn't make so much noise about it.
Thursday Mar 1st 2007, 18:47 »
“In its written form, Hebrew has no vowels, making it the ideal language for texting.”
—Said in jest on some Radio 4 programme just now.

Archive: 2007 · 2006 · 2005 · 2004
Feed