Δημοσιεύτηκε: 29 Μαρ 2012, 17:07
Λοιπόν, η εν λόγω συνάρτηση είναι η readInt() η οποία χρησιμοποιεί την s_getsflushed() για να διαβάσει την κύρια είσοδο μονοκόμματα ως string, το οποίο κατόπιν μετατρέπει σε int μέσω της strtol().
Η υλοποίηση της s_getsflushed() είναι μια "υποχόνδρια" παραλλαγή εκείνης που έχω στην LIBS, με την έννοια πως δεν θεωρεί αυτονόητο πως το sizeof(char) ισούται με 1 byte (αρχικά μην αναλωθείς στον κώδικά αυτηνής, επικεντρώσου πρώτα στον κώδικα της readInt() και θεώρησε πως αντί της s_getsflushed() είχες π.χ. την fgets() ... απλώς η s_getsflushed() καθαρίζει και το stdin από τυχόν έξτρα χαρακτήρες
).
Σε ότι αφορά την readInt() την έβαλα να επιστρέφει 2 διαφορετικές τιμές σε περίπτωση σφάλματος, INT_MIN και INT_MAX, επισημαίνοντας έτσι 2 διαφορετικούς λόγους αποτυχίας (τους γράφω σε σχόλια). Επίσης, επειδή δεν υπάρχει στάνταρ συνάρτηση stroi() που να δουλεύει απευθείας πάνω σε int, αναγκαστικά χρησιμοποίησα την strtol() σε έναν τοπικό long int (ret) τον οποίο και κάνω cast σε int πριν τον επιστρέψω.
Το βασικό error-checking το κάνει ουσιαστικά η strtol() κι εγώ απλώς "προσαρμόζω" τις δικές της τιμές αποτυχίας στις 2 δικές μου (INT_MIN και INT_MAX) έχοντας μια πιο "συμπαγή προς χρήση" συνάρτηση. Προφανώς, οι τιμές INT_MIN και INT_MAX παύουν πλέον να θεωρούνται έγκυρες τιμές για τους int που διαβάζουμε με την readInt(), αλλά είναι ελάχιστο τίμημα μπροστά στην αυτοματοποίηση που μας προσφέρει
Στην main() δείχνω έναν πιθανό τρόπο χρήση της readInt() με αντίστοιχα μηνύματα σφάλματος. Προφανώς δεν είναι υποχρεωτικό να τσεκάρει κανείς συνεχώς την τιμή επιστροφής της readInt() σε κάθε της κλήση, καλό είναι να το κάνει όμως. Το ζουμί είναι πως είτε την τσεκάρει είτε όχι, δεν υπάρχει περίπτωση να κρασάρει το πρόγραμμα αν του δοθεί bad input.
Όλες αυτές οι re-usable συναρτήσεις που θα φτιάχνεις μπορούν να προστίθενται σε μια βιβλιοθήκη την οποία θα την καλείς σε κάθε σου πρόγραμμα. Αν βαριέσαι τη διαδικασία της βιβλιοθήκης (που όντως είναι σπαστική) μπορείς να βάλεις τους ορισμούς των συναρτήσεων σου μέσα στο "myextras.h" και απλά να το κάνεις include σε κάθε σου πρόγραμμα (κι ας μη συνηθίζεται να μπαίνουν σε header files οι ορισμοί συναρτήσεων).
Όταν φτιάξεις πολλές συναρτήσεις που παράλληλα θα έχουν δοκιμαστεί και σε διάφορες ασκήσεις/προγράμματα που θα γράφεις, μπορείς τότε να τις κάνεις μια βιβλιοθήκη
Η υλοποίηση της s_getsflushed() είναι μια "υποχόνδρια" παραλλαγή εκείνης που έχω στην LIBS, με την έννοια πως δεν θεωρεί αυτονόητο πως το sizeof(char) ισούται με 1 byte (αρχικά μην αναλωθείς στον κώδικά αυτηνής, επικεντρώσου πρώτα στον κώδικα της readInt() και θεώρησε πως αντί της s_getsflushed() είχες π.χ. την fgets() ... απλώς η s_getsflushed() καθαρίζει και το stdin από τυχόν έξτρα χαρακτήρες
Σε ότι αφορά την readInt() την έβαλα να επιστρέφει 2 διαφορετικές τιμές σε περίπτωση σφάλματος, INT_MIN και INT_MAX, επισημαίνοντας έτσι 2 διαφορετικούς λόγους αποτυχίας (τους γράφω σε σχόλια). Επίσης, επειδή δεν υπάρχει στάνταρ συνάρτηση stroi() που να δουλεύει απευθείας πάνω σε int, αναγκαστικά χρησιμοποίησα την strtol() σε έναν τοπικό long int (ret) τον οποίο και κάνω cast σε int πριν τον επιστρέψω.
Το βασικό error-checking το κάνει ουσιαστικά η strtol() κι εγώ απλώς "προσαρμόζω" τις δικές της τιμές αποτυχίας στις 2 δικές μου (INT_MIN και INT_MAX) έχοντας μια πιο "συμπαγή προς χρήση" συνάρτηση. Προφανώς, οι τιμές INT_MIN και INT_MAX παύουν πλέον να θεωρούνται έγκυρες τιμές για τους int που διαβάζουμε με την readInt(), αλλά είναι ελάχιστο τίμημα μπροστά στην αυτοματοποίηση που μας προσφέρει
Στην main() δείχνω έναν πιθανό τρόπο χρήση της readInt() με αντίστοιχα μηνύματα σφάλματος. Προφανώς δεν είναι υποχρεωτικό να τσεκάρει κανείς συνεχώς την τιμή επιστροφής της readInt() σε κάθε της κλήση, καλό είναι να το κάνει όμως. Το ζουμί είναι πως είτε την τσεκάρει είτε όχι, δεν υπάρχει περίπτωση να κρασάρει το πρόγραμμα αν του δοθεί bad input.
- Μορφοποιημένος Κώδικας: Επιλογή όλων
-
#include <stdio.h>
#include <stdlib.h> /* strtol() */
#include <limits.h> /* INT_MIN, INT_MAX */
/*********************************************************//**
* @brief Read into existing cstring s up to (ssize-1) chars from stdin or until
* ENTER is pressed, and null terminate it (removing ENTER if necessary).
* If more than (len-1) chars have been typed before the ENTER is pressed,
* they are ignored and they are removed from the stdin buffer.
*
* @return A pointer to the start of read s, or NULL on error.
*************************************************************
*/
char *s_getsflushed( char *s, const size_t ssize )
{
const size_t charsize = sizeof(char);/* don't assume 1 byte == sizeof(char) */
size_t i = 0;
/* sanity checks */
if ( !s )
return NULL;
if ( ssize < charsize )
return s;
/* read chars from stdin */
for (i=0; (s[i]=getc(stdin)) != '\n' && i < ssize-charsize; i += charsize)
; /* ... empty loop-body */
if ( s[i] != '\n' ) { /* ssize reached without '\n' */
s[i] = '\0'; /* ... null terminate s */
while (getchar() != '\n') /* ... flush remaining chars */
; /* ... ... empty loop-body */
}
else
s[i] = '\0';
return s;
}
/*********************************************************//**
* @brief Read safely an integer form stdin.
* @return The integer, or INT_MIN if input contained non-digits (including blanks),
* or INT_MAX in case of out of range integer value.
*************************************************************
*/
int readInt( void )
{
char input[ 255+1 ] = {'\0'};
char *tail = NULL;
long int ret = INT_MAX; /* INT_MAX & INT_MIN denote errors (see comments above) */
/* input failure? */
if ( !s_getsflushed(input, 255+1) )
return INT_MAX;
ret = strtol(input, &tail, 10 );
/* blank or non-digit chars in input? */
if ( '\0' != *tail || (tail == input && 0 == ret) )
return INT_MIN;
/* over/underflowed input? */
if ( ret > INT_MAX-1 || ret < INT_MIN+1 )
return INT_MAX;
/* everything ok */
return (int)ret;
}
/* ------------------------------------------------- */
int main( void )
{
int n;
printf( "Enter a valid integer: " );
n = readInt();
if ( INT_MAX == n )
puts("*** error: out of range integer!");
else if ( INT_MIN == n )
puts("*** error: blank or non-digit chars in input!");
else
printf( "%d was a valid input\n", n );
system("pause"); /* windows only */
return 0;
}
Όλες αυτές οι re-usable συναρτήσεις που θα φτιάχνεις μπορούν να προστίθενται σε μια βιβλιοθήκη την οποία θα την καλείς σε κάθε σου πρόγραμμα. Αν βαριέσαι τη διαδικασία της βιβλιοθήκης (που όντως είναι σπαστική) μπορείς να βάλεις τους ορισμούς των συναρτήσεων σου μέσα στο "myextras.h" και απλά να το κάνεις include σε κάθε σου πρόγραμμα (κι ας μη συνηθίζεται να μπαίνουν σε header files οι ορισμοί συναρτήσεων).
Όταν φτιάξεις πολλές συναρτήσεις που παράλληλα θα έχουν δοκιμαστεί και σε διάφορες ασκήσεις/προγράμματα που θα γράφεις, μπορείς τότε να τις κάνεις μια βιβλιοθήκη