Problem z pętlą, oraz warunkiem isdigit()

0

Witam, mam następujący problem.
Stworzyłem mikroskopijny program, który ma za zadanie sprawdzać czy input jest liczbą, a jeśli nie - to o tym usera poinformować i wrócić do początku programu.
Oto kod:

#include <stdio.h> 
#include <stdlib.h> /*for atof*/
#include <ctype.h>

int main()
{
    double c, d;
    printf("please enter a number\n");
    c = getchar();
    do {
    if (isdigit(c)) 
        printf("thanks for the number\n");
    else
        printf("please enter a number\n");
    printf("press r to repeat\n");
    fflush(stdin);
    d = getchar();  
    } while (d == 'r');
    return 0;           
}    

Niestety obecnie pętla robi jeden ruch i wychodzi z programu. Co mam zrobić, żeby działało?
Zauważyłem również, że po dodaniu sprawdzającego printf, aby się upewnić, że liczba jest prawidłowo odczytana, wyświetla on zupełnie inną liczbę niż ta podana...

1
scanf
0

Zmodyfikowałem getchar na scanf, niestety nadal nie działa:

 #include <stdio.h> 
#include <stdlib.h>
#include <ctype.h>

int main()
{
    double c, d;
    printf("Please enter a number\n");
    scanf("%lg", &c);
    printf("ur number is %g", c);
    do {
    if (isdigit(c)) 
        printf("Thanks for the number");
    else
        printf("It is not a number. Please enter a number");
    printf("Press r to repeat\n");  
    scanf("%lg", &d);
    } while (d != 'r');
    return 0;           
}   

Program zwraca, że wpisana liczba nie jest liczbą (!) Wobec czego wchodzi w nieskończoną pętlę z instrukcją z else.
Co robię źle?

1

Twój program ma głównie taki problem, że funkcja isdigit przyjmuje za argument int, ale ten int, to jest liczba reprezentująca znak ASCII, czyli jak podasz z klawiatury 0, to tam trzeba podać kod zera, czyli najprościej

isdigit('0'); 

Wtedy kompilator sobie ten kod wyciągnie (jeśli dobrze pamiętam to ten kod jest 48, ale pewności nie mam. W necia na pewno można znaleźć).
Poza tym linijka

scanf("%lg", &d);

gdzie d jest typu double, a potem sprawdzanie

 while (d != 'r');

też nie jest najlepszym pomysłem, bo typ znakowy do double trochę niechętnie się przypisuje, tym gorzej z porównywaniem tych typów.

Ja zrobiłem sobie taką funkcję, która wczytuje z klawiatury znaki i zapisuje do tablicy char[], a potem, znak po znaku sprawdza, czy na każdej pozycji jest liczba, a właściwie przerywa sprawdzanie ze stosownym komunikatem, jeśli napotka jakiś znak który cyfrą nie jest:

    const int numberLength = 20;
    char number[numberLength] = { '\0' };

    do
    {
        printf("Podaj liczbe, albo 'q' zeby wyjsc: ");
        if(scanf_s("%s", number, numberLength) == 0)
        {
            fflush(stdin);
            printf("! Podano zbyt dlugi tekst.");
            getchar();
            break;
        }
        for(int i = 0; i < numberLength && number[i] != NULL; i++)
        {
            if(!isdigit(number[i]) && number[i] != '.')
            {
                printf("%s nie jest liczba\n", number);
                break;
            }
        }

    }while(number[0] != 'q'); 

Dawno nie pisałem w C++, więc być może ten problem da się rozwiązać prościej i szybciej, mi pierwsze co przyszło do głowy, to taki kod.
Program ma delikatną wadę, a mianowicie rozpoczęcie wprowadzania od 'q' przerywa program, niezależnie co po tym się wprowadzi. Ale nie jest to chyba najistotniejsze.

0

Bardzo dziękuję za pomoc. Mam jednak kilka pytań, zaznaczę je jako komentarze przy linijce:

Lena(R) napisał(a):

const int numberLength = 20;
char number[numberLength] = { '\0' }; /*po co inicjalizować tylko jeden element tablicy jako \0 a resztę jako zera w domyśle*/
do
{
    printf("Podaj liczbe, albo 'q' zeby wyjsc: ");
    if(scanf("%s", number, numberLength) == 0) /*tutaj scanf pobiera tylko number, czemu więc dopisałeś numberLength ?*/
    {
        fflush(stdin);
        printf("! Podano zbyt dlugi tekst."); /*czy ten komunikat jest poprawny?; przecież scanf z tym warunkiem z if, będzie = 0 wtedy gdy input nie będzie stringiem?*/
        getchar();
        break;
    }
    for(int i = 0; i < numberLength && number[i] != NULL; i++) /*!= NULL czy != 0 powinno być ?*/
    {
        if(!isdigit(number[i]) && number[i] != '.')
        {
            printf("%s nie jest liczba\n", number);
            break;
        }
    }

}while(number[0] != 'q'); 
1

odpowiem w komentarzach

Pole napisał(a):

Bardzo dziękuję za pomoc. Mam jednak kilka pytań, zaznaczę je jako komentarze przy linijce:

Lena(R) napisał(a):

const int numberLength = 20;
char number[numberLength] = { '\0' }; /*po co inicjalizować tylko jeden element tablicy jako \0 a resztę jako zera w domyśle*/ // w zasadzie nie ma to sensu, rownie dobrze mozna napisac char number[numberLength] = {}; domyslnie reszta elementow bedzie zerami. Natomiast zapis: char number[numberLength]; juz tego nie zapewnia (nie wiesz jakie beda wartosci)
do
{
    printf("Podaj liczbe, albo 'q' zeby wyjsc: ");
    if(scanf("%s", number, numberLength) == 0) /*tutaj scanf pobiera tylko number, czemu więc dopisałeś numberLength ?*/ // powinno nie byc drugiego elementu, a jeszcze lepiej gdybys zastapil to %20s lub fgets-em (zabezpieczenie przed buffer overflow)
    {
        fflush(stdin);
        printf("! Podano zbyt dlugi tekst."); /*czy ten komunikat jest poprawny?; przecież scanf z tym warunkiem z if, będzie = 0 wtedy gdy input nie będzie stringiem?*/ // ten komunikat nastapi tylko i wylacznie gdy nie bedzie zadnych niebialych znakow na wejsciu - tak czy siak jest zle
        getchar();
        break;
    }
    for(int i = 0; i < numberLength && number[i] != NULL; i++) /*!= NULL czy != 0 powinno być ?*/ // null jest rownowazne 0, ale prawidlowo powinno byc 0 lub '\0', NULL jest typu void*
    {
        if(!isdigit(number[i]) && number[i] != '.')
        {
            printf("%s nie jest liczba\n", number);
            break;
        }
    }

}while(number[0] != 'q'); 

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0