ANSI C: Διάσπαση Εισόδου σε Tokens & Μετατροπή σε Αριθμούς

...του ubuntu και έργων ΕΛ/ΛΑΚ (Έργα-Οδηγοί-Προτάσεις)

Συντονιστής: konnn

ANSI C: Διάσπαση Εισόδου σε Tokens & Μετατροπή σε Αριθμούς

Δημοσίευσηαπό migf1 » 25 Ιουν 2011, 17:09

Παραθέτω κώδικα για το διάβασμα μιας γραμμής από την κύρια είσοδο, διάσπασή της σε tokens (λέξεις), μετατροπή του κάθε token σε αριθμό και τύπωμα των αποτελεσμάτων στην οθόνη.

Ο κώδικας περιέχει κατατοπιστικότατα σχόλια στα Ελληνικά. Η main() περιέχει 2 συναρτήσεις μετατροπής (print_conv1simple() και print_conv2advanced() ) οι οποίες είναι ΑΠΕΝΕΡΓΟΠΟΙΗΜΕΝΕΣ μέσα σε σχόλια. ΕΝΕΡΓΟΠΟΙΗΣΤΕ όποια θέλετε να τρέξει (αφαιρέστε δηλαδή το // μπροστά από το όνομά της).

Απορίες, προτάσεις, επισημάνσεις πάντα ευπρόσδεκτα!

Σύνδεσμος για παρουσίαση με syntax-highlighting και κατέβασμα του κώδικα: http://ideone.com/FWutj

Κώδικας: Επιλογή όλων

/* -----------------------------------------------------------------------------------
* Παράδειγμα κώδικα σε C για...
* το διάβασμα μιας γραμμής από την κύρια είσοδο
* αποθήκευσή της σε ένα string (linebuf)
* διάσπασή της σε επί μέρους λέξεις (stokens)
* μετατροπή της κάθε λέξης σε διάφορους τύπους αριθμών (με και χωρίς έλεγχο)
* τύπωμα των αποτελεσμάτων στην οθόνη
*
* Για απλές μετατροπές ενεργοποιήστε τη συνάρτηση: print_conv1simple()
* Για προχωρημένες μετατροπές ενεργοποιήστε τη συνάρτηση: print_conv2advanced()
*
* ( και οι 2 παραπάνω συναρτήσεις βρίσκονται απενεργοποιημένες μέσα σε σχόλια
* στην συνάρτηση main() στις γραμμές 198 και 207, αντίστοιχα )
* -----------------------------------------------------------------------------------
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#define MAXLINE 255+1 // μέγιστο μήκος για τη γραμμή εισόδου
#define MAXTOKENS 3 // μέγιστο πλήθος tokens (λέξεων) ανά γραμμή

// Πρότυπα Συναρτήσεων

char *s_get(char */*s*/, int /*maxlen*/);
int s_tokenize(char */*s*/, char *[]/*tokens*/, int /*maxtokens*/, char */*delims*/);
void print_conv1simple( int /*ntokens*/, char *[]/*tokens*/ );
void print_conv2advanced( int /*ntokens*/, char *[]/*tokens*/ );


// -----------------------------------------------------------------------------------
// Διάβασμα του string s από την κύρια είσοδο, μέχρι να πατηθεί ENTER ή μέχρι να
// συμπληρωθούν maxlen-1 χαρακτήρες. Επιστρέφει το διαβασμένο s με μηδενισμένο τον
// τελευταίο χαρακτήρα (αν ήταν '\n' έχει αντικατασταθεί από '\0')
//
char *s_get(char *s, int maxlen)
{
register int i;

for (i=0; (s[i]=getchar()) != '\n' && i < maxlen-1; i++)
; // for-loop με κενό σώμα
s[i] = '\0'; // μηδενισμός τελικού χαρακτήρα

return s;
}

// -----------------------------------------------------------------------------------
// Διάσπαση του s σε έως maxtokens λέξεις, οι οποίες αποθηκεύονται στον πίνακα tokens[].
// Χαρακτήρες διαχωρισμού των tokens λογίζονται όσοι περιέχονται στο string delimiters.
// Επιστρέφει το πλήθος των tokens (λέξεων).
// ΣΗΜΑΝΤΙΚΟ: μετά το πέρας της συνάρτησης το αρχικο s έχει κατακερματιστεί (αν
// αυτό δεν είναι επιθυμητο, τότε θα πρέπει να περαστεί στην συνάρτηση
// κάποιο αντίγραφο του s).
//
int s_tokenize(char *s, char *tokens[], int maxtokens, char *delimiters)
{
register int i=0;

tokens[0] = strtok(s, delimiters); // αποθήκευση 1ου token
if (tokens[0] == NULL) // αποτυχία, πρόωρη έξοδος
return 0;
// αποθήκευση υπόλοιπων (έως maxtokens)
for (i=1; i < maxtokens && (tokens[i]=strtok(NULL, delimiters)) != NULL; i++)
; // for-loop με κενό σώμα

return i;
}

// -----------------------------------------------------------------------------------
// Απλή μετατροπή & τύπωμα των tokens ως int, long int και double, χρησιμοποιώντας
// την οικογένεια των στάνταρ συναρτήσεων ato?() ( ορίζονται στο <stdlib.h> )
// ΣΗΜΑΝΤΙΚΟ: Αυτές οι συναρτήσεις δεν δίνουν δυνατότητα ελέγχου για ενδεχόμενη
// αποτυχία της μετροπής. Αυτό το κάνουν οι συναρτήσεις strto?()
// ( δείτε παρακάτω την συνάρτηση: print_conv2advanced() )
//
void print_conv1simple( int ntokens, char *tokens[] )
{
int toi; // για αποθήκευση σε int
long int tol; // για αποθήκευση σε long int
double tod; // για αποθήκευση σε double
register int i; // για να διατρέξουμε τον tokens[]

for ( i=0; i < ntokens; i++ ) // όσο υπάρχουν tokens
{
// μετατροπές
toi = atoi( tokens[i] ); // μετατροπή σε int
tol = atol( tokens[i] ); // μετατροπή σε long int
tod = atof (tokens[i] ); // μετατροπή σε double

// τύπωμα αποτελεσμάτων
printf("Token #%d: \"%s\"\n", i+1, tokens[i]); // τύπωμα αρχικού token
// τύπωμα των μετατροπών
printf( "as int: %d, as long: %ld, as double: %g\n\n", toi, tol, tod );
}

return;
}

// -----------------------------------------------------------------------------------
// Προχωρημένη μετατροπή & τύπωμα των tokens ως double, long και unsigned long,
// χρησιμοποιώντας την οικογένεια των στάνταρ συναρτήσεων strto?() ( ορίζονται
// στο <stdlib.h> ).
//
// Oι συναρτήσεις αυτές χρησιμοποιούν την στάνταρ καθολική μεταβλητή errno (ορίζεται
// στο αρχείο <errno.h>) καθώς κι ένα προσωρινό string ( ptail ) ως 2ο όρισμά τους
// προκειμένου να σηματοδοτήσουν ενδεχόμενη αποτυχία της μετατροπής. Το 3ο τους όρισμα
// είναι η αριθμητική βάση για την μετατροπή (δεκαδική, οκταδική, κλπ).
//
// Υποστηρίζουν εντοπιότητες (locale), έλεγχο για λανθασμένη βάση και άλλα, τα οποία
// δεν τα χρησιμοποιώ εδώ.
//
// Για περισσότερες λεπτομέρειες διαβάστε την επίσημη τεκμηρίωσή τους στον compiler σας
// (εναλλακτικά: http://linux.die.net/man/3/strtol )
//
void print_conv2advanced( int ntokens, char *tokens[] )
{
extern int errno; // in <errno.h>

double tod; // για αποθήκευση σε double
long int tol; // για αποθήκευση σε long
unsigned long int toul; // για αποθήκευση σε unsigned long
char *ptail; // για έλεγχο περιττών χαρακτήρων
const int base = 10; // αριθμητική βάση για την μετατροπή
register int i; // για να διατρέξουμε τον tokens[]
char errmsg[MAXLINE] = ""; // βοηθητικό string για σφάλματα

for ( i=0; i < ntokens; i++ ) // όσο υπάρχουν tokens
{
*errmsg = '\0'; // εκκαθάριση του errmsg

// μετατροπή σε double
errno = 0; // εκκαθάριση του errno
tod = strtod( tokens[i], &ptail );
if ( *ptail != '\0' || errno == ERANGE) { // έλεγχος αποτυχίας
if ( tod == 0 )
strncpy(errmsg, "*** double failed ", MAXLINE);
else if (errno == ERANGE)
strncpy(errmsg, "+++ double overflowed ", MAXLINE);
else
strncpy(errmsg, "--- double fixed ", MAXLINE);
}

// μετατροπή σε long int
errno = 0; // εκκαθάριση του errno
tol = strtol( tokens[i], &ptail, base );
if ( *ptail != '\0' || errno == ERANGE) { // έλεγχος αποτυχίας
if (tol == 0)
strncat(errmsg, "*** long failed ", MAXLINE-1);
else if (errno == ERANGE)
strncpy(errmsg, "+++ long overflowed ", MAXLINE);
else
strncat(errmsg, "--- long fixed ", MAXLINE-1);
}

// μετατροπή σε unsigned long
errno = 0; // εκκαθάριση του errno
toul = strtoul(tokens[i], &ptail, base);
if ( *ptail != '\0' || errno == ERANGE) { // έλεγχος αποτυχίας
if (toul == 0)
strncat(errmsg, "*** unsigned long failed", MAXLINE-1);
else if (errno == ERANGE)
strncpy(errmsg, "+++ unsigned overflowed ", MAXLINE);
else
strncat(errmsg, "--- unsigned long fixed", MAXLINE-1);
}

// τύπωμα αποτελεσμάτων
printf("Token #%d: \"%s\"\n", i+1, tokens[i]); // τύπωμα αρχικού token
// τύπωμα των μετατροπών
printf( "as double: %g, as long: %ld, as unsigned long: %lu\n",
tod, tol, toul
);
// τύπωμα του ptail
printf("%s\n(ptail = \"%s\")\n\n", errmsg, ptail );
}

return;
}

// -----------------------------------------------------------------------------------
int main( void )
{
char linebuf[ MAXLINE ]; // για το διάβασμα της γραμμής ειδόδου
char *stokens[ MAXTOKENS ]; // για την αποθήκευση των tokens
int ntokens = 0; // το πλήθος των διαβασμένων tokens
register int i; // βοηθητικός μετρητής

// διάβασμα ολόκληρης της γραμμής εισόδου
printf("Enter up to %d words (tokens): ", MAXTOKENS);
s_get( linebuf, MAXLINE);

// διάσπαση σε έως MAXTOKENS λέξεις (διαχωριστικοί χαρακτήρες: space & tabs)
ntokens = s_tokenize( linebuf, stokens, MAXTOKENS, " \t");

// τύπωμα των λέξεων στις οποίες διασπάστηκε η γραμμή
printf("\n%d typed token(s):\n", ntokens);
for (i=0; i < ntokens; i++)
printf("\t%s\n", stokens[i] );
putchar('\n');

/*
* ΕΝΕΡΓΟΠΟΙΗΣΤΕ τη συνάρτηση που ακολουθεί για απλή μετατροπή των λέξεων
* σε αριθμούς (δηλαδή χωρίς έλεγχο κι ενημέρωση σε περίπτωση αποτυχίας)
*/

// απλή μετατροπή και τύπωμα των αποτελεσμάτων στην οθόνη
// print_conv1simple( ntokens, stokens ); // απλή μετατροπή

/*
* Εναλλακτικά, ΕΝΕΡΓΟΠΟΙΗΣΤΕ τη συνάρτηση που ακολουθεί για προχωρημένη
* μετατροπή των λέξεων σε αριθμούς (δηλαδή, με έλεγχο κι ενημέρωση σε
* περίπτωση αποτυχίας).
*/

// προχωρημένη μετατροπή και τύπωμά των αποτελεσμάτων στην οθόνη
// print_conv2advanced( ntokens, stokens ); // προχωρημένη μετατροπή

printf("\npress ENTER to exit..."); fflush(stdin); getchar();
exit( EXIT_SUCCESS);
}

Go under the hood with C: Pointers, Strings, Linked Lists
Άβαταρ μέλους
migf1
powerTUX
powerTUX
 
Δημοσιεύσεις: 2082
Εγγραφή: 03 Ιουν 2011, 16:32
Εκτύπωση

Επιστροφή στο Ανάπτυξη Λογισμικού / Αλγόριθμοι

cron