8

In C, what is the best way to ignore the commas when using scanf on a number like 1,000,000?

Spikatrix
  • 20,225
  • 7
  • 37
  • 83
Dizzzyp
  • 137
  • 1
  • 9

2 Answers2

14

I would say the best way is to not use scanf for this. At least not using any number formats.

Instead read it as a string, then remove the commas, and finally convert to a number.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
3

There are a number of ways to remove the commas (or any other character you want to skip). One of the easiest (and most flexible) is to simply walk two pointers down the input string shifting all the digits together ignoring the commas. (you must be sure to nul-terminate after the final digit).

An example would be:

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <limits.h>

#define MAXC 25

long xstrtol (char *p, char **ep, int base);

int main (void) {

    char string[MAXC] = "";
    char *rp, *wp;          /* a read pointer and write pointer */
    int c;
    long n = 0;

    rp = wp = string;

    printf ("enter number with ',': ");
    if (!fgets (string, MAXC, stdin)) {
        fprintf (stderr, "error: insufficient input.\n");
        return 1;
    }

    /* work down each char in string, shifting number together */
    while (*rp && (('0' <= *rp && *rp <= '9') || *rp == ',')) {
        if (*rp == ',') { rp++; continue; }     /* skip commas */
        *wp++ = *rp;               /* shift digits together    */
        rp++;
    }
    *wp = 0;   /* nul-terminate */

    if (*rp != '\n') /* flush input buffer */
        while ((c = getchar()) != '\n' && c != EOF) {}

    printf ("\n string : %s\n", string);
    n = xstrtol (string, &rp, 10);       /* convert string to long */

    printf(" n      : %ld\n\n", n);

    return 0;
}

/** a simple strtol implementation with error checking.
 *  any failed conversion will cause program exit. Adjust
 *  response to failed conversion as required.
 */
long xstrtol (char *p, char **ep, int base)
{
    errno = 0;

    long tmp = strtol (p, ep, base);

    /* Check for various possible errors */
    if ((errno == ERANGE && (tmp == LONG_MIN || tmp == LONG_MAX)) ||
        (errno != 0 && tmp == 0)) {
        perror ("strtol");
        exit (EXIT_FAILURE);
    }

    if (*ep == p) {
        fprintf (stderr, "No digits were found\n");
        exit (EXIT_FAILURE);
    }

    return tmp;
}

(note: xstrtol simply provides error checking on the conversion of string to long)

Use/Output

$ ./bin/nwithcomma
enter number with ',': 1,234,567

 string : 1234567
 n      : 1234567

Look it over and let me know if you have any questions. You can check against INT_MIN and INT_MAX if you want to cast the result to int, but it is just as easy to leave the answer as a long.

As a Function

As pointed out, it would be far more useful as a function. You can move the code to a simple conversion function, and adjust the main code as follows:

...
#define MAXC 25

long fmtstrtol (char *s);
long xstrtol (char *p, char **ep, int base);

int main (void) {

    char string[MAXC] = "";

    printf ("enter number with ',': ");
    if (!fgets (string, MAXC, stdin)) {
        fprintf (stderr, "error: insufficient input.\n");
        return 1;
    }

    printf(" number : %ld\n\n", fmtstrtol (string));

    return 0;
}

/* convert comma formatted string to long */
long fmtstrtol (char *s)
{
    if (!s || !*s) {
        fprintf (stderr, "fmtstrtol() error: invalid string.\n");
        exit (EXIT_FAILURE);
    }

    char *rp, *wp;  /* read pointer, write pointer */
    int c;

    rp = wp = s;

    while (*rp && (('0' <= *rp && *rp <= '9') || *rp == ',')) {
        if (*rp == ',') { rp++; continue; }
        *wp++ = *rp;
        rp++;
    }
    *wp = 0;

    if (*rp != '\n') /* flush input buffer */
        while ((c = getchar()) != '\n' && c != EOF) {}

    return xstrtol (s, &rp, 10);
}
...
David C. Rankin
  • 81,885
  • 6
  • 58
  • 85