2012-03-05 13 views
6

Próbuję odczytać unsigned int użyciu cin następująco:czytanie „unsigned int” za pomocą „cin”

#include <limits.h> 
#include <iostream> 

using namespace std; 

int main(int argc, char* argv[]) 
{ 
    unsigned int number; 

    // UINT_MAX = 4294967295 
    cout << "Please enter a number between 0 and " << UINT_MAX << ":" << endl; 

    cin >> number; 

    // Check if the number is a valid unsigned integer 
    if ((number < 0) || ((unsigned int)number > UINT_MAX)) 
    { 
     cout << "Invalid number." << endl; 
     return -1; 
    } 
    return 0; 
} 

Jednak ilekroć wprowadzić wartość większą niż górna granica liczba całkowita bez znaku (UINT_MAX) program wyświetla 3435973836. Jak sprawdzić, czy dane wejściowe podane przez użytkownika mieszczą się między 0 a UINT_MAX?

+12

'if ((liczba <0) || ((unsigned int) number> UINT_MAX))' Nie mogę nawet opisać, jak błędne jest to. – ildjarn

+0

Może zacznij od czegoś prostszego i zdecydowanie dobrej książki. –

+1

Dość podstawowe, ale rozsądne pytanie. Ale bardzo długo to wyjaśniać. – Mysticial

Odpowiedz

5

dwie rzeczy:

  • sprawdzenie czy liczba całkowita bez znaku jest < 0 lub> UINT_MAX jest bezcelowe, ponieważ może ona nigdy nie osiągnie tej wartości! Twój kompilator prawdopodobnie już narzeka z ostrzeżeniem, że "porównanie jest zawsze fałszywe z powodu ograniczonego zakresu typu".

  • Jedyne rozwiązanie, jakie mogę sobie wyobrazić, to przechwycenie danych wejściowych w łańcuchu, a następnie użycie staromodnej metody strtoul(), która ustawia errno w przypadku przepełnienia.

tj .:

#include <stdlib.h> 

unsigned long number; 
std::string numbuf; 
cin >> numbuf; 
number = strtoul(numbuf.c_str(), 0, 10); 
if (ULONG_MAX == number && ERANGE == errno) 
{ 
    std::cerr << "Number too big!" << std::endl; 
} 

Uwaga: strtoul zwraca unsigned long; nie ma funkcji strtou(), zwracanie niepodpisanej int.

+0

Prawdopodobnie lepiej ustawić errno na 0 przed wywołaniem, a następnie sprawdzić, czy nie ma zerowej wartości. Wygląda na to, że EINVAL może się również zdarzyć. –

2

Można odczytywać długi czas bez znaku i przetestować go w odniesieniu do niepodpisanego limitu int.

+0

Tak właśnie robi operator >>. –

+0

@ BoPersson, czy mówisz, że '>>' automatycznie promuje się na długo? Nawet jeśli tak się stanie, będzie musiał skrócić, gdy będzie przechowywany w unsigned int. – AShelly

+0

Mówię, że 'operator >>' używa 'num_get', który zbiera znaki, konwertuje na największy niepodpisany typ liczby całkowitej, a następnie weryfikuje zakres docelowy przed przypisaniem wyniku. Tak jakbyś zrobił to sam. –

2

Gdy użytkownik wchodzi wiele wyższy niż UINT_MAX, cinczapki go na UINT_MAX tak. Wartość nie może być również ujemna.

Jeśli chcesz przedłużyć zasięg, użyj wejścia unsigned long long i po kontroli odlcz do unsigned int. Nie będzie to jednak ochrona przed numerami spoza zakresu unsigned long long.

Aby uzyskać rozwiązanie uniwersalne, można odczytać numer string i wykonać konwersję samodzielnie, stosując jako wynik unsigned long long.

3

Twoje sprawdzanie nie ma sensu (o czym poinformowałby Cię kompilator z prawidłowo włączonymi ostrzeżeniami), ponieważ twoja wartość nigdy nie jest mniejsza niż 0 i nigdy nie przekracza UINT_MAX, ponieważ są to najmniejsza i największa wartość zmiennej typu unsigned int (która to liczba is) może pomieścić.

Użyj stanu strumienia, aby sprawdzić, czy odczyt do liczby całkowitej działał poprawnie.

1

Jeśli spróbujesz odczytać go w postaci unsigned int, będziesz musiał ograniczyć się do ograniczeń unsigned int.

Najbardziej ogólnym sposobem zrobienia tego, o co prosisz, jest odczytanie wejścia jako string i przeanalizowanie go, aby upewnić się, że znajduje się we właściwym zakresie. Po zatwierdzeniu go można go przekonwertować na unsigned int.

Powiązane problemy