Newsgroup: it.comp.lang.c
Titolo: Problema con atoi()

Ciao ragazzi,
ieri mi avete (giustamente) suggerito di usare la funzione atoi (abbinata a
fgets) per prendere un valore da tastiera e convertirlo in intero facendo un
controllo sui caratteri immessi (escludendo quindi le lettere etc...)
Il problema è che quando ad atoi() dai un carattere (ad esempio "ciao"), ti
ritorna 0 e io, in quel caso, ho printato il messaggio di errore. Ma facendo
così mi esclude anche il caso in cui il valore inserito è zero, e questa
cosa mi blocca.
Ad esempio, sto inserendo da tastiera il valore (che nel caso specifico è un
delay) e ho messo il controllo
if (!atoi(sec))
   {printf "Valore errato";
   return 0;}
Se scrivo ciao mamma, si ferma, e va bene.
Ma il valore dei secondi è 0, e quindi la variabile sec è zero, la considera
come un carattere e mi da "Valore errato"
Come potrei risolvere questo problema?
--------------------------------
Inviato via 
http://arianna.libero.it/usenet/

> Come potrei risolvere questo problema?
Forse ho risolto usando sscanf al posto di atoi()
Pare che sscanf restituisca 0 se il buffer di uscita ha un valore ma non è
"matchato" con il formato che è uno degli argomenti di ingresso. In questo
modo posso riconoscere se ha "convertito" o è uno 0 *originale. Che ne
pensate?


 ieri mi avete (giustamente) suggerito di usare la funzione atoi[...]
In realtà, io ti ho suggerito di usare strtol() o strtoul() che hanno
controllo d'errore rispetto ad atoi().
Leggendo i thread per intero, si evitano fatiche inutili ;-)
-- 
questo articolo e` stato inviato via web dal servizio gratuito 
http://www.newsland.it/news
 segnala gli abusi ad 
ab...@newsland.it

 per il tuo programma.
...quindi, visto che "ti serve" un controllo piu' pignolo, potresti fare 
come ti ho indicato controllando i "caratteri" di input - oppure (come 
ti ha suggerito Andrea) usare la strtol().
Comunque, anche con la strtol(), non e' semplicissimo ottenere un buon 
controllo di errore.
Usa, per esempio, qualcosa del genere:
===============================
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
long int_ok(char *bf, long *plRet)
{
         long lValue;
         char *pEndp = NULL;
         int bRet = 1;
         *plRet = 0L;
         errno = 0;
         lValue = strtol(bf, &pEndp, 10);
         if(errno == ERANGE)
                 bRet = 0; /* 'long int' fuori range */
         else if(!pEndp || pEndp == bf || (*pEndp != '\0' && 
!strchr("\r\n", *pEndp)))
                 bRet = 0; /* conversione parziale o non riuscita */
         if(bRet)
                 *plRet = lValue;
         return(bRet);
}
int main(void)
{
         char bf[256];
         long lVal = 0L;
         printf("Scrivi un num. intero: ");
         fgets(bf, sizeof(bf), stdin);
         if(!int_ok(bf, &lVal))
         {       fprintf(stderr, "Errore .....\n");
                 return -1;
         }
         printf("Val = %ld\n", lVal);
         return(0);
}
Ciao
-- 
Cybertoldo
Per rispondermi via email, sostituisci moc.liamg con 
gmail.com

> Leggendo i thread per intero, si evitano fatiche inutili ;-)
Hai ragione, in effetti avevo dato la precedenza ad atoi perchè *googlando*
era suggerita spesso, ma l'ho abbandonata. Per ora ho ottenuto risultati
migliori con sscanf ma domani dò un'occhiata a queste soluzioni e ottimizzo.
Grazie ancora a tutti :)

 controllo di errore.
Con strtol() è semplicissimo testare se la stringa iniziale era valida.
man strtol



Con sscanf() mi viene in mente qualcosa del genere, ma non ne ho 
verificato la portabilita' (potrebbero anche esserci errori - semi-tested):
#include <stdio.h>
#include <errno.h>
int main(void)
{
         char bf[256];
         int n, nVal = 0;
         char ch;
         printf("Scrivi un num. intero: ");
         fgets(bf, sizeof(bf), stdin);
         errno = 0;
         n = sscanf(bf, "%d%[^0-9\r\n]", &nVal, &ch);
         if(errno == ERANGE || n != 1)
         {       printf("Errore...");
                 return -1;
         }
         printf("Val = %d\n", nVal);
         return(0);


         else if(!pEndp || pEndp == bf || (*pEndp != '\0' && !strchr("\r\n", *pEndp)))
Ciao


il controllo su '\n' (e '\r')
Che non serve.

Andrea Laforgia ha scritto:

...allora devi prima "trimmare" il newline restituito dalla fgets(), se 
no non funziona


 verificato la portabilita' (potrebbero anche esserci errori - semi-tested):
Ops. Riguardandola meglio ora, infatti, c'era anche un errore grave 
(nella notte, insonne, si vedono meglio :) ).
La riscrivo tutta:
#include <stdio.h>
#include <string.h>
#include <errno.h>
int main(void)
{
         char bf[256], s[2];
         int n, nVal = 0;
         printf("Scrivi un num. intero: ");
         fgets(bf, sizeof(bf), stdin);
         errno = 0;
         n = sscanf(bf, "%d%1[^\n]", &nVal, s);
         if(errno != 0 || n != 1)
         {       printf("Errore...");
                 return -1;
         }
         printf("Val = %d\n", nVal);
         return(0);
}
Sorry.
PS: l'"errno" su overflow potrebbe non essere impostato (su gcc x linux 
funziona).



--
Giorgio Silvestri
DSP/Embedded/Real Time OS   Software Engineer