2012-03-17 8 views
18

Muszę sprawdzić, czy łańcuch C jest poprawną liczbą całkowitą.Ustal, czy łańcuch C jest poprawnym int w C

Próbowałem zarówno

int num=atoi(str); 

i

int res=sscanf(str, "%d", &num); 

Ale wysyłanie ciąg "8 -9 10" w obu liniach powrócił po prostu 8, bez wskazania nieważności tego łańcucha.

Czy ktoś może zaproponować alternatywę?

+0

'atoi' nie sprawdza błędów; jego zachowanie, jeśli 'str' nie zawiera reprezentacji wartości' int', jest niezdefiniowane. (Typowe implementacje zwracają '0'.)' Sscanf' jest lepszy, ale jego zachowanie jest niezdefiniowane, jeśli wartość w łańcuchu nie jest reprezentowana jako 'int'. Twój tytuł mówi, że chcesz sprawdzić poprawną int, ale treść twojego pytania mówi "poprawna liczba całkowita"; nie są tym samym. 'int' jest jednym z kilku typów * liczb całkowitych *. –

Odpowiedz

29

Spójrz na strtol(), może powiedzieć ci o niepoprawnych częściach łańcucha przez zwrócenie wskaźnika.

I uwaga na entuzjastyczny przykładowy kod. Zobacz stronę podręcznika dla kompleksowej obsługi błędów.

+0

strtol() po prostu ustawia wskaźnik na następny "obiekt" w łańcuchu. To nic nie potwierdza. –

+1

@ g24l Jeśli wskaźnik ten wskazuje na NULL, oznacza to, że cały ciąg znaków jest prawidłowy. Jeśli nie, nie. Tadaa! – blueshift

+0

Jeśli jest to łańcuch zakończony znakiem zerowym. –

8

Może będę się podpalany na nie za pomocą strtol lub podobnych libc funkcje, ale rozumowanie o ten problem nie jest trudne:

#include <stdbool.h> // if using C99... for C++ leave this out. 
#include <ctype.h> 

bool is_valid_int(const char *str) 
{ 
    // Handle negative numbers. 
    // 
    if (*str == '-') 
     ++str; 

    // Handle empty string or just "-". 
    // 
    if (!*str) 
     return false; 

    // Check for non-digit chars in the rest of the stirng. 
    // 
    while (*str) 
    { 
     if (!isdigit(*str)) 
     return false; 
     else 
     ++str; 
    } 

    return true; 
} 

[NB: mógłbym inaczej zrobione isdigit(*str++) zamiast else do ale krótsze, ale moje wspomnienie jest takie, że standardy mówią, że możliwe jest, że isdigit jest makro.]

Domyślam się, że jednym ograniczeniem jest to, że nie zwraca ono fałszu, jeśli liczba w łańcuchu nie mieści się w liczbie całkowitej. To może lub nie ma znaczenia dla Ciebie.

+1

"nie tak trudne", ale trzeba było wrócić i zmienić;) – blueshift

+1

@blueshift Punkt wzięty, ale 1 edycja w 5 minut, kiedy wpisanie kodu do formularza internetowego nie jest dla mnie takie złe. :-) – asveikau

+0

W tym przypadku nie wiem, czy jest to bardziej podatne na błędy, czy mogę samemu przetasować, czy spróbować uzyskać obsługę błędów dla strtol() w prawo. Prawdopodobnie nadal będę polecał strtol. – blueshift

2

Prostym sposobem, aby to zrobić solidnie byłoby odczytać int i upewnić się, że reprezentacja ciąg jest identyczna z ciągu wejściowego, na przykład łącząc atoi i itoa:

int is_int(char const* p) 
{ 
    return strcmp(itoa(atoi(p)), p) == 0; 
} 
+0

Fajny pomysł :). Będzie to jednak wymagać również przycinania spacji i spacji w celu jej usprawnienia. – sara

+3

Należy pamiętać, że to rozwiązanie nie jest zgodne z ANSI. –

0

Dla sprawdzenia, czy ciąg zawiera prawidłowy numer, możesz użyć wyrażenia regularnego. Na przykład dla liczb całkowitych używać:

[- +] [0-9] +

i ogólnym przypadku dla liczb zmiennoprzecinkowych:?

[+ -] [0-9] + [ .]? [0-9] * ([eE] [- +]? [0-9] +)?

W przypadku C++ 11 funkcje wyrażenia regularnego są dostępne w bibliotece, np. "std :: regex_match (.....)" daje dokładne dopasowanie. Kod powinien wyglądać następująco:

#include <regex> 
..... 
std::string strnumber("-1.234e+01"); 
float number; 
if(regex_match(strnumber,std::regex("[+-]?[0-9]+[.]?[0-9]*([eE][-+]?[0-9]+)?")) 
number=std::stof(strnumber); 
else 
std::cout<<"error, string is not a valid number"; 
0

Niestety na wykopaniu temat, ale w trosce o kompletność i dlatego ten wątek to pierwszy mecz podczas wyszukiwania google ...

Jest możliwe użyć czegoś takiego:

ret = sscanf(string, "%d%n", &number, &idx); 
if (ret == 0 || string[idx] != '\0') 
    /* handle the error */ 

dyrektywy %n, który wydaje się być standard C według strony człowieka, zlicza liczbę znaków przetworzonych.

[Edytuj] sscanf nie wydaje się zapewniać sposobu na wykrycie przepełnienia, dlatego rodzina funkcji strtoX powinna być preferowana jako IMHO.