Λοιπόν, δες για παράδειγμα τον παρακάτω κώδικα, που σου ζητάει να γράψεις έναν αριθμό, τον διαβάζει ως string και κατόπιν τον μετατρέπει σε double πρώτα με την atof() και κατόπιν με την strtod().
- Κώδικας: Επιλογή όλων
#include <stdio.h>
#include <stdlib.h>
#define MAX_LINE 255+1
// -----------------------------------------------------------------------------------
char *s_get(char s[], int maxlen)
{
register int i;
for (i=0; (s[i]=getchar()) != '\n' && i < maxlen-1; i++)
; // for-loop with empty body
s[i] = '\0'; // null-terminate s
return s;
}
// -----------------------------------------------------------------------------------
int main( void )
{
char line[MAX_LINE];
double num = 0.0;
printf("Enter any real number: ");
fflush(stdin);
s_get( line, MAX_LINE);
printf("You entered the string: %s\n", line);
num = atof( line );
printf("\nConverted to double with atof() it gives: %g\n", num);
num = strtod( line, NULL );
printf("Converted to double with strtod() it gives: %g\n", num);
printf("\npress ENTER to exit..."); fflush(stdin); getchar();
exit(0);
}
Την s_get() στην έκανα επίτηδες να μη χρησιμοποιεί συμβολισμούς δεικτών, για να μη σε μπερδεύει. Αλλά είτε έτσι, είτε αλλιώς, χρησιμοποίησέ την ατόφια χωρίς να σε ενοχλεί ο εσωτερικό της κώδικας (είναι σαν να χρησιμοποιείς π.χ. την getline() του gcc, η οποία όμως δεν υπάρχει σε άλλους compilers).
Το ενδιαφέρον που παρουσιάζει ο παραπάνω κώδικας είναι πώς τόσο η
atof() όσο και η
strotod() παίρνουν το διαβασμένο
string line και το μετατρέπουν σε
double num. Αν το line περιείχε άκυρα πράματα (γράμματα, κλπ) τότε επιστρέφουν 0, αν περιείχε ανάμιξη αριθμών με γραμμάτων με τους αριθμούς μπροστά τότε μετατρέπονται μόνο οι αριθμοί, αλλιώς επιστρέφουν τον πραγματικό αριθμό που αντιστοιχεί σε αυτό που έγραψε ο χρήστης.
Μάλιστα, κατά την μετατροπή, αγνοούν τυχόν κενά στην αρχή του string. Επίσης, αν η γραμμή περιείχε περισσότερα από ένα πράγματα, δαιχωρισμένα με κενά, η μετατροπή λαμβάνει υπόψη της μονάχα το 1ο από αυτά.
Από τη στιγμή λοιπόν που και οι δυο αυτές συναρτήσεις ανήκουν στην στάνταρ βιβλιοθήκη της C (stdlib) μπορούμε να υποθέσουμε με ασφάλεια πως αυτή την συμπεριφορά την διατηρούν σε όλους τους compilers, σε όλες τις πλατφόρμες

Το πρόβλημα που υπάρχει είναι πως σε περίπτωση σφάλματος, επιστρέφουν την τιμή 0. Οπότε αν ο χρήστης είχε γράψει 0 στο string line, τότε δεν έχουμε τρόπο να ξέρουμε αν το 0 που μας επιστρέφει η μετατροπή είναι έγκυρη τιμή ή προϊόν σφάλματος.
Και με την atof() δεν έχουμε κιόλας τρόπο να το ελέγξουμε. Βέβαια στις περισσότερες περιπτώσεις ίσως να μη χρειάζεται καν να ελέγξουμε (και απλά να εχουμε γράψει στην τεκμηρίωση του προγράμματός μας πως τυχόν άκυρες τιμές στο line μετατρέπονται πάντα σε 0

Αν όμως θέλουμε όντως να ελέγξουμε, μπορούμε να το κάνουμε μέσω της strtod(), με χρήση του 2ου ορίσματός της (τώρα το έχουμε NULL στον κώδικα) σε συνδυασμό με την καθολική μεταβλητή
errno που ορίζεται στη στάνταρ βιβλιοθήκη:
<errno.h>.
Την μεταβλητή errno την χρησιμοποιούν όλες οι στάνταρ συναρτήσεις για να επισημάνουν τυχόν σφάλματα που προέκυψαν κατά την εκτέλεσή τους, με συγκεκριμένες τιμές που εκχωρούν στην errno (δες το παραπάνω link για αυτές τις τιμές.... ουσιαστικά είναι θετικές σταθερές, καθορισμένες με #define μέσα στο errno.h που ξεκινάνε πάντα με το γράμμα E). Το στάνταρ υποχρεώνει να έχουν καθοριστεί τουλάχιστον 3 τέτοιες τιμές:
- EDOM (σημαίνει: Mathematics argument out of domain of function)
- EILSEQ (σημαίνει: Illegal byte sequence.)
- ERANGE (σημαίνει: Result too large.)
οπότε αυτές υπάρχουν σε όλους τους compilers. Υπάρχουν και πολλές άλλες, ανάλογα τον compiler, αλλά τουλάχιστον οι 3 παραπάνω είναι στάνταρ σε όλους!
Ο πιο σίγουρος τρόπος να ελέγχουμε τη μεταβλητή errno είναι να την μηδενίζουμε πριν καλέσουμε την όποια συνάρτηση, και μετά το τέλος της συνάρτησης να ελέγχουμε αν έχει αλλάξει η τιμή του errno.
Επιστρέφοντας τώρα στην strtod(), αν διαβάσεις την τεκμηρίωσή της θα δεις πως για 2ο όρισμα αντί για NULL μπορούμε να της περάσουμε τη διεύθυνση ενός char pointer (δείκτης χαρακτήρων) ο οποίος αν η μετατροπή είναι επιτυχημένη τότε περιέχει τον μηδενικό χαρακτήρα ('\0').
Αλλιώς, εκτός από το 0 που επιστρέφει η συνάρτηση, βάζει και το 2ο όρισμά της να δείχνει είτε στο αρχικό string line (αν περιείχε μονάχα κενά ή/και άκυρα πράματα) είτε στο άκυρο μέρος του string line (π.χ. αν το line περιείχε: "123abcd" η συνάρτηση μετατρέπει κι επιστρέφει ως double το "123" και βάζει το 2ο όρισμα να δείχνει στο "abcd").
Επιπρόσθετα, αν τα έγκυρα πράματα του line αντιστοιχούν σε αριθμό που είναι έξω από το εύρος των αριθμών που μπορεί να απεικονίσει ο τύπος double, τότε πάει και βάζει στο errno την τιμή: ERANGE
Οπότε, για να ελέγξουμε αν η strtod() απέτυχε (ή αν... μισοπέτυχε

), μετά το κάλεσμά της ελέγχουμε δυο πράγματα:
- αν το errno ισούται με ERANGE
- αν ο πρώτος χαρακτήρας το 2ου ορίσματος της είναι διάφορος του '\0'
Όλα τα παραπάνω τα χρησιμοποιώ στην συνάρτηση: num_askuser() στον κώδικά μου στην 1η δημοσίευση, αλλά για να είναι πιο ευανάγνωστα, ας τα ενσωματώσουμε πιο απλοποιημένα στο παράδειγμα κώδικα αυτής εδώ της δημοσίευσης:
- Κώδικας: Επιλογή όλων
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#define MAX_LINE 255+1
// -----------------------------------------------------------------------------------
char *s_get(char s[], int maxlen)
{
register int i;
for (i=0; (s[i]=getchar()) != '\n' && i < maxlen-1; i++)
; // for-loop with empty body
s[i] = '\0'; // null-terminate s
return s;
}
// -----------------------------------------------------------------------------------
int main( void )
{
extern int errno; // defined in <errno.h>
char line[MAX_LINE];
char *dummy;
double num = 0.0;
printf("Enter any real number: ");
fflush(stdin);
s_get( line, MAX_LINE);
printf("You entered the string: %s\n", line);
num = atof( line );
printf("\nConverted to double with atof() it gives: %g\n", num);
errno = 0;
num = strtod( line, &dummy );
printf("\nConverted to double with strtod() it gives: %g\n", num);
if (errno == ERANGE)
puts("\t*** error: number too big or too small");
if ( *dummy != '\0')
printf("\t*** info: \"%s\" was invalid so it was ignored\n", dummy);
printf("\npress ENTER to exit..."); fflush(stdin); getchar();
exit(0);
}
ΥΓ. Η strtod() δέχεται ως έγκυρα και συγκεκριμένα strings, όπως π.χ. τα "infinity" και "inf" που συμβολίζουν το άπειρο. Για περισσότερες λεπτομέρειες διαβάστε την τεκμηρίωσή της.