В C, как использовать scanf для сканирования в 1,000,000, игнорируя запятые

В C, каков наилучший способ игнорировать запятые при использовании scanf на номер 1,000,000?

2 ответов


существует несколько способов удаления запятых (или любого другого символа, который вы хотите пропустить). Один из самых простых (и наиболее гибких) - просто пройти два указателя по входной строке, сдвинув все цифры вместе, игнорируя запятые. (вы должны быть уверены, что nul-terminate после последней цифрой).

пример:

#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;
}

(Примечание: xstrtol просто обеспечивает проверку ошибок при преобразовании string в long)

Использовать/Выход

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

 string : 1234567
 n      : 1234567

посмотреть его снова и дайте мне знать, если у вас есть какие-либо вопросы. Вы можете проверить против INT_MIN и INT_MAX если вы хотите привести результат к int, но так же легко оставить ответ, как long.

функции

как указано, это было бы гораздо более полезно в качестве функции. Вы можете переместить код в простую функцию преобразования и настроить основной код следующим образом:

...
#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);
}
...

Я бы сказал, что лучший способ-это не использовать scanf для этого. По крайней мере, не используя числовые форматы.

вместо этого прочитайте его как строку, затем удалите запятые и, наконец,преобразовать в ряд.