Dubito che sia possibile parlare di "ottimizzazione", però m'è preso il ghiribizzo di pasticciare un po' con la tua idea di un marchingegno per scomporre numeri in fattori primi. Ne è venuta fuori una roba, distribuita su tre file che credo sia in ANSI C. Il compilatore che uso (mingw) ha sputato fuori un eseguibile di 11 Kb in tutto, alla faccia del C++ che anche solo usando cin e cout s'avvicinava al Mb!
Sicuramente ci saranno ingenuità mostruose, sia perché le mie conoscenze matematiche sono quel che sono, sia perché ho fatto tutto un po' di getto, appiccicando funzioni su funzioni preso dal fuoco sacro del giocare a fingere d'essere un programmatore della madonna! (che non è vero)
1. main.c
#include <stdio.h>
#include <string.h>
#include "interfaccia.h"
// ===> MACRO/COSTANTI/STRINGHE <===============================================
#define MAX_FATTORI 36 // in effetti, unsigned long puo' contenere un valore
// massimo di 2^32-1, per cui nella scomposizione non
// ci possono essere piu' di 32 fattori primi
const char *kStrPres[] = {
"SCOMPOSIZIONE IN FATTORI PRIMI",
"questo programma scompone in fattori primi valori interi compresi",
"tra 2 e 4294967295, presentando il risultato sia in forma di",
"calcolo in colonna, sia come formula riassuntiva in linea"
};
const int kNStrPres = sizeof(kStrPres)/sizeof(*kStrPres);
// ===> PROTOTIPI DI FUNZIONI <=================================================
void scomponi( unsigned long n, unsigned long *fattori );
// ===> FUNZIONE D'ACCESSO AL PROGRAMMA <=======================================
int main() {
unsigned long n, fattori[MAX_FATTORI];
presenta_in_console( kStrPres, kNStrPres );
do {
memset( fattori, 0, sizeof(*fattori)*MAX_FATTORI );
n = chiedi_numero_da_scomporre();
scomponi( n, fattori );
scrivi_tabella_scomposizione( n, fattori );
scrivi_scomposizione_in_linea( n, fattori );
} while( chiedi_se_continuare() );
return 0;
}
// ===> FUNZIONE DI SCOMPOSIZIONE IN FATTORI PRIMI <============================
void scomponi( unsigned long n, unsigned long *fattori ) {
if( n > 1 ) {
unsigned long d, max;
int nf; // la quantita' dei fattori trovati
for( d=2, nf=0; n%d==0; ++nf ) {
fattori[nf] = d;
n /= d;
}
if( n == 1 ) return;
for( max=n, d=3; d<=max; ) {
if( n%d ) { d+=2; continue; }
fattori[nf++] = d;
if( (n/=d) == 1 ) break;
max = n;
}
}
else {
if( n == 0 )
printf( "Lo zero non e' scomponibile.\n\n" );
else printf( "L'unita' non e' scomponibile.\n\n" );
}
}
2. interfaccia.h
#ifndef INTERFACCIA_H_INCLUDED
#define INTERFACCIA_H_INCLUDED
void presenta_in_console( const char *s[], int ns );
unsigned long chiedi_numero_da_scomporre( void );
void scrivi_tabella_scomposizione( unsigned long n, unsigned long *fattori );
void scrivi_scomposizione_in_linea( unsigned long n, unsigned long *fattori );
int chiedi_se_continuare( void );
#endif // INTERFACCIA_H_INCLUDED
3. interfaccia.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "interfaccia.h"
// ===> MACRO/COSTANTI <========================================================
#define LARGHEZZA_CONSOLE 80 // specificare la larghezza della console
#define A_CAPO printf("\n")
// ===> PROTOTIPI DI FUNZIONI <=================================================
int leggi_riga_da_console( char **riga, size_t *dim_riga );
int stringa_in_numero_intero( const char *s, unsigned long *n );
void centra_in_console( const char *s );
void traccia_riga_in_console( int c, int nc );
void mostra_errore_in_console( const char *msg );
void attendi_invio_da_console( void );
void svuota_console( void );
/*==============================================================================
Chiede all'utente di immettere il numero che intende scomporre. Verifica il dato
immesso per assicurarsi che sia effettivamente un numero intero. La verifica
avviene tramite la funzione standard strtoul(). La richiesta viene iterata fino
a che viene immesso un valore accettabile.
==============================================================================*/
unsigned long chiedi_numero_da_scomporre( void ) {
unsigned long numero;
char *riga = NULL;
int err = 1;
do {
svuota_console();
printf( "\nInserisci un numero da scomporre: " );
if( leggi_riga_da_console(&riga,NULL) == 0 ) {
if( stringa_in_numero_intero(riga,&numero) == 0 ) {
err = 0;
} else mostra_errore_in_console( "l'input non e' un numero intero" );
free( riga ); riga = NULL;
} else mostra_errore_in_console( "impossibile allocare" );
} while( err != 0 );
svuota_console();
printf( "\n" );
return numero;
}
/*==============================================================================
Legge una riga di testo di lunghezza arbitraria dalla console. La riga letta
viene collocata in uno spazio di memoria allocato dinamicamente il cui puntatore
viene immesso in *riga. Se dim_riga non e' NULL, le dimensioni della stringa
risultante sono collocate in *dim_riga (escluso il carattere terminatore).
Spetta al chiamante liberare con free() la memoria allocata.
Valori di ritorno:
0 tutto bene
1 parametri non validi (puntatori NULL)
4 impossibile allocare dinamicamente la memoria necessaria
==============================================================================*/
int leggi_riga_da_console( char **riga, size_t *dim_riga ) {
const size_t inc = 16; // procede per blocchi d'allocazione di inc byte
size_t dr, dm; // dr = dimensioni riga; dm = dimensioni memoria
char *tmp, *aux;
int c;
if( dim_riga ) *dim_riga = 0;
if( riga ) *riga = NULL; else return 1;
// alloca un primo blocco di memoria dinamica
dm = inc;
tmp = malloc( dm+1 );
if( !tmp ) return 4;
// legge i dati nella memoria dinamica, ridimensionandola se necessario
for( dr=0, c=fgetc(stdin); c!='\n' && c!=EOF; ++dr, c=fgetc(stdin) ) {
if( dr < (dm-1) ) {
tmp[dr] = c;
}
else {
aux = tmp; // caso mai realloc fallisse (vedi else)
if( (tmp=realloc(tmp,dm+inc)) ) {
dm += inc;
tmp[dr] = c;
}
else {
free( aux );
return 4;
}
}
}
*riga = tmp;
(*riga)[dr] = 'Dubito che sia possibile parlare di "ottimizzazione", però m'è preso il ghiribizzo di pasticciare un po' con la tua idea di un marchingegno per scomporre numeri in fattori primi. Ne è venuta fuori una roba, distribuita su tre file che credo sia in ANSI C. Il compilatore che uso (mingw) ha sputato fuori un eseguibile di 11 Kb in tutto, alla faccia del C++ che anche solo usando cin e cout s'avvicinava al Mb!
Sicuramente ci saranno ingenuità mostruose, sia perché le mie conoscenze matematiche sono quel che sono, sia perché ho fatto tutto un po' di getto, appiccicando funzioni su funzioni preso dal fuoco sacro del giocare a fingere d'essere un programmatore della madonna! (che non è vero)
1. main.c
#include <stdio.h>
#include <string.h>
#include "interfaccia.h"
// ===> MACRO/COSTANTI/STRINGHE <===============================================
#define MAX_FATTORI 36 // in effetti, unsigned long puo' contenere un valore
// massimo di 2^32-1, per cui nella scomposizione non
// ci possono essere piu' di 32 fattori primi
const char *kStrPres[] = {
"SCOMPOSIZIONE IN FATTORI PRIMI",
"questo programma scompone in fattori primi valori interi compresi",
"tra 2 e 4294967295, presentando il risultato sia in forma di",
"calcolo in colonna, sia come formula riassuntiva in linea"
};
const int kNStrPres = sizeof(kStrPres)/sizeof(*kStrPres);
// ===> PROTOTIPI DI FUNZIONI <=================================================
void scomponi( unsigned long n, unsigned long *fattori );
// ===> FUNZIONE D'ACCESSO AL PROGRAMMA <=======================================
int main() {
unsigned long n, fattori[MAX_FATTORI];
presenta_in_console( kStrPres, kNStrPres );
do {
memset( fattori, 0, sizeof(*fattori)*MAX_FATTORI );
n = chiedi_numero_da_scomporre();
scomponi( n, fattori );
scrivi_tabella_scomposizione( n, fattori );
scrivi_scomposizione_in_linea( n, fattori );
} while( chiedi_se_continuare() );
return 0;
}
// ===> FUNZIONE DI SCOMPOSIZIONE IN FATTORI PRIMI <============================
void scomponi( unsigned long n, unsigned long *fattori ) {
if( n > 1 ) {
unsigned long d, max;
int nf; // la quantita' dei fattori trovati
for( d=2, nf=0; n%d==0; ++nf ) {
fattori[nf] = d;
n /= d;
}
if( n == 1 ) return;
for( max=n, d=3; d<=max; ) {
if( n%d ) { d+=2; continue; }
fattori[nf++] = d;
if( (n/=d) == 1 ) break;
max = n;
}
}
else {
if( n == 0 )
printf( "Lo zero non e' scomponibile.\n\n" );
else printf( "L'unita' non e' scomponibile.\n\n" );
}
}
2. interfaccia.h
#ifndef INTERFACCIA_H_INCLUDED
#define INTERFACCIA_H_INCLUDED
void presenta_in_console( const char *s[], int ns );
unsigned long chiedi_numero_da_scomporre( void );
void scrivi_tabella_scomposizione( unsigned long n, unsigned long *fattori );
void scrivi_scomposizione_in_linea( unsigned long n, unsigned long *fattori );
int chiedi_se_continuare( void );
#endif // INTERFACCIA_H_INCLUDED
3. interfaccia.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "interfaccia.h"
// ===> MACRO/COSTANTI <========================================================
#define LARGHEZZA_CONSOLE 80 // specificare la larghezza della console
#define A_CAPO printf("\n")
// ===> PROTOTIPI DI FUNZIONI <=================================================
int leggi_riga_da_console( char **riga, size_t *dim_riga );
int stringa_in_numero_intero( const char *s, unsigned long *n );
void centra_in_console( const char *s );
void traccia_riga_in_console( int c, int nc );
void mostra_errore_in_console( const char *msg );
void attendi_invio_da_console( void );
void svuota_console( void );
/*==============================================================================
Chiede all'utente di immettere il numero che intende scomporre. Verifica il dato
immesso per assicurarsi che sia effettivamente un numero intero. La verifica
avviene tramite la funzione standard strtoul(). La richiesta viene iterata fino
a che viene immesso un valore accettabile.
==============================================================================*/
unsigned long chiedi_numero_da_scomporre( void ) {
unsigned long numero;
char *riga = NULL;
int err = 1;
do {
svuota_console();
printf( "\nInserisci un numero da scomporre: " );
if( leggi_riga_da_console(&riga,NULL) == 0 ) {
if( stringa_in_numero_intero(riga,&numero) == 0 ) {
err = 0;
} else mostra_errore_in_console( "l'input non e' un numero intero" );
free( riga ); riga = NULL;
} else mostra_errore_in_console( "impossibile allocare" );
} while( err != 0 );
svuota_console();
printf( "\n" );
return numero;
}
/*==============================================================================
Legge una riga di testo di lunghezza arbitraria dalla console. La riga letta
viene collocata in uno spazio di memoria allocato dinamicamente il cui puntatore
viene immesso in *riga. Se dim_riga non e' NULL, le dimensioni della stringa
risultante sono collocate in *dim_riga (escluso il carattere terminatore).
Spetta al chiamante liberare con free() la memoria allocata.
Valori di ritorno:
0 tutto bene
1 parametri non validi (puntatori NULL)
4 impossibile allocare dinamicamente la memoria necessaria
==============================================================================*/
int leggi_riga_da_console( char **riga, size_t *dim_riga ) {
const size_t inc = 16; // procede per blocchi d'allocazione di inc byte
size_t dr, dm; // dr = dimensioni riga; dm = dimensioni memoria
char *tmp, *aux;
int c;
if( dim_riga ) *dim_riga = 0;
if( riga ) *riga = NULL; else return 1;
// alloca un primo blocco di memoria dinamica
dm = inc;
tmp = malloc( dm+1 );
if( !tmp ) return 4;
// legge i dati nella memoria dinamica, ridimensionandola se necessario
for( dr=0, c=fgetc(stdin); c!='\n' && c!=EOF; ++dr, c=fgetc(stdin) ) {
if( dr < (dm-1) ) {
tmp[dr] = c;
}
else {
aux = tmp; // caso mai realloc fallisse (vedi else)
if( (tmp=realloc(tmp,dm+inc)) ) {
dm += inc;
tmp[dr] = c;
}
else {
free( aux );
return 4;
}
}
}
*riga = tmp;
(*riga)[dr] = '{parsed_message}'; // termina la stringa
if( dim_riga ) *dim_riga = dr;
return 0;
}
/*==============================================================================
Tramile la funzione standard strtoul() tenta di verificare la validita' della
stringa immessa dall'utente. Restituisce in *n il numero intero senza segno
rappresentato dalla stringa s. Se tutto va bene, il valore di ritorno e' 0; in
caso contrario e' diverso da 0.
==============================================================================*/
int stringa_in_numero_intero( const char *s, unsigned long *n ) {
char *fine = NULL;
*n = strtoul( s, &fine, 10 );
return s == fine;
}
/*==============================================================================
Scrive, centrandole nella console, una serie di ns stringhe ricavandole
dall'array s[]. Al termine della scrittura si pone in attesa della pressione del
tasto "invio" da parte dell'utente. Quando l'utente preme "invio", svuota la
console e ritorna.
==============================================================================*/
void presenta_in_console( const char *s[], int ns ) {
if( s ) {
int i;
traccia_riga_in_console( '=', LARGHEZZA_CONSOLE-1 ); A_CAPO;
for( i=0; i<ns; ++i ) { centra_in_console( s[i] ); A_CAPO; }
traccia_riga_in_console( '=', LARGHEZZA_CONSOLE-1 ); A_CAPO; A_CAPO;
attendi_invio_da_console();
svuota_console();
}
}
/*==============================================================================
Scrive nella console la stringa s, facendola precedere dalla quantità di spazi
necessari per centrarla.
==============================================================================*/
void centra_in_console( const char *s ) {
if( s ) {
char buff[LARGHEZZA_CONSOLE/2+4];
int l = (LARGHEZZA_CONSOLE-strlen(s))/2;
memset( buff, ' ', l ); buff[l] = '{parsed_message}';
printf( "%s%s", buff, s );
}
}
/*==============================================================================
Scrive nella console una serie di nc caratteri c. Se nc e' maggiore di
LARGHEZZA_CONSOLE la funzione scrive comunque un massimo di LARGHEZZA_CONSOLE
caratteri.
==============================================================================*/
void traccia_riga_in_console( int c, int nc ) {
if( nc > 0 ) {
char buff[LARGHEZZA_CONSOLE+4];
nc = nc<=LARGHEZZA_CONSOLE ? nc : LARGHEZZA_CONSOLE;
memset( buff, c, nc ); buff[nc] = '{parsed_message}';
printf( "%s", buff );
}
}
/*==============================================================================
Scrive nella console la stringa msg, preceduta da una breve intestazione
d'errore. Emette un "bip" d'avviso sonoro. Al termine della scrittura si pone in
attesa della pressione del tasto "invio" da parte dell'utente. Quando l'utente
preme "invio", ritorna.
==============================================================================*/
void mostra_errore_in_console( const char *msg ) {
if( msg ) {
printf( "\a\n===> ERRORE <===\n%s\n\n", msg );
attendi_invio_da_console();
}
}
/*==============================================================================
Si pone in attesa della pressione del tasto "invio" da parte dell'utente. Quando
l'utente preme "invio", svuota lo stream di input e ritorna.
==============================================================================*/
void attendi_invio_da_console( void ) {
printf( "Premi \"invio\" per continuare... " );
while( getchar() != '\n' );
}
/*==============================================================================
Usa system() per richiedere lo svuotamento della console.
==============================================================================*/
void svuota_console( void ) {
system( "cls" );
}
/*==============================================================================
Scrive nella console una tabella che raffigura il procedimento di scomposizione
in fattori primi del numero n, secondo i dati immagazzinati nell'array fattori.
==============================================================================*/
void scrivi_tabella_scomposizione( unsigned long n, unsigned long *fattori ) {
int i;
for( i=0; n!=1; ++i ) {
printf( "%12lu | %lu\n", n, fattori[i] );
n /= fattori[i];
}
printf( "%12lu | \n\n", n );
}
/*==============================================================================
Scrive nella console una formula che descrive la scomposizione in fattori del
numero n, secondo i dati immagazzinati nell'array fattori.
==============================================================================*/
void scrivi_scomposizione_in_linea( unsigned long n, unsigned long *fattori ) {
unsigned long fc = 0; // fc = fattore corrente
int ec; // ec = esponente corrente
int tf; // tf = totale fattori
int i;
for( tf=0; fattori[tf]!=0; ++tf );
if( tf == 0 ) return;
printf( " %lu = ", n );
for( i=tf-1, fc=fattori[i], ec=0; i>=0; --i ) {
if( fc != fattori[i] ) {
printf( "%lu", fc );
if( ec != 1 ) printf( "^%d", ec );
printf( " * " );
fc = fattori[i];
ec = 1;
}
else {
++ec;
}
}
printf( "%lu", fc );
if( ec != 1 ) printf( "^%d", ec );
printf( "\n" );
}
/*==============================================================================
Chiede all'utente se intende continuare con un'ulteriore scomposizione o uscire
dal programma.
==============================================================================*/
int chiedi_se_continuare( void ) {
char *riga = NULL;
int esito = 0xFFFF;
do {
printf( "\nVuoi scomporre un altro numero? (S/N) " );
if( leggi_riga_da_console(&riga,NULL) == 0 ) {
switch( toupper(*riga) ) {
case 'S': esito = 1; break;
case 'N': esito = 0; break;
default: mostra_errore_in_console( "input non valido" );
}
free( riga ); riga = NULL;
} else mostra_errore_in_console( "impossibile allocare" );
} while( esito == 0xFFFF );
return esito;
}
'; // termina la stringa
if( dim_riga ) *dim_riga = dr;
return 0;
}
/*==============================================================================
Tramile la funzione standard strtoul() tenta di verificare la validita' della
stringa immessa dall'utente. Restituisce in *n il numero intero senza segno
rappresentato dalla stringa s. Se tutto va bene, il valore di ritorno e' 0; in
caso contrario e' diverso da 0.
==============================================================================*/
int stringa_in_numero_intero( const char *s, unsigned long *n ) {
char *fine = NULL;
*n = strtoul( s, &fine, 10 );
return s == fine;
}
/*==============================================================================
Scrive, centrandole nella console, una serie di ns stringhe ricavandole
dall'array s[]. Al termine della scrittura si pone in attesa della pressione del
tasto "invio" da parte dell'utente. Quando l'utente preme "invio", svuota la
console e ritorna.
==============================================================================*/
void presenta_in_console( const char *s[], int ns ) {
if( s ) {
int i;
traccia_riga_in_console( '=', LARGHEZZA_CONSOLE-1 ); A_CAPO;
for( i=0; i<ns; ++i ) { centra_in_console( s[i] ); A_CAPO; }
traccia_riga_in_console( '=', LARGHEZZA_CONSOLE-1 ); A_CAPO; A_CAPO;
attendi_invio_da_console();
svuota_console();
}
}
/*==============================================================================
Scrive nella console la stringa s, facendola precedere dalla quantità di spazi
necessari per centrarla.
==============================================================================*/
void centra_in_console( const char *s ) {
if( s ) {
char buff[LARGHEZZA_CONSOLE/2+4];
int l = (LARGHEZZA_CONSOLE-strlen(s))/2;
memset( buff, ' ', l ); buff[l] = 'Dubito che sia possibile parlare di "ottimizzazione", però m'è preso il ghiribizzo di pasticciare un po' con la tua idea di un marchingegno per scomporre numeri in fattori primi. Ne è venuta fuori una roba, distribuita su tre file che credo sia in ANSI C. Il compilatore che uso (mingw) ha sputato fuori un eseguibile di 11 Kb in tutto, alla faccia del C++ che anche solo usando cin e cout s'avvicinava al Mb!
Sicuramente ci saranno ingenuità mostruose, sia perché le mie conoscenze matematiche sono quel che sono, sia perché ho fatto tutto un po' di getto, appiccicando funzioni su funzioni preso dal fuoco sacro del giocare a fingere d'essere un programmatore della madonna! (che non è vero)
1. main.c
#include <stdio.h>
#include <string.h>
#include "interfaccia.h"
// ===> MACRO/COSTANTI/STRINGHE <===============================================
#define MAX_FATTORI 36 // in effetti, unsigned long puo' contenere un valore
// massimo di 2^32-1, per cui nella scomposizione non
// ci possono essere piu' di 32 fattori primi
const char *kStrPres[] = {
"SCOMPOSIZIONE IN FATTORI PRIMI",
"questo programma scompone in fattori primi valori interi compresi",
"tra 2 e 4294967295, presentando il risultato sia in forma di",
"calcolo in colonna, sia come formula riassuntiva in linea"
};
const int kNStrPres = sizeof(kStrPres)/sizeof(*kStrPres);
// ===> PROTOTIPI DI FUNZIONI <=================================================
void scomponi( unsigned long n, unsigned long *fattori );
// ===> FUNZIONE D'ACCESSO AL PROGRAMMA <=======================================
int main() {
unsigned long n, fattori[MAX_FATTORI];
presenta_in_console( kStrPres, kNStrPres );
do {
memset( fattori, 0, sizeof(*fattori)*MAX_FATTORI );
n = chiedi_numero_da_scomporre();
scomponi( n, fattori );
scrivi_tabella_scomposizione( n, fattori );
scrivi_scomposizione_in_linea( n, fattori );
} while( chiedi_se_continuare() );
return 0;
}
// ===> FUNZIONE DI SCOMPOSIZIONE IN FATTORI PRIMI <============================
void scomponi( unsigned long n, unsigned long *fattori ) {
if( n > 1 ) {
unsigned long d, max;
int nf; // la quantita' dei fattori trovati
for( d=2, nf=0; n%d==0; ++nf ) {
fattori[nf] = d;
n /= d;
}
if( n == 1 ) return;
for( max=n, d=3; d<=max; ) {
if( n%d ) { d+=2; continue; }
fattori[nf++] = d;
if( (n/=d) == 1 ) break;
max = n;
}
}
else {
if( n == 0 )
printf( "Lo zero non e' scomponibile.\n\n" );
else printf( "L'unita' non e' scomponibile.\n\n" );
}
}
2. interfaccia.h
#ifndef INTERFACCIA_H_INCLUDED
#define INTERFACCIA_H_INCLUDED
void presenta_in_console( const char *s[], int ns );
unsigned long chiedi_numero_da_scomporre( void );
void scrivi_tabella_scomposizione( unsigned long n, unsigned long *fattori );
void scrivi_scomposizione_in_linea( unsigned long n, unsigned long *fattori );
int chiedi_se_continuare( void );
#endif // INTERFACCIA_H_INCLUDED
3. interfaccia.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "interfaccia.h"
// ===> MACRO/COSTANTI <========================================================
#define LARGHEZZA_CONSOLE 80 // specificare la larghezza della console
#define A_CAPO printf("\n")
// ===> PROTOTIPI DI FUNZIONI <=================================================
int leggi_riga_da_console( char **riga, size_t *dim_riga );
int stringa_in_numero_intero( const char *s, unsigned long *n );
void centra_in_console( const char *s );
void traccia_riga_in_console( int c, int nc );
void mostra_errore_in_console( const char *msg );
void attendi_invio_da_console( void );
void svuota_console( void );
/*==============================================================================
Chiede all'utente di immettere il numero che intende scomporre. Verifica il dato
immesso per assicurarsi che sia effettivamente un numero intero. La verifica
avviene tramite la funzione standard strtoul(). La richiesta viene iterata fino
a che viene immesso un valore accettabile.
==============================================================================*/
unsigned long chiedi_numero_da_scomporre( void ) {
unsigned long numero;
char *riga = NULL;
int err = 1;
do {
svuota_console();
printf( "\nInserisci un numero da scomporre: " );
if( leggi_riga_da_console(&riga,NULL) == 0 ) {
if( stringa_in_numero_intero(riga,&numero) == 0 ) {
err = 0;
} else mostra_errore_in_console( "l'input non e' un numero intero" );
free( riga ); riga = NULL;
} else mostra_errore_in_console( "impossibile allocare" );
} while( err != 0 );
svuota_console();
printf( "\n" );
return numero;
}
/*==============================================================================
Legge una riga di testo di lunghezza arbitraria dalla console. La riga letta
viene collocata in uno spazio di memoria allocato dinamicamente il cui puntatore
viene immesso in *riga. Se dim_riga non e' NULL, le dimensioni della stringa
risultante sono collocate in *dim_riga (escluso il carattere terminatore).
Spetta al chiamante liberare con free() la memoria allocata.
Valori di ritorno:
0 tutto bene
1 parametri non validi (puntatori NULL)
4 impossibile allocare dinamicamente la memoria necessaria
==============================================================================*/
int leggi_riga_da_console( char **riga, size_t *dim_riga ) {
const size_t inc = 16; // procede per blocchi d'allocazione di inc byte
size_t dr, dm; // dr = dimensioni riga; dm = dimensioni memoria
char *tmp, *aux;
int c;
if( dim_riga ) *dim_riga = 0;
if( riga ) *riga = NULL; else return 1;
// alloca un primo blocco di memoria dinamica
dm = inc;
tmp = malloc( dm+1 );
if( !tmp ) return 4;
// legge i dati nella memoria dinamica, ridimensionandola se necessario
for( dr=0, c=fgetc(stdin); c!='\n' && c!=EOF; ++dr, c=fgetc(stdin) ) {
if( dr < (dm-1) ) {
tmp[dr] = c;
}
else {
aux = tmp; // caso mai realloc fallisse (vedi else)
if( (tmp=realloc(tmp,dm+inc)) ) {
dm += inc;
tmp[dr] = c;
}
else {
free( aux );
return 4;
}
}
}
*riga = tmp;
(*riga)[dr] = '{parsed_message}'; // termina la stringa
if( dim_riga ) *dim_riga = dr;
return 0;
}
/*==============================================================================
Tramile la funzione standard strtoul() tenta di verificare la validita' della
stringa immessa dall'utente. Restituisce in *n il numero intero senza segno
rappresentato dalla stringa s. Se tutto va bene, il valore di ritorno e' 0; in
caso contrario e' diverso da 0.
==============================================================================*/
int stringa_in_numero_intero( const char *s, unsigned long *n ) {
char *fine = NULL;
*n = strtoul( s, &fine, 10 );
return s == fine;
}
/*==============================================================================
Scrive, centrandole nella console, una serie di ns stringhe ricavandole
dall'array s[]. Al termine della scrittura si pone in attesa della pressione del
tasto "invio" da parte dell'utente. Quando l'utente preme "invio", svuota la
console e ritorna.
==============================================================================*/
void presenta_in_console( const char *s[], int ns ) {
if( s ) {
int i;
traccia_riga_in_console( '=', LARGHEZZA_CONSOLE-1 ); A_CAPO;
for( i=0; i<ns; ++i ) { centra_in_console( s[i] ); A_CAPO; }
traccia_riga_in_console( '=', LARGHEZZA_CONSOLE-1 ); A_CAPO; A_CAPO;
attendi_invio_da_console();
svuota_console();
}
}
/*==============================================================================
Scrive nella console la stringa s, facendola precedere dalla quantità di spazi
necessari per centrarla.
==============================================================================*/
void centra_in_console( const char *s ) {
if( s ) {
char buff[LARGHEZZA_CONSOLE/2+4];
int l = (LARGHEZZA_CONSOLE-strlen(s))/2;
memset( buff, ' ', l ); buff[l] = '{parsed_message}';
printf( "%s%s", buff, s );
}
}
/*==============================================================================
Scrive nella console una serie di nc caratteri c. Se nc e' maggiore di
LARGHEZZA_CONSOLE la funzione scrive comunque un massimo di LARGHEZZA_CONSOLE
caratteri.
==============================================================================*/
void traccia_riga_in_console( int c, int nc ) {
if( nc > 0 ) {
char buff[LARGHEZZA_CONSOLE+4];
nc = nc<=LARGHEZZA_CONSOLE ? nc : LARGHEZZA_CONSOLE;
memset( buff, c, nc ); buff[nc] = '{parsed_message}';
printf( "%s", buff );
}
}
/*==============================================================================
Scrive nella console la stringa msg, preceduta da una breve intestazione
d'errore. Emette un "bip" d'avviso sonoro. Al termine della scrittura si pone in
attesa della pressione del tasto "invio" da parte dell'utente. Quando l'utente
preme "invio", ritorna.
==============================================================================*/
void mostra_errore_in_console( const char *msg ) {
if( msg ) {
printf( "\a\n===> ERRORE <===\n%s\n\n", msg );
attendi_invio_da_console();
}
}
/*==============================================================================
Si pone in attesa della pressione del tasto "invio" da parte dell'utente. Quando
l'utente preme "invio", svuota lo stream di input e ritorna.
==============================================================================*/
void attendi_invio_da_console( void ) {
printf( "Premi \"invio\" per continuare... " );
while( getchar() != '\n' );
}
/*==============================================================================
Usa system() per richiedere lo svuotamento della console.
==============================================================================*/
void svuota_console( void ) {
system( "cls" );
}
/*==============================================================================
Scrive nella console una tabella che raffigura il procedimento di scomposizione
in fattori primi del numero n, secondo i dati immagazzinati nell'array fattori.
==============================================================================*/
void scrivi_tabella_scomposizione( unsigned long n, unsigned long *fattori ) {
int i;
for( i=0; n!=1; ++i ) {
printf( "%12lu | %lu\n", n, fattori[i] );
n /= fattori[i];
}
printf( "%12lu | \n\n", n );
}
/*==============================================================================
Scrive nella console una formula che descrive la scomposizione in fattori del
numero n, secondo i dati immagazzinati nell'array fattori.
==============================================================================*/
void scrivi_scomposizione_in_linea( unsigned long n, unsigned long *fattori ) {
unsigned long fc = 0; // fc = fattore corrente
int ec; // ec = esponente corrente
int tf; // tf = totale fattori
int i;
for( tf=0; fattori[tf]!=0; ++tf );
if( tf == 0 ) return;
printf( " %lu = ", n );
for( i=tf-1, fc=fattori[i], ec=0; i>=0; --i ) {
if( fc != fattori[i] ) {
printf( "%lu", fc );
if( ec != 1 ) printf( "^%d", ec );
printf( " * " );
fc = fattori[i];
ec = 1;
}
else {
++ec;
}
}
printf( "%lu", fc );
if( ec != 1 ) printf( "^%d", ec );
printf( "\n" );
}
/*==============================================================================
Chiede all'utente se intende continuare con un'ulteriore scomposizione o uscire
dal programma.
==============================================================================*/
int chiedi_se_continuare( void ) {
char *riga = NULL;
int esito = 0xFFFF;
do {
printf( "\nVuoi scomporre un altro numero? (S/N) " );
if( leggi_riga_da_console(&riga,NULL) == 0 ) {
switch( toupper(*riga) ) {
case 'S': esito = 1; break;
case 'N': esito = 0; break;
default: mostra_errore_in_console( "input non valido" );
}
free( riga ); riga = NULL;
} else mostra_errore_in_console( "impossibile allocare" );
} while( esito == 0xFFFF );
return esito;
}
';
printf( "%s%s", buff, s );
}
}
/*==============================================================================
Scrive nella console una serie di nc caratteri c. Se nc e' maggiore di
LARGHEZZA_CONSOLE la funzione scrive comunque un massimo di LARGHEZZA_CONSOLE
caratteri.
==============================================================================*/
void traccia_riga_in_console( int c, int nc ) {
if( nc > 0 ) {
char buff[LARGHEZZA_CONSOLE+4];
nc = nc<=LARGHEZZA_CONSOLE ? nc : LARGHEZZA_CONSOLE;
memset( buff, c, nc ); buff[nc] = 'Dubito che sia possibile parlare di "ottimizzazione", però m'è preso il ghiribizzo di pasticciare un po' con la tua idea di un marchingegno per scomporre numeri in fattori primi. Ne è venuta fuori una roba, distribuita su tre file che credo sia in ANSI C. Il compilatore che uso (mingw) ha sputato fuori un eseguibile di 11 Kb in tutto, alla faccia del C++ che anche solo usando cin e cout s'avvicinava al Mb!
Sicuramente ci saranno ingenuità mostruose, sia perché le mie conoscenze matematiche sono quel che sono, sia perché ho fatto tutto un po' di getto, appiccicando funzioni su funzioni preso dal fuoco sacro del giocare a fingere d'essere un programmatore della madonna! (che non è vero)
1. main.c
#include <stdio.h>
#include <string.h>
#include "interfaccia.h"
// ===> MACRO/COSTANTI/STRINGHE <===============================================
#define MAX_FATTORI 36 // in effetti, unsigned long puo' contenere un valore
// massimo di 2^32-1, per cui nella scomposizione non
// ci possono essere piu' di 32 fattori primi
const char *kStrPres[] = {
"SCOMPOSIZIONE IN FATTORI PRIMI",
"questo programma scompone in fattori primi valori interi compresi",
"tra 2 e 4294967295, presentando il risultato sia in forma di",
"calcolo in colonna, sia come formula riassuntiva in linea"
};
const int kNStrPres = sizeof(kStrPres)/sizeof(*kStrPres);
// ===> PROTOTIPI DI FUNZIONI <=================================================
void scomponi( unsigned long n, unsigned long *fattori );
// ===> FUNZIONE D'ACCESSO AL PROGRAMMA <=======================================
int main() {
unsigned long n, fattori[MAX_FATTORI];
presenta_in_console( kStrPres, kNStrPres );
do {
memset( fattori, 0, sizeof(*fattori)*MAX_FATTORI );
n = chiedi_numero_da_scomporre();
scomponi( n, fattori );
scrivi_tabella_scomposizione( n, fattori );
scrivi_scomposizione_in_linea( n, fattori );
} while( chiedi_se_continuare() );
return 0;
}
// ===> FUNZIONE DI SCOMPOSIZIONE IN FATTORI PRIMI <============================
void scomponi( unsigned long n, unsigned long *fattori ) {
if( n > 1 ) {
unsigned long d, max;
int nf; // la quantita' dei fattori trovati
for( d=2, nf=0; n%d==0; ++nf ) {
fattori[nf] = d;
n /= d;
}
if( n == 1 ) return;
for( max=n, d=3; d<=max; ) {
if( n%d ) { d+=2; continue; }
fattori[nf++] = d;
if( (n/=d) == 1 ) break;
max = n;
}
}
else {
if( n == 0 )
printf( "Lo zero non e' scomponibile.\n\n" );
else printf( "L'unita' non e' scomponibile.\n\n" );
}
}
2. interfaccia.h
#ifndef INTERFACCIA_H_INCLUDED
#define INTERFACCIA_H_INCLUDED
void presenta_in_console( const char *s[], int ns );
unsigned long chiedi_numero_da_scomporre( void );
void scrivi_tabella_scomposizione( unsigned long n, unsigned long *fattori );
void scrivi_scomposizione_in_linea( unsigned long n, unsigned long *fattori );
int chiedi_se_continuare( void );
#endif // INTERFACCIA_H_INCLUDED
3. interfaccia.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "interfaccia.h"
// ===> MACRO/COSTANTI <========================================================
#define LARGHEZZA_CONSOLE 80 // specificare la larghezza della console
#define A_CAPO printf("\n")
// ===> PROTOTIPI DI FUNZIONI <=================================================
int leggi_riga_da_console( char **riga, size_t *dim_riga );
int stringa_in_numero_intero( const char *s, unsigned long *n );
void centra_in_console( const char *s );
void traccia_riga_in_console( int c, int nc );
void mostra_errore_in_console( const char *msg );
void attendi_invio_da_console( void );
void svuota_console( void );
/*==============================================================================
Chiede all'utente di immettere il numero che intende scomporre. Verifica il dato
immesso per assicurarsi che sia effettivamente un numero intero. La verifica
avviene tramite la funzione standard strtoul(). La richiesta viene iterata fino
a che viene immesso un valore accettabile.
==============================================================================*/
unsigned long chiedi_numero_da_scomporre( void ) {
unsigned long numero;
char *riga = NULL;
int err = 1;
do {
svuota_console();
printf( "\nInserisci un numero da scomporre: " );
if( leggi_riga_da_console(&riga,NULL) == 0 ) {
if( stringa_in_numero_intero(riga,&numero) == 0 ) {
err = 0;
} else mostra_errore_in_console( "l'input non e' un numero intero" );
free( riga ); riga = NULL;
} else mostra_errore_in_console( "impossibile allocare" );
} while( err != 0 );
svuota_console();
printf( "\n" );
return numero;
}
/*==============================================================================
Legge una riga di testo di lunghezza arbitraria dalla console. La riga letta
viene collocata in uno spazio di memoria allocato dinamicamente il cui puntatore
viene immesso in *riga. Se dim_riga non e' NULL, le dimensioni della stringa
risultante sono collocate in *dim_riga (escluso il carattere terminatore).
Spetta al chiamante liberare con free() la memoria allocata.
Valori di ritorno:
0 tutto bene
1 parametri non validi (puntatori NULL)
4 impossibile allocare dinamicamente la memoria necessaria
==============================================================================*/
int leggi_riga_da_console( char **riga, size_t *dim_riga ) {
const size_t inc = 16; // procede per blocchi d'allocazione di inc byte
size_t dr, dm; // dr = dimensioni riga; dm = dimensioni memoria
char *tmp, *aux;
int c;
if( dim_riga ) *dim_riga = 0;
if( riga ) *riga = NULL; else return 1;
// alloca un primo blocco di memoria dinamica
dm = inc;
tmp = malloc( dm+1 );
if( !tmp ) return 4;
// legge i dati nella memoria dinamica, ridimensionandola se necessario
for( dr=0, c=fgetc(stdin); c!='\n' && c!=EOF; ++dr, c=fgetc(stdin) ) {
if( dr < (dm-1) ) {
tmp[dr] = c;
}
else {
aux = tmp; // caso mai realloc fallisse (vedi else)
if( (tmp=realloc(tmp,dm+inc)) ) {
dm += inc;
tmp[dr] = c;
}
else {
free( aux );
return 4;
}
}
}
*riga = tmp;
(*riga)[dr] = '{parsed_message}'; // termina la stringa
if( dim_riga ) *dim_riga = dr;
return 0;
}
/*==============================================================================
Tramile la funzione standard strtoul() tenta di verificare la validita' della
stringa immessa dall'utente. Restituisce in *n il numero intero senza segno
rappresentato dalla stringa s. Se tutto va bene, il valore di ritorno e' 0; in
caso contrario e' diverso da 0.
==============================================================================*/
int stringa_in_numero_intero( const char *s, unsigned long *n ) {
char *fine = NULL;
*n = strtoul( s, &fine, 10 );
return s == fine;
}
/*==============================================================================
Scrive, centrandole nella console, una serie di ns stringhe ricavandole
dall'array s[]. Al termine della scrittura si pone in attesa della pressione del
tasto "invio" da parte dell'utente. Quando l'utente preme "invio", svuota la
console e ritorna.
==============================================================================*/
void presenta_in_console( const char *s[], int ns ) {
if( s ) {
int i;
traccia_riga_in_console( '=', LARGHEZZA_CONSOLE-1 ); A_CAPO;
for( i=0; i<ns; ++i ) { centra_in_console( s[i] ); A_CAPO; }
traccia_riga_in_console( '=', LARGHEZZA_CONSOLE-1 ); A_CAPO; A_CAPO;
attendi_invio_da_console();
svuota_console();
}
}
/*==============================================================================
Scrive nella console la stringa s, facendola precedere dalla quantità di spazi
necessari per centrarla.
==============================================================================*/
void centra_in_console( const char *s ) {
if( s ) {
char buff[LARGHEZZA_CONSOLE/2+4];
int l = (LARGHEZZA_CONSOLE-strlen(s))/2;
memset( buff, ' ', l ); buff[l] = '{parsed_message}';
printf( "%s%s", buff, s );
}
}
/*==============================================================================
Scrive nella console una serie di nc caratteri c. Se nc e' maggiore di
LARGHEZZA_CONSOLE la funzione scrive comunque un massimo di LARGHEZZA_CONSOLE
caratteri.
==============================================================================*/
void traccia_riga_in_console( int c, int nc ) {
if( nc > 0 ) {
char buff[LARGHEZZA_CONSOLE+4];
nc = nc<=LARGHEZZA_CONSOLE ? nc : LARGHEZZA_CONSOLE;
memset( buff, c, nc ); buff[nc] = '{parsed_message}';
printf( "%s", buff );
}
}
/*==============================================================================
Scrive nella console la stringa msg, preceduta da una breve intestazione
d'errore. Emette un "bip" d'avviso sonoro. Al termine della scrittura si pone in
attesa della pressione del tasto "invio" da parte dell'utente. Quando l'utente
preme "invio", ritorna.
==============================================================================*/
void mostra_errore_in_console( const char *msg ) {
if( msg ) {
printf( "\a\n===> ERRORE <===\n%s\n\n", msg );
attendi_invio_da_console();
}
}
/*==============================================================================
Si pone in attesa della pressione del tasto "invio" da parte dell'utente. Quando
l'utente preme "invio", svuota lo stream di input e ritorna.
==============================================================================*/
void attendi_invio_da_console( void ) {
printf( "Premi \"invio\" per continuare... " );
while( getchar() != '\n' );
}
/*==============================================================================
Usa system() per richiedere lo svuotamento della console.
==============================================================================*/
void svuota_console( void ) {
system( "cls" );
}
/*==============================================================================
Scrive nella console una tabella che raffigura il procedimento di scomposizione
in fattori primi del numero n, secondo i dati immagazzinati nell'array fattori.
==============================================================================*/
void scrivi_tabella_scomposizione( unsigned long n, unsigned long *fattori ) {
int i;
for( i=0; n!=1; ++i ) {
printf( "%12lu | %lu\n", n, fattori[i] );
n /= fattori[i];
}
printf( "%12lu | \n\n", n );
}
/*==============================================================================
Scrive nella console una formula che descrive la scomposizione in fattori del
numero n, secondo i dati immagazzinati nell'array fattori.
==============================================================================*/
void scrivi_scomposizione_in_linea( unsigned long n, unsigned long *fattori ) {
unsigned long fc = 0; // fc = fattore corrente
int ec; // ec = esponente corrente
int tf; // tf = totale fattori
int i;
for( tf=0; fattori[tf]!=0; ++tf );
if( tf == 0 ) return;
printf( " %lu = ", n );
for( i=tf-1, fc=fattori[i], ec=0; i>=0; --i ) {
if( fc != fattori[i] ) {
printf( "%lu", fc );
if( ec != 1 ) printf( "^%d", ec );
printf( " * " );
fc = fattori[i];
ec = 1;
}
else {
++ec;
}
}
printf( "%lu", fc );
if( ec != 1 ) printf( "^%d", ec );
printf( "\n" );
}
/*==============================================================================
Chiede all'utente se intende continuare con un'ulteriore scomposizione o uscire
dal programma.
==============================================================================*/
int chiedi_se_continuare( void ) {
char *riga = NULL;
int esito = 0xFFFF;
do {
printf( "\nVuoi scomporre un altro numero? (S/N) " );
if( leggi_riga_da_console(&riga,NULL) == 0 ) {
switch( toupper(*riga) ) {
case 'S': esito = 1; break;
case 'N': esito = 0; break;
default: mostra_errore_in_console( "input non valido" );
}
free( riga ); riga = NULL;
} else mostra_errore_in_console( "impossibile allocare" );
} while( esito == 0xFFFF );
return esito;
}
';
printf( "%s", buff );
}
}
/*==============================================================================
Scrive nella console la stringa msg, preceduta da una breve intestazione
d'errore. Emette un "bip" d'avviso sonoro. Al termine della scrittura si pone in
attesa della pressione del tasto "invio" da parte dell'utente. Quando l'utente
preme "invio", ritorna.
==============================================================================*/
void mostra_errore_in_console( const char *msg ) {
if( msg ) {
printf( "\a\n===> ERRORE <===\n%s\n\n", msg );
attendi_invio_da_console();
}
}
/*==============================================================================
Si pone in attesa della pressione del tasto "invio" da parte dell'utente. Quando
l'utente preme "invio", svuota lo stream di input e ritorna.
==============================================================================*/
void attendi_invio_da_console( void ) {
printf( "Premi \"invio\" per continuare... " );
while( getchar() != '\n' );
}
/*==============================================================================
Usa system() per richiedere lo svuotamento della console.
==============================================================================*/
void svuota_console( void ) {
system( "cls" );
}
/*==============================================================================
Scrive nella console una tabella che raffigura il procedimento di scomposizione
in fattori primi del numero n, secondo i dati immagazzinati nell'array fattori.
==============================================================================*/
void scrivi_tabella_scomposizione( unsigned long n, unsigned long *fattori ) {
int i;
for( i=0; n!=1; ++i ) {
printf( "%12lu | %lu\n", n, fattori[i] );
n /= fattori[i];
}
printf( "%12lu | \n\n", n );
}
/*==============================================================================
Scrive nella console una formula che descrive la scomposizione in fattori del
numero n, secondo i dati immagazzinati nell'array fattori.
==============================================================================*/
void scrivi_scomposizione_in_linea( unsigned long n, unsigned long *fattori ) {
unsigned long fc = 0; // fc = fattore corrente
int ec; // ec = esponente corrente
int tf; // tf = totale fattori
int i;
for( tf=0; fattori[tf]!=0; ++tf );
if( tf == 0 ) return;
printf( " %lu = ", n );
for( i=tf-1, fc=fattori[i], ec=0; i>=0; --i ) {
if( fc != fattori[i] ) {
printf( "%lu", fc );
if( ec != 1 ) printf( "^%d", ec );
printf( " * " );
fc = fattori[i];
ec = 1;
}
else {
++ec;
}
}
printf( "%lu", fc );
if( ec != 1 ) printf( "^%d", ec );
printf( "\n" );
}
/*==============================================================================
Chiede all'utente se intende continuare con un'ulteriore scomposizione o uscire
dal programma.
==============================================================================*/
int chiedi_se_continuare( void ) {
char *riga = NULL;
int esito = 0xFFFF;
do {
printf( "\nVuoi scomporre un altro numero? (S/N) " );
if( leggi_riga_da_console(&riga,NULL) == 0 ) {
switch( toupper(*riga) ) {
case 'S': esito = 1; break;
case 'N': esito = 0; break;
default: mostra_errore_in_console( "input non valido" );
}
free( riga ); riga = NULL;
} else mostra_errore_in_console( "impossibile allocare" );
} while( esito == 0xFFFF );
return esito;
}
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.