30/04/17 22:23
AldoBaldo
Ciao a te che leggi.
Oggi non sapevo che fare e ho messo insieme una paginata di roba in previsione di un futuro ed ipotetico uso personale. Probabilmente si tratta della classica "reinvenzione della ruota", però sapete che son fatto così e che mi diverto a scrivere 'ste cose. Non escludo che si tratti pure di un modo improprio di ottenere il risultato.
Detto questo... potrebbe essere utile aggiungere questi file alla sezione "esempi" dei programmi presenti su Pierotofy? Se sì, aggiungo; se no, tengo per me. Graditi opinioni e, se non significano "rivoluzionare" tutto (non ne vale la pena, credo), suggerimenti su come migliorare il codice. Meno gradito, ma comunque accettato, un eventuale "ma piantala lì!".
Tre file. Il primo: numeri_e_stringhe.h
Il secondo: numeri_e_stringhe.c
Il terzo, con un programmino d'esempio d'uso: main.c
Oggi non sapevo che fare e ho messo insieme una paginata di roba in previsione di un futuro ed ipotetico uso personale. Probabilmente si tratta della classica "reinvenzione della ruota", però sapete che son fatto così e che mi diverto a scrivere 'ste cose. Non escludo che si tratti pure di un modo improprio di ottenere il risultato.
Detto questo... potrebbe essere utile aggiungere questi file alla sezione "esempi" dei programmi presenti su Pierotofy? Se sì, aggiungo; se no, tengo per me. Graditi opinioni e, se non significano "rivoluzionare" tutto (non ne vale la pena, credo), suggerimenti su come migliorare il codice. Meno gradito, ma comunque accettato, un eventuale "ma piantala lì!".
Tre file. Il primo: numeri_e_stringhe.h
/**============================================================================= NUMERI E STRINGHE v1.0 - aprile 2017 Gestisce valori compresi tra 9223372036854775807 e -9223372036854775807 (interi a 64 bit) con base compresa tra 2 e 36. =============================================================================**/ #ifndef NUMERI_E_STRINGHE_H_INCLUDED #define NUMERI_E_STRINGHE_H_INCLUDED /** ===> INCLUSIONI <========================================================**/ #include <stdio.h> #include <stdlib.h> #include <stdint.h> /* per usare i tipi uint64_t, int64_t, int16_t e int8_t */ #include <stdbool.h> /* per usare il tipo bool */ #include <ctype.h> /* per usare tolower() e toupper() */ /** ===> MACRO <============================================================ **/ #define NS_USACHIEDINUMERO /* da definire per usare NS_chiedi_numero() */ #define NS_CIFRANONVALIDA -1 /* restituito come errore da NS_cifra() */ #define NS_MINBASE 2 /* la base non puo' essere inferiore */ #define NS_MAXBASE 36 /* la base non puo' essere superiore */ #define NS_MINVAL -9223372036854775807LL #define NS_MAXVAL 9223372036854775807LL #define NS_DIMBUFFNUM 68 /* le dimensioni del buffer per la rappresentazione dei numeri a 64 bit sotto forma di stringa */ /** ===> PROTOTIPI DELLE FUNZIONI <========================================= **/ #ifdef NS_USACHIEDINUMERO int64_t NS_chiedi_numero( int64_t minimo, int64_t massimo, int8_t base ); #endif // NS_USACHIEDINUMERO int64_t NS_sn( const char *s, int16_t *qCifre, int8_t base ); char *NS_ns( int64_t n, char *buff, int8_t base ); int8_t NS_cifra( char c, int8_t base ); void NS_usa_cifre_maiuscole( bool usa_cifre_maiuscole ); #endif /* NUMERI_E_STRINGHE_H_INCLUDED */
Il secondo: numeri_e_stringhe.c
/**============================================================================= NUMERI E STRINGHE v1.0 - aprile 2017 Gestisce valori compresi tra 9223372036854775807 e -9223372036854775807 (interi a 64 bit) con base compresa tra 2 e 36. =============================================================================**/ #include "numeri_e_stringhe.h" /** ===> COSTANTI <========================================================= **/ static const char *NS_Cifre = "0123456789abcdefghijklmnopqrstuvwxyz"; static const char NS_SegnoNegativo = '-'; static const char *NS_StrErrBaseNonValida = "(la base eccede i limiti)"; /** ===> VARIABILI GLOBALI PER QUESTO FILE <================================ **/ bool NS_usa_maiuscole = false; /** ===> DEFINIZIONE DELLE FUNZIONI <======================================= **/ /*============================================================================== Chiede l'immissione in console di un numero intero compreso tra min e max, dove min non puo' essere inferiore a NS_MINVAL e max non puo' essere superiore a NS_MAXVAL. Restituisce il numero immesso come valore di ritorno di tipo int64_t. La funzione insiste nella sua richiesta fintanto che non viene immesso un dato accettabile, quindi ritorna. Per usare questa funzione occorre che sia definita la macro NS_USACHIEDINUMERO. ==============================================================================*/ #ifdef NS_USACHIEDINUMERO int64_t NS_chiedi_numero( int64_t min, int64_t max, int8_t base ) { char buff[NS_DIMBUFFNUM]; /* 64 cifre + il segno negativo */ bool ripeti, pp = true; /* pp = primo passaggio */ int16_t l, qCifre; int64_t n; do { if( !pp ) /* se non e' il primo passaggio... */ printf( "Input non valido, riprova: " ); else pp = false; /* se e' il primo passaggio */ fgets( buff, NS_DIMBUFFNUM, stdin ); /* riceviamo l'input */ for( l=0; buff[l]; ++l ); /* la lunghezza dell'input */ if( buff[l-1] == '\n' ) { n = NS_sn( buff, &qCifre, base ); /* converte in int64_t */ ripeti = n<min || n>max || qCifre==0; } else { /* se l'ultimo carattere non e' '\n' significa che l'input e' stato troncato, il che non va bene; eliminiamo i caratteri ancora "pendenti" */ while( getchar() != '\n' ); ripeti = true; /* la condizione per ripetere */ } } while( ripeti ); return n; /* restituisce il numero immesso */ } #endif // NS_USACHIEDINUMERO /*============================================================================== Converte una stringa nel numero intero corrispondente, secondo la base di numerazione specificata. Se la stringa inizia con caratteri non idonei a rappresentare le cifre del sistema di numerazione specificato, quei caratteri non vengono considerati. Se la stringa contiene una rappresentazione numerica valida, la funzione restituisce il valore ricavato dalla stringa (in formato int64_t) e immette la quantita' delle cifre riconosciute all'indirizzo indicato dal parametro qCifre. Se la stringa NON contiene una rappresentazione numerica valida, la funzione restituisce 0 e immette 0 anche all'indirizzo indicato dal parametro qCifre. Se il parametro qCifre e' un puntatore NULL, la funzione non puo' fornire informazioni circa la quantita' di cifre riconosciute, rendendo di fatto impossibile al chiamante sapere se la conversione e' stata portata a termine correttamente oppure no. ==============================================================================*/ int64_t NS_sn( const char *s, int16_t *qCifre, int8_t base ) { int16_t totCifre = 0; /* si presuppone il fallimento */ int64_t r = 0; /* il risultato dell'operazione */ /* se i parametri sono accettabili, analizziamo la stringa */ if( s != NULL && (base>=NS_MINBASE&&base<=NS_MAXBASE) ) { const char *p = s; /* puntatore ausiliario */ bool negativo; /* scartiamo tutti i caratteri non numerici iniziali */ while( !(NS_cifra(*p,base)>=0||*p==NS_SegnoNegativo) && *p!='Ciao a te che leggi.
Oggi non sapevo che fare e ho messo insieme una paginata di roba in previsione di un futuro ed ipotetico uso personale. Probabilmente si tratta della classica "reinvenzione della ruota", però sapete che son fatto così e che mi diverto a scrivere 'ste cose. Non escludo che si tratti pure di un modo improprio di ottenere il risultato.
Detto questo... potrebbe essere utile aggiungere questi file alla sezione "esempi" dei programmi presenti su Pierotofy? Se sì, aggiungo; se no, tengo per me. Graditi opinioni e, se non significano "rivoluzionare" tutto (non ne vale la pena, credo), suggerimenti su come migliorare il codice. Meno gradito, ma comunque accettato, un eventuale "ma piantala lì!".
Tre file. Il primo: numeri_e_stringhe.h
/**============================================================================= NUMERI E STRINGHE v1.0 - aprile 2017 Gestisce valori compresi tra 9223372036854775807 e -9223372036854775807 (interi a 64 bit) con base compresa tra 2 e 36. =============================================================================**/ #ifndef NUMERI_E_STRINGHE_H_INCLUDED #define NUMERI_E_STRINGHE_H_INCLUDED /** ===> INCLUSIONI <========================================================**/ #include <stdio.h> #include <stdlib.h> #include <stdint.h> /* per usare i tipi uint64_t, int64_t, int16_t e int8_t */ #include <stdbool.h> /* per usare il tipo bool */ #include <ctype.h> /* per usare tolower() e toupper() */ /** ===> MACRO <============================================================ **/ #define NS_USACHIEDINUMERO /* da definire per usare NS_chiedi_numero() */ #define NS_CIFRANONVALIDA -1 /* restituito come errore da NS_cifra() */ #define NS_MINBASE 2 /* la base non puo' essere inferiore */ #define NS_MAXBASE 36 /* la base non puo' essere superiore */ #define NS_MINVAL -9223372036854775807LL #define NS_MAXVAL 9223372036854775807LL #define NS_DIMBUFFNUM 68 /* le dimensioni del buffer per la rappresentazione dei numeri a 64 bit sotto forma di stringa */ /** ===> PROTOTIPI DELLE FUNZIONI <========================================= **/ #ifdef NS_USACHIEDINUMERO int64_t NS_chiedi_numero( int64_t minimo, int64_t massimo, int8_t base ); #endif // NS_USACHIEDINUMERO int64_t NS_sn( const char *s, int16_t *qCifre, int8_t base ); char *NS_ns( int64_t n, char *buff, int8_t base ); int8_t NS_cifra( char c, int8_t base ); void NS_usa_cifre_maiuscole( bool usa_cifre_maiuscole ); #endif /* NUMERI_E_STRINGHE_H_INCLUDED */
Il secondo: numeri_e_stringhe.c
/**============================================================================= NUMERI E STRINGHE v1.0 - aprile 2017 Gestisce valori compresi tra 9223372036854775807 e -9223372036854775807 (interi a 64 bit) con base compresa tra 2 e 36. =============================================================================**/ #include "numeri_e_stringhe.h" /** ===> COSTANTI <========================================================= **/ static const char *NS_Cifre = "0123456789abcdefghijklmnopqrstuvwxyz"; static const char NS_SegnoNegativo = '-'; static const char *NS_StrErrBaseNonValida = "(la base eccede i limiti)"; /** ===> VARIABILI GLOBALI PER QUESTO FILE <================================ **/ bool NS_usa_maiuscole = false; /** ===> DEFINIZIONE DELLE FUNZIONI <======================================= **/ /*============================================================================== Chiede l'immissione in console di un numero intero compreso tra min e max, dove min non puo' essere inferiore a NS_MINVAL e max non puo' essere superiore a NS_MAXVAL. Restituisce il numero immesso come valore di ritorno di tipo int64_t. La funzione insiste nella sua richiesta fintanto che non viene immesso un dato accettabile, quindi ritorna. Per usare questa funzione occorre che sia definita la macro NS_USACHIEDINUMERO. ==============================================================================*/ #ifdef NS_USACHIEDINUMERO int64_t NS_chiedi_numero( int64_t min, int64_t max, int8_t base ) { char buff[NS_DIMBUFFNUM]; /* 64 cifre + il segno negativo */ bool ripeti, pp = true; /* pp = primo passaggio */ int16_t l, qCifre; int64_t n; do { if( !pp ) /* se non e' il primo passaggio... */ printf( "Input non valido, riprova: " ); else pp = false; /* se e' il primo passaggio */ fgets( buff, NS_DIMBUFFNUM, stdin ); /* riceviamo l'input */ for( l=0; buff[l]; ++l ); /* la lunghezza dell'input */ if( buff[l-1] == '\n' ) { n = NS_sn( buff, &qCifre, base ); /* converte in int64_t */ ripeti = n<min || n>max || qCifre==0; } else { /* se l'ultimo carattere non e' '\n' significa che l'input e' stato troncato, il che non va bene; eliminiamo i caratteri ancora "pendenti" */ while( getchar() != '\n' ); ripeti = true; /* la condizione per ripetere */ } } while( ripeti ); return n; /* restituisce il numero immesso */ } #endif // NS_USACHIEDINUMERO /*============================================================================== Converte una stringa nel numero intero corrispondente, secondo la base di numerazione specificata. Se la stringa inizia con caratteri non idonei a rappresentare le cifre del sistema di numerazione specificato, quei caratteri non vengono considerati. Se la stringa contiene una rappresentazione numerica valida, la funzione restituisce il valore ricavato dalla stringa (in formato int64_t) e immette la quantita' delle cifre riconosciute all'indirizzo indicato dal parametro qCifre. Se la stringa NON contiene una rappresentazione numerica valida, la funzione restituisce 0 e immette 0 anche all'indirizzo indicato dal parametro qCifre. Se il parametro qCifre e' un puntatore NULL, la funzione non puo' fornire informazioni circa la quantita' di cifre riconosciute, rendendo di fatto impossibile al chiamante sapere se la conversione e' stata portata a termine correttamente oppure no. ==============================================================================*/ int64_t NS_sn( const char *s, int16_t *qCifre, int8_t base ) { int16_t totCifre = 0; /* si presuppone il fallimento */ int64_t r = 0; /* il risultato dell'operazione */ /* se i parametri sono accettabili, analizziamo la stringa */ if( s != NULL && (base>=NS_MINBASE&&base<=NS_MAXBASE) ) { const char *p = s; /* puntatore ausiliario */ bool negativo; /* scartiamo tutti i caratteri non numerici iniziali */ while( !(NS_cifra(*p,base)>=0||*p==NS_SegnoNegativo) && *p!='{parsed_message}' ) ++p; if( *p != '{parsed_message}' ) { /* se sono rimasti caratteri */ int16_t i, j; /* contatori */ if( (negativo=*p==NS_SegnoNegativo) ) ++p; /* saltiamo il segno */ while( *p == '0' ) ++p; /* saltiamo gli zeri iniziali */ while( NS_cifra(p[totCifre],base) >= 0 ) /* contiamo le cifre */ ++totCifre; if( totCifre > 0 ) { /* se ci sono cifre valide, calcoliamo */ for( i=totCifre; i>0; --i ) { /* partendo dal fondo */ int64_t tmp=1; for( j=0; j<totCifre-i; ++j ) tmp *= base; /* potenza */ r += NS_cifra(p[i-1],base) * tmp; } if( negativo ) r = -r; /* se era negativo, ripristiniamo */ } } } if( qCifre != NULL ) *qCifre = totCifre; /* solo se non e' NULL */ return r; } /*============================================================================== Converte un numero intero in formato int64_t nella sua rappresentazione in forma di stringa, secondo la base di numerazione specificata. Se il parametro buff e' un puntatore valido, la funzione impiega lo spazio di memoria puntato per collocarvi la stringa risultante dalla conversione. Spetta al chiamante assicurarsi che buff punti a uno spazio di memoria sufficiente per contenere la stringa (il caso piu' "esigente" riguarda il valore a 64 bit massimo in formato binario: 64 caratteri piu' il terminatore, eventualmente con l'aggiunta d'un segno negativo -- 66 caratteri in tutto). Se il parametro buff e' NULL, la funzione inserisce la stringa risultante in un buffer statico costituito da NS_DIMBUFFNUM char. Ovviamente, ogni nuova chiamata alla funzione sovrascrive il buffer cancellando l'esito delle eventuali conversioni precedenti. La funzione fallisce (restituendo una stringa che descrive l'errore) solo se il parametro base eccede i limiti consentiti da NS_MINBASE e NS_MAXBASE. ==============================================================================*/ char *NS_ns( int64_t n, char *buff, int8_t base ) { static char sBuff[NS_DIMBUFFNUM]; /* max 64 cifre + il segno negativo */ uint64_t un; /* necessario per il valore negativo minimo */ int16_t i; /* deve poter contenere almeno la lunghezza della stringa */ /* se il parametro buff e' nullo, usiamo il buffer statico */ if( buff == NULL ) buff = sBuff; if( base>=NS_MINBASE && base<=NS_MAXBASE ) { int16_t l, lMezzi; bool negativo; int8_t cifra; negativo = n < 0; /* memorizziamo il segno */ un = negativo ? -n : n; /* usiamo sempre un valore positivo */ /* N.B. la stringa viene generata "all'indietro" */ for( l=0; un!=0; ++l ) { cifra = un%base; buff[l] = NS_Cifre[cifra]; un /= base; } if( negativo ) buff[l++] = NS_SegnoNegativo; /* apponiamo il segno? */ buff[l] = '{parsed_message}'; /* terminiamo la stringa */ /* "rovesciamo" la stringa (generata all'indietro) */ for( lMezzi=l/2, i=0; i<lMezzi; ++i ) { char aux = buff[i]; buff[i] = buff[l-i-1]; buff[l-i-1] = aux; } /* se necessario, usiamo le cifre in caratteri maiuscoli */ if( NS_usa_maiuscole ) for( i=0; i<l; ++i ) buff[i] = toupper( buff[i] ); } else { /* la base eccede i limiti imposti da NS_MINBASE e NS_MAXBASE */ for( i=0; NS_StrErrBaseNonValida[i]; ++i ) buff[i] = NS_StrErrBaseNonValida[i]; /* copiamo l'errore */ buff[i] = '{parsed_message}'; /* terminiamo la stringa */ } return buff; /* restituiamo un puntatore al buffer effettivamente usato */ } /*============================================================================== Verifica se c corrisponde a una delle cifre valide nel sistema di numerazione che impiega la base specificata dal parametro base. Se c e' una cifra valida restituisce il valore della cifra; se c NON e' una cifra valida restituisce NS_CIFRANONVALIDA. ==============================================================================*/ int8_t NS_cifra( char c, int8_t base ) { c = tolower(c); int8_t i; if( base>=NS_MINBASE && base<=NS_MAXBASE ) for( i=0; i<base; ++i ) if( c == NS_Cifre[i] ) return i; return NS_CIFRANONVALIDA; } /*============================================================================== Imposta una variabile statica che fa si' che le altre funzioni impieghino (nelle chiamate successive) caratteri maiuscoli o minuscoli come cifre per quei sistemi di numerazione che richiedono l'uso di oltre 10 cifre. ==============================================================================*/ void NS_usa_cifre_maiuscole( bool usa_cifre_maiuscole ) { NS_usa_maiuscole = usa_cifre_maiuscole; }
Il terzo, con un programmino d'esempio d'uso: main.c
/**============================================================================= Programma d'esempio per numeri_e_stringhe. =============================================================================**/ #include <string.h> #include "numeri_e_stringhe.h" int main() { char buff[NS_DIMBUFFNUM]; int8_t b1, b2; int64_t n; bool ripeti; printf( "CONVERTE LA BASE DI NUMERAZIONE DI UN NUMERO DATO\n" ); printf( "=================================================\n\n" ); do { printf( "Immetti la base di numerazione iniziale (%d-%d): ", NS_MINBASE, NS_MAXBASE ); b1 = NS_chiedi_numero( NS_MINBASE, NS_MAXBASE, 10 ); printf( "Immetti la base di numerazione di destinazione (%d-%d): ", NS_MINBASE, NS_MAXBASE ); b2 = NS_chiedi_numero( NS_MINBASE, NS_MAXBASE, 10 ); printf( "Immetti il numero da convertire: " ); n = NS_chiedi_numero( NS_MINVAL, NS_MAXVAL, b1 ); printf( "\n base %2d: %s\n", b1, NS_ns(n,buff,b1) ); printf( " base %2d: %s\n\n", b2, NS_ns(n,buff,b2) ); printf( "Vuoi effettuare un'altra conversione? " "(\"s\" per continuare) " ); fgets( buff, NS_DIMBUFFNUM, stdin ); ripeti = tolower(*buff) != 'n'; /* se necessario, "svuota" stdin */ while( buff[strlen(buff)-1] != '\n' ) fgets( buff, NS_DIMBUFFNUM, stdin ); printf( "\n\n" ); } while( ripeti ); return 0; }' ) ++p; if( *p != 'Ciao a te che leggi.
Oggi non sapevo che fare e ho messo insieme una paginata di roba in previsione di un futuro ed ipotetico uso personale. Probabilmente si tratta della classica "reinvenzione della ruota", però sapete che son fatto così e che mi diverto a scrivere 'ste cose. Non escludo che si tratti pure di un modo improprio di ottenere il risultato.
Detto questo... potrebbe essere utile aggiungere questi file alla sezione "esempi" dei programmi presenti su Pierotofy? Se sì, aggiungo; se no, tengo per me. Graditi opinioni e, se non significano "rivoluzionare" tutto (non ne vale la pena, credo), suggerimenti su come migliorare il codice. Meno gradito, ma comunque accettato, un eventuale "ma piantala lì!".
Tre file. Il primo: numeri_e_stringhe.h
/**============================================================================= NUMERI E STRINGHE v1.0 - aprile 2017 Gestisce valori compresi tra 9223372036854775807 e -9223372036854775807 (interi a 64 bit) con base compresa tra 2 e 36. =============================================================================**/ #ifndef NUMERI_E_STRINGHE_H_INCLUDED #define NUMERI_E_STRINGHE_H_INCLUDED /** ===> INCLUSIONI <========================================================**/ #include <stdio.h> #include <stdlib.h> #include <stdint.h> /* per usare i tipi uint64_t, int64_t, int16_t e int8_t */ #include <stdbool.h> /* per usare il tipo bool */ #include <ctype.h> /* per usare tolower() e toupper() */ /** ===> MACRO <============================================================ **/ #define NS_USACHIEDINUMERO /* da definire per usare NS_chiedi_numero() */ #define NS_CIFRANONVALIDA -1 /* restituito come errore da NS_cifra() */ #define NS_MINBASE 2 /* la base non puo' essere inferiore */ #define NS_MAXBASE 36 /* la base non puo' essere superiore */ #define NS_MINVAL -9223372036854775807LL #define NS_MAXVAL 9223372036854775807LL #define NS_DIMBUFFNUM 68 /* le dimensioni del buffer per la rappresentazione dei numeri a 64 bit sotto forma di stringa */ /** ===> PROTOTIPI DELLE FUNZIONI <========================================= **/ #ifdef NS_USACHIEDINUMERO int64_t NS_chiedi_numero( int64_t minimo, int64_t massimo, int8_t base ); #endif // NS_USACHIEDINUMERO int64_t NS_sn( const char *s, int16_t *qCifre, int8_t base ); char *NS_ns( int64_t n, char *buff, int8_t base ); int8_t NS_cifra( char c, int8_t base ); void NS_usa_cifre_maiuscole( bool usa_cifre_maiuscole ); #endif /* NUMERI_E_STRINGHE_H_INCLUDED */
Il secondo: numeri_e_stringhe.c
/**============================================================================= NUMERI E STRINGHE v1.0 - aprile 2017 Gestisce valori compresi tra 9223372036854775807 e -9223372036854775807 (interi a 64 bit) con base compresa tra 2 e 36. =============================================================================**/ #include "numeri_e_stringhe.h" /** ===> COSTANTI <========================================================= **/ static const char *NS_Cifre = "0123456789abcdefghijklmnopqrstuvwxyz"; static const char NS_SegnoNegativo = '-'; static const char *NS_StrErrBaseNonValida = "(la base eccede i limiti)"; /** ===> VARIABILI GLOBALI PER QUESTO FILE <================================ **/ bool NS_usa_maiuscole = false; /** ===> DEFINIZIONE DELLE FUNZIONI <======================================= **/ /*============================================================================== Chiede l'immissione in console di un numero intero compreso tra min e max, dove min non puo' essere inferiore a NS_MINVAL e max non puo' essere superiore a NS_MAXVAL. Restituisce il numero immesso come valore di ritorno di tipo int64_t. La funzione insiste nella sua richiesta fintanto che non viene immesso un dato accettabile, quindi ritorna. Per usare questa funzione occorre che sia definita la macro NS_USACHIEDINUMERO. ==============================================================================*/ #ifdef NS_USACHIEDINUMERO int64_t NS_chiedi_numero( int64_t min, int64_t max, int8_t base ) { char buff[NS_DIMBUFFNUM]; /* 64 cifre + il segno negativo */ bool ripeti, pp = true; /* pp = primo passaggio */ int16_t l, qCifre; int64_t n; do { if( !pp ) /* se non e' il primo passaggio... */ printf( "Input non valido, riprova: " ); else pp = false; /* se e' il primo passaggio */ fgets( buff, NS_DIMBUFFNUM, stdin ); /* riceviamo l'input */ for( l=0; buff[l]; ++l ); /* la lunghezza dell'input */ if( buff[l-1] == '\n' ) { n = NS_sn( buff, &qCifre, base ); /* converte in int64_t */ ripeti = n<min || n>max || qCifre==0; } else { /* se l'ultimo carattere non e' '\n' significa che l'input e' stato troncato, il che non va bene; eliminiamo i caratteri ancora "pendenti" */ while( getchar() != '\n' ); ripeti = true; /* la condizione per ripetere */ } } while( ripeti ); return n; /* restituisce il numero immesso */ } #endif // NS_USACHIEDINUMERO /*============================================================================== Converte una stringa nel numero intero corrispondente, secondo la base di numerazione specificata. Se la stringa inizia con caratteri non idonei a rappresentare le cifre del sistema di numerazione specificato, quei caratteri non vengono considerati. Se la stringa contiene una rappresentazione numerica valida, la funzione restituisce il valore ricavato dalla stringa (in formato int64_t) e immette la quantita' delle cifre riconosciute all'indirizzo indicato dal parametro qCifre. Se la stringa NON contiene una rappresentazione numerica valida, la funzione restituisce 0 e immette 0 anche all'indirizzo indicato dal parametro qCifre. Se il parametro qCifre e' un puntatore NULL, la funzione non puo' fornire informazioni circa la quantita' di cifre riconosciute, rendendo di fatto impossibile al chiamante sapere se la conversione e' stata portata a termine correttamente oppure no. ==============================================================================*/ int64_t NS_sn( const char *s, int16_t *qCifre, int8_t base ) { int16_t totCifre = 0; /* si presuppone il fallimento */ int64_t r = 0; /* il risultato dell'operazione */ /* se i parametri sono accettabili, analizziamo la stringa */ if( s != NULL && (base>=NS_MINBASE&&base<=NS_MAXBASE) ) { const char *p = s; /* puntatore ausiliario */ bool negativo; /* scartiamo tutti i caratteri non numerici iniziali */ while( !(NS_cifra(*p,base)>=0||*p==NS_SegnoNegativo) && *p!='{parsed_message}' ) ++p; if( *p != '{parsed_message}' ) { /* se sono rimasti caratteri */ int16_t i, j; /* contatori */ if( (negativo=*p==NS_SegnoNegativo) ) ++p; /* saltiamo il segno */ while( *p == '0' ) ++p; /* saltiamo gli zeri iniziali */ while( NS_cifra(p[totCifre],base) >= 0 ) /* contiamo le cifre */ ++totCifre; if( totCifre > 0 ) { /* se ci sono cifre valide, calcoliamo */ for( i=totCifre; i>0; --i ) { /* partendo dal fondo */ int64_t tmp=1; for( j=0; j<totCifre-i; ++j ) tmp *= base; /* potenza */ r += NS_cifra(p[i-1],base) * tmp; } if( negativo ) r = -r; /* se era negativo, ripristiniamo */ } } } if( qCifre != NULL ) *qCifre = totCifre; /* solo se non e' NULL */ return r; } /*============================================================================== Converte un numero intero in formato int64_t nella sua rappresentazione in forma di stringa, secondo la base di numerazione specificata. Se il parametro buff e' un puntatore valido, la funzione impiega lo spazio di memoria puntato per collocarvi la stringa risultante dalla conversione. Spetta al chiamante assicurarsi che buff punti a uno spazio di memoria sufficiente per contenere la stringa (il caso piu' "esigente" riguarda il valore a 64 bit massimo in formato binario: 64 caratteri piu' il terminatore, eventualmente con l'aggiunta d'un segno negativo -- 66 caratteri in tutto). Se il parametro buff e' NULL, la funzione inserisce la stringa risultante in un buffer statico costituito da NS_DIMBUFFNUM char. Ovviamente, ogni nuova chiamata alla funzione sovrascrive il buffer cancellando l'esito delle eventuali conversioni precedenti. La funzione fallisce (restituendo una stringa che descrive l'errore) solo se il parametro base eccede i limiti consentiti da NS_MINBASE e NS_MAXBASE. ==============================================================================*/ char *NS_ns( int64_t n, char *buff, int8_t base ) { static char sBuff[NS_DIMBUFFNUM]; /* max 64 cifre + il segno negativo */ uint64_t un; /* necessario per il valore negativo minimo */ int16_t i; /* deve poter contenere almeno la lunghezza della stringa */ /* se il parametro buff e' nullo, usiamo il buffer statico */ if( buff == NULL ) buff = sBuff; if( base>=NS_MINBASE && base<=NS_MAXBASE ) { int16_t l, lMezzi; bool negativo; int8_t cifra; negativo = n < 0; /* memorizziamo il segno */ un = negativo ? -n : n; /* usiamo sempre un valore positivo */ /* N.B. la stringa viene generata "all'indietro" */ for( l=0; un!=0; ++l ) { cifra = un%base; buff[l] = NS_Cifre[cifra]; un /= base; } if( negativo ) buff[l++] = NS_SegnoNegativo; /* apponiamo il segno? */ buff[l] = '{parsed_message}'; /* terminiamo la stringa */ /* "rovesciamo" la stringa (generata all'indietro) */ for( lMezzi=l/2, i=0; i<lMezzi; ++i ) { char aux = buff[i]; buff[i] = buff[l-i-1]; buff[l-i-1] = aux; } /* se necessario, usiamo le cifre in caratteri maiuscoli */ if( NS_usa_maiuscole ) for( i=0; i<l; ++i ) buff[i] = toupper( buff[i] ); } else { /* la base eccede i limiti imposti da NS_MINBASE e NS_MAXBASE */ for( i=0; NS_StrErrBaseNonValida[i]; ++i ) buff[i] = NS_StrErrBaseNonValida[i]; /* copiamo l'errore */ buff[i] = '{parsed_message}'; /* terminiamo la stringa */ } return buff; /* restituiamo un puntatore al buffer effettivamente usato */ } /*============================================================================== Verifica se c corrisponde a una delle cifre valide nel sistema di numerazione che impiega la base specificata dal parametro base. Se c e' una cifra valida restituisce il valore della cifra; se c NON e' una cifra valida restituisce NS_CIFRANONVALIDA. ==============================================================================*/ int8_t NS_cifra( char c, int8_t base ) { c = tolower(c); int8_t i; if( base>=NS_MINBASE && base<=NS_MAXBASE ) for( i=0; i<base; ++i ) if( c == NS_Cifre[i] ) return i; return NS_CIFRANONVALIDA; } /*============================================================================== Imposta una variabile statica che fa si' che le altre funzioni impieghino (nelle chiamate successive) caratteri maiuscoli o minuscoli come cifre per quei sistemi di numerazione che richiedono l'uso di oltre 10 cifre. ==============================================================================*/ void NS_usa_cifre_maiuscole( bool usa_cifre_maiuscole ) { NS_usa_maiuscole = usa_cifre_maiuscole; }
Il terzo, con un programmino d'esempio d'uso: main.c
/**============================================================================= Programma d'esempio per numeri_e_stringhe. =============================================================================**/ #include <string.h> #include "numeri_e_stringhe.h" int main() { char buff[NS_DIMBUFFNUM]; int8_t b1, b2; int64_t n; bool ripeti; printf( "CONVERTE LA BASE DI NUMERAZIONE DI UN NUMERO DATO\n" ); printf( "=================================================\n\n" ); do { printf( "Immetti la base di numerazione iniziale (%d-%d): ", NS_MINBASE, NS_MAXBASE ); b1 = NS_chiedi_numero( NS_MINBASE, NS_MAXBASE, 10 ); printf( "Immetti la base di numerazione di destinazione (%d-%d): ", NS_MINBASE, NS_MAXBASE ); b2 = NS_chiedi_numero( NS_MINBASE, NS_MAXBASE, 10 ); printf( "Immetti il numero da convertire: " ); n = NS_chiedi_numero( NS_MINVAL, NS_MAXVAL, b1 ); printf( "\n base %2d: %s\n", b1, NS_ns(n,buff,b1) ); printf( " base %2d: %s\n\n", b2, NS_ns(n,buff,b2) ); printf( "Vuoi effettuare un'altra conversione? " "(\"s\" per continuare) " ); fgets( buff, NS_DIMBUFFNUM, stdin ); ripeti = tolower(*buff) != 'n'; /* se necessario, "svuota" stdin */ while( buff[strlen(buff)-1] != '\n' ) fgets( buff, NS_DIMBUFFNUM, stdin ); printf( "\n\n" ); } while( ripeti ); return 0; }' ) { /* se sono rimasti caratteri */ int16_t i, j; /* contatori */ if( (negativo=*p==NS_SegnoNegativo) ) ++p; /* saltiamo il segno */ while( *p == '0' ) ++p; /* saltiamo gli zeri iniziali */ while( NS_cifra(p[totCifre],base) >= 0 ) /* contiamo le cifre */ ++totCifre; if( totCifre > 0 ) { /* se ci sono cifre valide, calcoliamo */ for( i=totCifre; i>0; --i ) { /* partendo dal fondo */ int64_t tmp=1; for( j=0; j<totCifre-i; ++j ) tmp *= base; /* potenza */ r += NS_cifra(p[i-1],base) * tmp; } if( negativo ) r = -r; /* se era negativo, ripristiniamo */ } } } if( qCifre != NULL ) *qCifre = totCifre; /* solo se non e' NULL */ return r; } /*============================================================================== Converte un numero intero in formato int64_t nella sua rappresentazione in forma di stringa, secondo la base di numerazione specificata. Se il parametro buff e' un puntatore valido, la funzione impiega lo spazio di memoria puntato per collocarvi la stringa risultante dalla conversione. Spetta al chiamante assicurarsi che buff punti a uno spazio di memoria sufficiente per contenere la stringa (il caso piu' "esigente" riguarda il valore a 64 bit massimo in formato binario: 64 caratteri piu' il terminatore, eventualmente con l'aggiunta d'un segno negativo -- 66 caratteri in tutto). Se il parametro buff e' NULL, la funzione inserisce la stringa risultante in un buffer statico costituito da NS_DIMBUFFNUM char. Ovviamente, ogni nuova chiamata alla funzione sovrascrive il buffer cancellando l'esito delle eventuali conversioni precedenti. La funzione fallisce (restituendo una stringa che descrive l'errore) solo se il parametro base eccede i limiti consentiti da NS_MINBASE e NS_MAXBASE. ==============================================================================*/ char *NS_ns( int64_t n, char *buff, int8_t base ) { static char sBuff[NS_DIMBUFFNUM]; /* max 64 cifre + il segno negativo */ uint64_t un; /* necessario per il valore negativo minimo */ int16_t i; /* deve poter contenere almeno la lunghezza della stringa */ /* se il parametro buff e' nullo, usiamo il buffer statico */ if( buff == NULL ) buff = sBuff; if( base>=NS_MINBASE && base<=NS_MAXBASE ) { int16_t l, lMezzi; bool negativo; int8_t cifra; negativo = n < 0; /* memorizziamo il segno */ un = negativo ? -n : n; /* usiamo sempre un valore positivo */ /* N.B. la stringa viene generata "all'indietro" */ for( l=0; un!=0; ++l ) { cifra = un%base; buff[l] = NS_Cifre[cifra]; un /= base; } if( negativo ) buff[l++] = NS_SegnoNegativo; /* apponiamo il segno? */ buff[l] = 'Ciao a te che leggi.
Oggi non sapevo che fare e ho messo insieme una paginata di roba in previsione di un futuro ed ipotetico uso personale. Probabilmente si tratta della classica "reinvenzione della ruota", però sapete che son fatto così e che mi diverto a scrivere 'ste cose. Non escludo che si tratti pure di un modo improprio di ottenere il risultato.
Detto questo... potrebbe essere utile aggiungere questi file alla sezione "esempi" dei programmi presenti su Pierotofy? Se sì, aggiungo; se no, tengo per me. Graditi opinioni e, se non significano "rivoluzionare" tutto (non ne vale la pena, credo), suggerimenti su come migliorare il codice. Meno gradito, ma comunque accettato, un eventuale "ma piantala lì!".
Tre file. Il primo: numeri_e_stringhe.h
/**============================================================================= NUMERI E STRINGHE v1.0 - aprile 2017 Gestisce valori compresi tra 9223372036854775807 e -9223372036854775807 (interi a 64 bit) con base compresa tra 2 e 36. =============================================================================**/ #ifndef NUMERI_E_STRINGHE_H_INCLUDED #define NUMERI_E_STRINGHE_H_INCLUDED /** ===> INCLUSIONI <========================================================**/ #include <stdio.h> #include <stdlib.h> #include <stdint.h> /* per usare i tipi uint64_t, int64_t, int16_t e int8_t */ #include <stdbool.h> /* per usare il tipo bool */ #include <ctype.h> /* per usare tolower() e toupper() */ /** ===> MACRO <============================================================ **/ #define NS_USACHIEDINUMERO /* da definire per usare NS_chiedi_numero() */ #define NS_CIFRANONVALIDA -1 /* restituito come errore da NS_cifra() */ #define NS_MINBASE 2 /* la base non puo' essere inferiore */ #define NS_MAXBASE 36 /* la base non puo' essere superiore */ #define NS_MINVAL -9223372036854775807LL #define NS_MAXVAL 9223372036854775807LL #define NS_DIMBUFFNUM 68 /* le dimensioni del buffer per la rappresentazione dei numeri a 64 bit sotto forma di stringa */ /** ===> PROTOTIPI DELLE FUNZIONI <========================================= **/ #ifdef NS_USACHIEDINUMERO int64_t NS_chiedi_numero( int64_t minimo, int64_t massimo, int8_t base ); #endif // NS_USACHIEDINUMERO int64_t NS_sn( const char *s, int16_t *qCifre, int8_t base ); char *NS_ns( int64_t n, char *buff, int8_t base ); int8_t NS_cifra( char c, int8_t base ); void NS_usa_cifre_maiuscole( bool usa_cifre_maiuscole ); #endif /* NUMERI_E_STRINGHE_H_INCLUDED */
Il secondo: numeri_e_stringhe.c
/**============================================================================= NUMERI E STRINGHE v1.0 - aprile 2017 Gestisce valori compresi tra 9223372036854775807 e -9223372036854775807 (interi a 64 bit) con base compresa tra 2 e 36. =============================================================================**/ #include "numeri_e_stringhe.h" /** ===> COSTANTI <========================================================= **/ static const char *NS_Cifre = "0123456789abcdefghijklmnopqrstuvwxyz"; static const char NS_SegnoNegativo = '-'; static const char *NS_StrErrBaseNonValida = "(la base eccede i limiti)"; /** ===> VARIABILI GLOBALI PER QUESTO FILE <================================ **/ bool NS_usa_maiuscole = false; /** ===> DEFINIZIONE DELLE FUNZIONI <======================================= **/ /*============================================================================== Chiede l'immissione in console di un numero intero compreso tra min e max, dove min non puo' essere inferiore a NS_MINVAL e max non puo' essere superiore a NS_MAXVAL. Restituisce il numero immesso come valore di ritorno di tipo int64_t. La funzione insiste nella sua richiesta fintanto che non viene immesso un dato accettabile, quindi ritorna. Per usare questa funzione occorre che sia definita la macro NS_USACHIEDINUMERO. ==============================================================================*/ #ifdef NS_USACHIEDINUMERO int64_t NS_chiedi_numero( int64_t min, int64_t max, int8_t base ) { char buff[NS_DIMBUFFNUM]; /* 64 cifre + il segno negativo */ bool ripeti, pp = true; /* pp = primo passaggio */ int16_t l, qCifre; int64_t n; do { if( !pp ) /* se non e' il primo passaggio... */ printf( "Input non valido, riprova: " ); else pp = false; /* se e' il primo passaggio */ fgets( buff, NS_DIMBUFFNUM, stdin ); /* riceviamo l'input */ for( l=0; buff[l]; ++l ); /* la lunghezza dell'input */ if( buff[l-1] == '\n' ) { n = NS_sn( buff, &qCifre, base ); /* converte in int64_t */ ripeti = n<min || n>max || qCifre==0; } else { /* se l'ultimo carattere non e' '\n' significa che l'input e' stato troncato, il che non va bene; eliminiamo i caratteri ancora "pendenti" */ while( getchar() != '\n' ); ripeti = true; /* la condizione per ripetere */ } } while( ripeti ); return n; /* restituisce il numero immesso */ } #endif // NS_USACHIEDINUMERO /*============================================================================== Converte una stringa nel numero intero corrispondente, secondo la base di numerazione specificata. Se la stringa inizia con caratteri non idonei a rappresentare le cifre del sistema di numerazione specificato, quei caratteri non vengono considerati. Se la stringa contiene una rappresentazione numerica valida, la funzione restituisce il valore ricavato dalla stringa (in formato int64_t) e immette la quantita' delle cifre riconosciute all'indirizzo indicato dal parametro qCifre. Se la stringa NON contiene una rappresentazione numerica valida, la funzione restituisce 0 e immette 0 anche all'indirizzo indicato dal parametro qCifre. Se il parametro qCifre e' un puntatore NULL, la funzione non puo' fornire informazioni circa la quantita' di cifre riconosciute, rendendo di fatto impossibile al chiamante sapere se la conversione e' stata portata a termine correttamente oppure no. ==============================================================================*/ int64_t NS_sn( const char *s, int16_t *qCifre, int8_t base ) { int16_t totCifre = 0; /* si presuppone il fallimento */ int64_t r = 0; /* il risultato dell'operazione */ /* se i parametri sono accettabili, analizziamo la stringa */ if( s != NULL && (base>=NS_MINBASE&&base<=NS_MAXBASE) ) { const char *p = s; /* puntatore ausiliario */ bool negativo; /* scartiamo tutti i caratteri non numerici iniziali */ while( !(NS_cifra(*p,base)>=0||*p==NS_SegnoNegativo) && *p!='{parsed_message}' ) ++p; if( *p != '{parsed_message}' ) { /* se sono rimasti caratteri */ int16_t i, j; /* contatori */ if( (negativo=*p==NS_SegnoNegativo) ) ++p; /* saltiamo il segno */ while( *p == '0' ) ++p; /* saltiamo gli zeri iniziali */ while( NS_cifra(p[totCifre],base) >= 0 ) /* contiamo le cifre */ ++totCifre; if( totCifre > 0 ) { /* se ci sono cifre valide, calcoliamo */ for( i=totCifre; i>0; --i ) { /* partendo dal fondo */ int64_t tmp=1; for( j=0; j<totCifre-i; ++j ) tmp *= base; /* potenza */ r += NS_cifra(p[i-1],base) * tmp; } if( negativo ) r = -r; /* se era negativo, ripristiniamo */ } } } if( qCifre != NULL ) *qCifre = totCifre; /* solo se non e' NULL */ return r; } /*============================================================================== Converte un numero intero in formato int64_t nella sua rappresentazione in forma di stringa, secondo la base di numerazione specificata. Se il parametro buff e' un puntatore valido, la funzione impiega lo spazio di memoria puntato per collocarvi la stringa risultante dalla conversione. Spetta al chiamante assicurarsi che buff punti a uno spazio di memoria sufficiente per contenere la stringa (il caso piu' "esigente" riguarda il valore a 64 bit massimo in formato binario: 64 caratteri piu' il terminatore, eventualmente con l'aggiunta d'un segno negativo -- 66 caratteri in tutto). Se il parametro buff e' NULL, la funzione inserisce la stringa risultante in un buffer statico costituito da NS_DIMBUFFNUM char. Ovviamente, ogni nuova chiamata alla funzione sovrascrive il buffer cancellando l'esito delle eventuali conversioni precedenti. La funzione fallisce (restituendo una stringa che descrive l'errore) solo se il parametro base eccede i limiti consentiti da NS_MINBASE e NS_MAXBASE. ==============================================================================*/ char *NS_ns( int64_t n, char *buff, int8_t base ) { static char sBuff[NS_DIMBUFFNUM]; /* max 64 cifre + il segno negativo */ uint64_t un; /* necessario per il valore negativo minimo */ int16_t i; /* deve poter contenere almeno la lunghezza della stringa */ /* se il parametro buff e' nullo, usiamo il buffer statico */ if( buff == NULL ) buff = sBuff; if( base>=NS_MINBASE && base<=NS_MAXBASE ) { int16_t l, lMezzi; bool negativo; int8_t cifra; negativo = n < 0; /* memorizziamo il segno */ un = negativo ? -n : n; /* usiamo sempre un valore positivo */ /* N.B. la stringa viene generata "all'indietro" */ for( l=0; un!=0; ++l ) { cifra = un%base; buff[l] = NS_Cifre[cifra]; un /= base; } if( negativo ) buff[l++] = NS_SegnoNegativo; /* apponiamo il segno? */ buff[l] = '{parsed_message}'; /* terminiamo la stringa */ /* "rovesciamo" la stringa (generata all'indietro) */ for( lMezzi=l/2, i=0; i<lMezzi; ++i ) { char aux = buff[i]; buff[i] = buff[l-i-1]; buff[l-i-1] = aux; } /* se necessario, usiamo le cifre in caratteri maiuscoli */ if( NS_usa_maiuscole ) for( i=0; i<l; ++i ) buff[i] = toupper( buff[i] ); } else { /* la base eccede i limiti imposti da NS_MINBASE e NS_MAXBASE */ for( i=0; NS_StrErrBaseNonValida[i]; ++i ) buff[i] = NS_StrErrBaseNonValida[i]; /* copiamo l'errore */ buff[i] = '{parsed_message}'; /* terminiamo la stringa */ } return buff; /* restituiamo un puntatore al buffer effettivamente usato */ } /*============================================================================== Verifica se c corrisponde a una delle cifre valide nel sistema di numerazione che impiega la base specificata dal parametro base. Se c e' una cifra valida restituisce il valore della cifra; se c NON e' una cifra valida restituisce NS_CIFRANONVALIDA. ==============================================================================*/ int8_t NS_cifra( char c, int8_t base ) { c = tolower(c); int8_t i; if( base>=NS_MINBASE && base<=NS_MAXBASE ) for( i=0; i<base; ++i ) if( c == NS_Cifre[i] ) return i; return NS_CIFRANONVALIDA; } /*============================================================================== Imposta una variabile statica che fa si' che le altre funzioni impieghino (nelle chiamate successive) caratteri maiuscoli o minuscoli come cifre per quei sistemi di numerazione che richiedono l'uso di oltre 10 cifre. ==============================================================================*/ void NS_usa_cifre_maiuscole( bool usa_cifre_maiuscole ) { NS_usa_maiuscole = usa_cifre_maiuscole; }
Il terzo, con un programmino d'esempio d'uso: main.c
/**============================================================================= Programma d'esempio per numeri_e_stringhe. =============================================================================**/ #include <string.h> #include "numeri_e_stringhe.h" int main() { char buff[NS_DIMBUFFNUM]; int8_t b1, b2; int64_t n; bool ripeti; printf( "CONVERTE LA BASE DI NUMERAZIONE DI UN NUMERO DATO\n" ); printf( "=================================================\n\n" ); do { printf( "Immetti la base di numerazione iniziale (%d-%d): ", NS_MINBASE, NS_MAXBASE ); b1 = NS_chiedi_numero( NS_MINBASE, NS_MAXBASE, 10 ); printf( "Immetti la base di numerazione di destinazione (%d-%d): ", NS_MINBASE, NS_MAXBASE ); b2 = NS_chiedi_numero( NS_MINBASE, NS_MAXBASE, 10 ); printf( "Immetti il numero da convertire: " ); n = NS_chiedi_numero( NS_MINVAL, NS_MAXVAL, b1 ); printf( "\n base %2d: %s\n", b1, NS_ns(n,buff,b1) ); printf( " base %2d: %s\n\n", b2, NS_ns(n,buff,b2) ); printf( "Vuoi effettuare un'altra conversione? " "(\"s\" per continuare) " ); fgets( buff, NS_DIMBUFFNUM, stdin ); ripeti = tolower(*buff) != 'n'; /* se necessario, "svuota" stdin */ while( buff[strlen(buff)-1] != '\n' ) fgets( buff, NS_DIMBUFFNUM, stdin ); printf( "\n\n" ); } while( ripeti ); return 0; }'; /* terminiamo la stringa */ /* "rovesciamo" la stringa (generata all'indietro) */ for( lMezzi=l/2, i=0; i<lMezzi; ++i ) { char aux = buff[i]; buff[i] = buff[l-i-1]; buff[l-i-1] = aux; } /* se necessario, usiamo le cifre in caratteri maiuscoli */ if( NS_usa_maiuscole ) for( i=0; i<l; ++i ) buff[i] = toupper( buff[i] ); } else { /* la base eccede i limiti imposti da NS_MINBASE e NS_MAXBASE */ for( i=0; NS_StrErrBaseNonValida[i]; ++i ) buff[i] = NS_StrErrBaseNonValida[i]; /* copiamo l'errore */ buff[i] = 'Ciao a te che leggi.
Oggi non sapevo che fare e ho messo insieme una paginata di roba in previsione di un futuro ed ipotetico uso personale. Probabilmente si tratta della classica "reinvenzione della ruota", però sapete che son fatto così e che mi diverto a scrivere 'ste cose. Non escludo che si tratti pure di un modo improprio di ottenere il risultato.
Detto questo... potrebbe essere utile aggiungere questi file alla sezione "esempi" dei programmi presenti su Pierotofy? Se sì, aggiungo; se no, tengo per me. Graditi opinioni e, se non significano "rivoluzionare" tutto (non ne vale la pena, credo), suggerimenti su come migliorare il codice. Meno gradito, ma comunque accettato, un eventuale "ma piantala lì!".
Tre file. Il primo: numeri_e_stringhe.h
/**============================================================================= NUMERI E STRINGHE v1.0 - aprile 2017 Gestisce valori compresi tra 9223372036854775807 e -9223372036854775807 (interi a 64 bit) con base compresa tra 2 e 36. =============================================================================**/ #ifndef NUMERI_E_STRINGHE_H_INCLUDED #define NUMERI_E_STRINGHE_H_INCLUDED /** ===> INCLUSIONI <========================================================**/ #include <stdio.h> #include <stdlib.h> #include <stdint.h> /* per usare i tipi uint64_t, int64_t, int16_t e int8_t */ #include <stdbool.h> /* per usare il tipo bool */ #include <ctype.h> /* per usare tolower() e toupper() */ /** ===> MACRO <============================================================ **/ #define NS_USACHIEDINUMERO /* da definire per usare NS_chiedi_numero() */ #define NS_CIFRANONVALIDA -1 /* restituito come errore da NS_cifra() */ #define NS_MINBASE 2 /* la base non puo' essere inferiore */ #define NS_MAXBASE 36 /* la base non puo' essere superiore */ #define NS_MINVAL -9223372036854775807LL #define NS_MAXVAL 9223372036854775807LL #define NS_DIMBUFFNUM 68 /* le dimensioni del buffer per la rappresentazione dei numeri a 64 bit sotto forma di stringa */ /** ===> PROTOTIPI DELLE FUNZIONI <========================================= **/ #ifdef NS_USACHIEDINUMERO int64_t NS_chiedi_numero( int64_t minimo, int64_t massimo, int8_t base ); #endif // NS_USACHIEDINUMERO int64_t NS_sn( const char *s, int16_t *qCifre, int8_t base ); char *NS_ns( int64_t n, char *buff, int8_t base ); int8_t NS_cifra( char c, int8_t base ); void NS_usa_cifre_maiuscole( bool usa_cifre_maiuscole ); #endif /* NUMERI_E_STRINGHE_H_INCLUDED */
Il secondo: numeri_e_stringhe.c
/**============================================================================= NUMERI E STRINGHE v1.0 - aprile 2017 Gestisce valori compresi tra 9223372036854775807 e -9223372036854775807 (interi a 64 bit) con base compresa tra 2 e 36. =============================================================================**/ #include "numeri_e_stringhe.h" /** ===> COSTANTI <========================================================= **/ static const char *NS_Cifre = "0123456789abcdefghijklmnopqrstuvwxyz"; static const char NS_SegnoNegativo = '-'; static const char *NS_StrErrBaseNonValida = "(la base eccede i limiti)"; /** ===> VARIABILI GLOBALI PER QUESTO FILE <================================ **/ bool NS_usa_maiuscole = false; /** ===> DEFINIZIONE DELLE FUNZIONI <======================================= **/ /*============================================================================== Chiede l'immissione in console di un numero intero compreso tra min e max, dove min non puo' essere inferiore a NS_MINVAL e max non puo' essere superiore a NS_MAXVAL. Restituisce il numero immesso come valore di ritorno di tipo int64_t. La funzione insiste nella sua richiesta fintanto che non viene immesso un dato accettabile, quindi ritorna. Per usare questa funzione occorre che sia definita la macro NS_USACHIEDINUMERO. ==============================================================================*/ #ifdef NS_USACHIEDINUMERO int64_t NS_chiedi_numero( int64_t min, int64_t max, int8_t base ) { char buff[NS_DIMBUFFNUM]; /* 64 cifre + il segno negativo */ bool ripeti, pp = true; /* pp = primo passaggio */ int16_t l, qCifre; int64_t n; do { if( !pp ) /* se non e' il primo passaggio... */ printf( "Input non valido, riprova: " ); else pp = false; /* se e' il primo passaggio */ fgets( buff, NS_DIMBUFFNUM, stdin ); /* riceviamo l'input */ for( l=0; buff[l]; ++l ); /* la lunghezza dell'input */ if( buff[l-1] == '\n' ) { n = NS_sn( buff, &qCifre, base ); /* converte in int64_t */ ripeti = n<min || n>max || qCifre==0; } else { /* se l'ultimo carattere non e' '\n' significa che l'input e' stato troncato, il che non va bene; eliminiamo i caratteri ancora "pendenti" */ while( getchar() != '\n' ); ripeti = true; /* la condizione per ripetere */ } } while( ripeti ); return n; /* restituisce il numero immesso */ } #endif // NS_USACHIEDINUMERO /*============================================================================== Converte una stringa nel numero intero corrispondente, secondo la base di numerazione specificata. Se la stringa inizia con caratteri non idonei a rappresentare le cifre del sistema di numerazione specificato, quei caratteri non vengono considerati. Se la stringa contiene una rappresentazione numerica valida, la funzione restituisce il valore ricavato dalla stringa (in formato int64_t) e immette la quantita' delle cifre riconosciute all'indirizzo indicato dal parametro qCifre. Se la stringa NON contiene una rappresentazione numerica valida, la funzione restituisce 0 e immette 0 anche all'indirizzo indicato dal parametro qCifre. Se il parametro qCifre e' un puntatore NULL, la funzione non puo' fornire informazioni circa la quantita' di cifre riconosciute, rendendo di fatto impossibile al chiamante sapere se la conversione e' stata portata a termine correttamente oppure no. ==============================================================================*/ int64_t NS_sn( const char *s, int16_t *qCifre, int8_t base ) { int16_t totCifre = 0; /* si presuppone il fallimento */ int64_t r = 0; /* il risultato dell'operazione */ /* se i parametri sono accettabili, analizziamo la stringa */ if( s != NULL && (base>=NS_MINBASE&&base<=NS_MAXBASE) ) { const char *p = s; /* puntatore ausiliario */ bool negativo; /* scartiamo tutti i caratteri non numerici iniziali */ while( !(NS_cifra(*p,base)>=0||*p==NS_SegnoNegativo) && *p!='{parsed_message}' ) ++p; if( *p != '{parsed_message}' ) { /* se sono rimasti caratteri */ int16_t i, j; /* contatori */ if( (negativo=*p==NS_SegnoNegativo) ) ++p; /* saltiamo il segno */ while( *p == '0' ) ++p; /* saltiamo gli zeri iniziali */ while( NS_cifra(p[totCifre],base) >= 0 ) /* contiamo le cifre */ ++totCifre; if( totCifre > 0 ) { /* se ci sono cifre valide, calcoliamo */ for( i=totCifre; i>0; --i ) { /* partendo dal fondo */ int64_t tmp=1; for( j=0; j<totCifre-i; ++j ) tmp *= base; /* potenza */ r += NS_cifra(p[i-1],base) * tmp; } if( negativo ) r = -r; /* se era negativo, ripristiniamo */ } } } if( qCifre != NULL ) *qCifre = totCifre; /* solo se non e' NULL */ return r; } /*============================================================================== Converte un numero intero in formato int64_t nella sua rappresentazione in forma di stringa, secondo la base di numerazione specificata. Se il parametro buff e' un puntatore valido, la funzione impiega lo spazio di memoria puntato per collocarvi la stringa risultante dalla conversione. Spetta al chiamante assicurarsi che buff punti a uno spazio di memoria sufficiente per contenere la stringa (il caso piu' "esigente" riguarda il valore a 64 bit massimo in formato binario: 64 caratteri piu' il terminatore, eventualmente con l'aggiunta d'un segno negativo -- 66 caratteri in tutto). Se il parametro buff e' NULL, la funzione inserisce la stringa risultante in un buffer statico costituito da NS_DIMBUFFNUM char. Ovviamente, ogni nuova chiamata alla funzione sovrascrive il buffer cancellando l'esito delle eventuali conversioni precedenti. La funzione fallisce (restituendo una stringa che descrive l'errore) solo se il parametro base eccede i limiti consentiti da NS_MINBASE e NS_MAXBASE. ==============================================================================*/ char *NS_ns( int64_t n, char *buff, int8_t base ) { static char sBuff[NS_DIMBUFFNUM]; /* max 64 cifre + il segno negativo */ uint64_t un; /* necessario per il valore negativo minimo */ int16_t i; /* deve poter contenere almeno la lunghezza della stringa */ /* se il parametro buff e' nullo, usiamo il buffer statico */ if( buff == NULL ) buff = sBuff; if( base>=NS_MINBASE && base<=NS_MAXBASE ) { int16_t l, lMezzi; bool negativo; int8_t cifra; negativo = n < 0; /* memorizziamo il segno */ un = negativo ? -n : n; /* usiamo sempre un valore positivo */ /* N.B. la stringa viene generata "all'indietro" */ for( l=0; un!=0; ++l ) { cifra = un%base; buff[l] = NS_Cifre[cifra]; un /= base; } if( negativo ) buff[l++] = NS_SegnoNegativo; /* apponiamo il segno? */ buff[l] = '{parsed_message}'; /* terminiamo la stringa */ /* "rovesciamo" la stringa (generata all'indietro) */ for( lMezzi=l/2, i=0; i<lMezzi; ++i ) { char aux = buff[i]; buff[i] = buff[l-i-1]; buff[l-i-1] = aux; } /* se necessario, usiamo le cifre in caratteri maiuscoli */ if( NS_usa_maiuscole ) for( i=0; i<l; ++i ) buff[i] = toupper( buff[i] ); } else { /* la base eccede i limiti imposti da NS_MINBASE e NS_MAXBASE */ for( i=0; NS_StrErrBaseNonValida[i]; ++i ) buff[i] = NS_StrErrBaseNonValida[i]; /* copiamo l'errore */ buff[i] = '{parsed_message}'; /* terminiamo la stringa */ } return buff; /* restituiamo un puntatore al buffer effettivamente usato */ } /*============================================================================== Verifica se c corrisponde a una delle cifre valide nel sistema di numerazione che impiega la base specificata dal parametro base. Se c e' una cifra valida restituisce il valore della cifra; se c NON e' una cifra valida restituisce NS_CIFRANONVALIDA. ==============================================================================*/ int8_t NS_cifra( char c, int8_t base ) { c = tolower(c); int8_t i; if( base>=NS_MINBASE && base<=NS_MAXBASE ) for( i=0; i<base; ++i ) if( c == NS_Cifre[i] ) return i; return NS_CIFRANONVALIDA; } /*============================================================================== Imposta una variabile statica che fa si' che le altre funzioni impieghino (nelle chiamate successive) caratteri maiuscoli o minuscoli come cifre per quei sistemi di numerazione che richiedono l'uso di oltre 10 cifre. ==============================================================================*/ void NS_usa_cifre_maiuscole( bool usa_cifre_maiuscole ) { NS_usa_maiuscole = usa_cifre_maiuscole; }
Il terzo, con un programmino d'esempio d'uso: main.c
/**============================================================================= Programma d'esempio per numeri_e_stringhe. =============================================================================**/ #include <string.h> #include "numeri_e_stringhe.h" int main() { char buff[NS_DIMBUFFNUM]; int8_t b1, b2; int64_t n; bool ripeti; printf( "CONVERTE LA BASE DI NUMERAZIONE DI UN NUMERO DATO\n" ); printf( "=================================================\n\n" ); do { printf( "Immetti la base di numerazione iniziale (%d-%d): ", NS_MINBASE, NS_MAXBASE ); b1 = NS_chiedi_numero( NS_MINBASE, NS_MAXBASE, 10 ); printf( "Immetti la base di numerazione di destinazione (%d-%d): ", NS_MINBASE, NS_MAXBASE ); b2 = NS_chiedi_numero( NS_MINBASE, NS_MAXBASE, 10 ); printf( "Immetti il numero da convertire: " ); n = NS_chiedi_numero( NS_MINVAL, NS_MAXVAL, b1 ); printf( "\n base %2d: %s\n", b1, NS_ns(n,buff,b1) ); printf( " base %2d: %s\n\n", b2, NS_ns(n,buff,b2) ); printf( "Vuoi effettuare un'altra conversione? " "(\"s\" per continuare) " ); fgets( buff, NS_DIMBUFFNUM, stdin ); ripeti = tolower(*buff) != 'n'; /* se necessario, "svuota" stdin */ while( buff[strlen(buff)-1] != '\n' ) fgets( buff, NS_DIMBUFFNUM, stdin ); printf( "\n\n" ); } while( ripeti ); return 0; }'; /* terminiamo la stringa */ } return buff; /* restituiamo un puntatore al buffer effettivamente usato */ } /*============================================================================== Verifica se c corrisponde a una delle cifre valide nel sistema di numerazione che impiega la base specificata dal parametro base. Se c e' una cifra valida restituisce il valore della cifra; se c NON e' una cifra valida restituisce NS_CIFRANONVALIDA. ==============================================================================*/ int8_t NS_cifra( char c, int8_t base ) { c = tolower(c); int8_t i; if( base>=NS_MINBASE && base<=NS_MAXBASE ) for( i=0; i<base; ++i ) if( c == NS_Cifre[i] ) return i; return NS_CIFRANONVALIDA; } /*============================================================================== Imposta una variabile statica che fa si' che le altre funzioni impieghino (nelle chiamate successive) caratteri maiuscoli o minuscoli come cifre per quei sistemi di numerazione che richiedono l'uso di oltre 10 cifre. ==============================================================================*/ void NS_usa_cifre_maiuscole( bool usa_cifre_maiuscole ) { NS_usa_maiuscole = usa_cifre_maiuscole; }
Il terzo, con un programmino d'esempio d'uso: main.c
/**============================================================================= Programma d'esempio per numeri_e_stringhe. =============================================================================**/ #include <string.h> #include "numeri_e_stringhe.h" int main() { char buff[NS_DIMBUFFNUM]; int8_t b1, b2; int64_t n; bool ripeti; printf( "CONVERTE LA BASE DI NUMERAZIONE DI UN NUMERO DATO\n" ); printf( "=================================================\n\n" ); do { printf( "Immetti la base di numerazione iniziale (%d-%d): ", NS_MINBASE, NS_MAXBASE ); b1 = NS_chiedi_numero( NS_MINBASE, NS_MAXBASE, 10 ); printf( "Immetti la base di numerazione di destinazione (%d-%d): ", NS_MINBASE, NS_MAXBASE ); b2 = NS_chiedi_numero( NS_MINBASE, NS_MAXBASE, 10 ); printf( "Immetti il numero da convertire: " ); n = NS_chiedi_numero( NS_MINVAL, NS_MAXVAL, b1 ); printf( "\n base %2d: %s\n", b1, NS_ns(n,buff,b1) ); printf( " base %2d: %s\n\n", b2, NS_ns(n,buff,b2) ); printf( "Vuoi effettuare un'altra conversione? " "(\"s\" per continuare) " ); fgets( buff, NS_DIMBUFFNUM, stdin ); ripeti = tolower(*buff) != 'n'; /* se necessario, "svuota" stdin */ while( buff[strlen(buff)-1] != '\n' ) fgets( buff, NS_DIMBUFFNUM, stdin ); printf( "\n\n" ); } while( ripeti ); return 0; }
Ultima modifica effettuata da AldoBaldo 01/05/17 6:42
ATTENZIONE! Sono un hobbista e l'affidabilità delle mie conoscenze informatiche è molto limitata. Non prendere come esempio il codice che scrivo, perché non ho alcuna formazione accademica e rischieresti di apprendere pratiche controproducenti.