Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In C, How to use scanf to scan in 1,000,000 ignoring the commas

Tags:

c

scanf

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

like image 756
Dizzzyp Avatar asked Apr 07 '16 06:04

Dizzzyp


People also ask

How do I scanf a string until a character?

We should use "%[^\n]", which tells scanf() to take input string till user presses enter or return key.

How do I make scanf read whitespace?

So we use “%[^\n]s” instead of “%s”. So to get a line of input with space we can go with scanf(“%[^\n]s”,str);

How does scanf treat whitespace?

scanf() just stops once it encounters a whitespace as it considers this variable "done".


2 Answers

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.

like image 108
Some programmer dude Avatar answered Sep 22 '22 03:09

Some programmer dude


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);
}
...
like image 35
David C. Rankin Avatar answered Sep 23 '22 03:09

David C. Rankin