30

Is there a good way to loop over a string with sscanf?

Let's say I have a string that looks like this:

char line[] = "100 185 400 11 1000";

and I'd like to print the sum. What I'd really like to write is this:

int n, sum = 0;
while (1 == sscanf(line, " %d", &n)) {
  sum += n;
  line += <number of bytes consumed by sscanf>
}

but there's no clean way to get that information out of sscanf. If it returned the number of bytes consumed, that'd be useful. In cases like this, one can just use strtok, but it'd be nice to be able to write something similar to what you can do from stdin:

int n, sum = 0;
while (1 == scanf(" %d", &n)) {
  sum += n;
  // stdin is transparently advanced by scanf call
}

Is there a simple solution I'm forgetting?

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Andrew H. Hunter
  • 561
  • 1
  • 4
  • 8

1 Answers1

53

Look up the %n conversion specifier for sscanf() and family. It gives you the information you need.

#include <stdio.h>

int main(void)
{
    char line[] = "100 185 400 11 1000";
    char *data = line;
    int offset;
    int n;
    int sum = 0;

    while (sscanf(data, " %d%n", &n, &offset) == 1)
    {
        sum += n;
        data += offset;
        printf("read: %5d; sum = %5d; offset = %5d\n", n, sum, offset);
    }

    printf("sum = %d\n", sum);
    return 0;
}

Changed 'line' to 'data' because you can't increment the name of an array.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • 2
    @Green Code: I've read, and reread, and re-reread, the manual pages for the function over the years, on many machines, and using my copy of the C standard, etc. I think it is actually the first time I've used the `%n` notation, but it works fine. **Beware**: `%n` also exists in `printf()` and has the analogous meaning. It becomes a risk factor because it is an *output* value in a function that predominantly reads values. It is also banned by the secure versions of `printf()` for TR24731. And `%n` can be used with devastating effect by people who manage format string attacks on programs. – Jonathan Leffler Oct 20 '10 at 13:41
  • I'm actually aware of %n, yeah, but am wary of using it for security reasons. But if it's the only way... – Andrew H. Hunter Oct 20 '10 at 19:38
  • @JonathanLeffler is the leading space in the format string of `sscanf` needed because `%d` anyway reads and discards any number of whitespace characters? – ajay Mar 25 '14 at 10:56
  • Also could you please explain what is `TR24731` that you mentioned for `printf`? – ajay Mar 25 '14 at 11:23
  • 1
    @ajay: no, the leading space is not required; I copied it from the question without thinking. [TR 24731-1](http://www.open-std.org/jtc1/sc22/wg14/www/projects#24731-1) "Extensions to the C Library Part 1: Bounds Checking Interfaces" is a Technical Report from the ISO JTC1/SC22/WG14 Committee (aka 'Standard C' committee) that defines 'safer' versions of a number of functions. They are implemented, more or less, by Microsoft (see [Do you use TR 24731 safe functions](http://stackoverflow.com/q/372980/)). TR24731-1 is (optional) Annex K in ISO/IEC 9899:2011, the current version of the C standard. – Jonathan Leffler Mar 25 '14 at 13:52
  • @JonathanLeffler Thank you so much :) Every day I feel how little I know and excited at the same time to realize how much there is to learn. – ajay Mar 25 '14 at 17:07
  • Am using this to get average of numbers from command line argument , thanks a lot – An Ant Feb 01 '21 at 04:55