[C] Conteggio delle parole di una stringa di caratteri
L'esercizio da svolgere è il seguente:
Esercizio 2. Si scriva un programma C che:
a. Acquisisca una stringa di massimo N caratteri (con N valore costante)
b. Ne manipoli il contenuto
i. Trasformando tutte le lettere minuscole in maiuscole
ii. Rimpiazzando tutti i caratteri non alfanumerici con il carattere ‘_’
iii. Sostituendo i caratteri numerici con il carattere ‘*’
c. Scandisca la stringa manipolata per contare quante parole sono
presenti al suo interno, considerando una o più occorrenze del
carattere ‘_’ come separatore tra parole.
I punti a. e b. sono riuscito a farli, ma il punto c. mi lascia un po' perplesso... il mio svolgimento dell'esercizio è il seguente:
Il problema è che inserendo una frase mi conta una parola in meno di quelle effettivamente inserite nella stringa...
Esercizio 2. Si scriva un programma C che:
a. Acquisisca una stringa di massimo N caratteri (con N valore costante)
b. Ne manipoli il contenuto
i. Trasformando tutte le lettere minuscole in maiuscole
ii. Rimpiazzando tutti i caratteri non alfanumerici con il carattere ‘_’
iii. Sostituendo i caratteri numerici con il carattere ‘*’
c. Scandisca la stringa manipolata per contare quante parole sono
presenti al suo interno, considerando una o più occorrenze del
carattere ‘_’ come separatore tra parole.
I punti a. e b. sono riuscito a farli, ma il punto c. mi lascia un po' perplesso... il mio svolgimento dell'esercizio è il seguente:
#include <stdio.h> #include <stdlib.h> #define SIZE 300 #include <string.h> #include <ctype.h> void leggiStringa(char* s1) { printf("Inserire il testo da analizzare:\n"); gets(s1); return; } void maiusc(char* s1) { int i; for(i=0; s1[i]!='\0'; i++) { if(islower(s1[i])) s1[i]=toupper(s1[i]); } return; } void sost1(char* s1) { int i=0; for(i=0; s1[i]!='\0'; i++) { if(isalnum(s1[i])==0) s1[i]='_'; } return; } void sost2(char* s1) { int i; for(i=0; s1[i]!='\0'; i++) { if(isdigit(s1[i])!=0) s1[i]='*'; } return; } int numparole(char* s1) \*CONTEGGIO DEL NUMERO DI PAROLE NELLA STRINGA*\ { int i, parole=0; for(i=0; s1[i]!='\0'; i++) { if((s1[i]=='_') && (s1[i-1]!='_')) parole++; } return parole; } int main() { char s1[SIZE]; leggiStringa(s1); printf("Codifica stringa:\n"); maiusc(s1); sost1(s1); sost2(s1); printf("%s\n\n", s1); printf("Il numero di parole nella stringa e':%d", numparole(s1)); return 0; }
Il problema è che inserendo una frase mi conta una parola in meno di quelle effettivamente inserite nella stringa...
Risposte
Ed è giusto l'errore che hai.
Perchè per come hai impostato tu il conteggio delle parole, l'ultima non te la conterà mai poichè arrivato al carattere terminatore '\0" terminerà il ciclo e non si verificherà la condizione.
Perchè per come hai impostato tu il conteggio delle parole, l'ultima non te la conterà mai poichè arrivato al carattere terminatore '\0" terminerà il ciclo e non si verificherà la condizione.
Ho identificato qualche bug e modificato alcune cose che potevano essere migliorate (secondo il mio parere ) . Oltre a questi miglioramenti avrei anche unificato tutte le modifiche in una sola funzione, ma ho preferito mantenere la struttura generale. Ho anche lanciato clang-format sul file, quindi la formattazione è un po' differente.
Nel codice ho dato per scontato che il codice potesse usare il C99 o il C90 con l'aggiunta delle estensioni più comuni (commenti come il C++ e possibilità di definire le variabili a piacimento). Se così non è, non è difficile eliminare i commenti e definire le variabili all'inizio del blocco.
Qui trovi una versione senza commenti
Nel codice ho dato per scontato che il codice potesse usare il C99 o il C90 con l'aggiunta delle estensioni più comuni (commenti come il C++ e possibilità di definire le variabili a piacimento). Se così non è, non è difficile eliminare i commenti e definire le variabili all'inizio del blocco.
#include <ctype.h> #include <stdio.h> // IMPROVEMENT // Queste due non sono necessarie // #include <stdlib.h> // #include <string.h> #define SIZE 300 // IMPROVEMENT // conviene passare la dimensione del buffer // void leggiStringa(char* s1) void leggiStringa( char *restrict s1, size_t const dim ) { // IMPROVEMENT // E' inutile chiamare printf se devi solo stampare una stringa // printf("Inserire il testo da analizzare:\n"); puts( "Inserire il testo da analizzare:" ); // BUG // ERRORE molto grave!!! Questa funzione e' stata eliminata dall'ultimo // standard. // Questa funzione può produrre problemi di sicurezza MOLTO seri! // gets(s1); fgets( s1, dim, stdin ); // IMPROVEMENT // il return e' inutile // return; } // IMPROVEMENT // conviene passare la dimensione del buffer void maiusc( char *restrict s1, size_t const dim ) { // IMPROVEMENT // dal C99 in poi il C permette di definire le variabili dove si preferisce // int i; // IMPROVEMENT // in teoria non è necessario ma e' meglio controllare di non uscire // dall'array for ( int i = 0; i != dim && s1[i] != '\0'; i++ ) { // IMPROVEMENT // non e' necessario testare prima che sia minuscola // if(islower(s1[i])) // s1[i]=toupper(s1[i]); s1[i] = toupper( s1[i] ); } // IMPROVEMENT // il return e' inutile // return; } // IMPROVEMENT // conviene passare la dimensione del buffer void sost1( char *restrict s1, size_t const dim ) { // IMPROVEMENT // dal C99 in poi il C permette di definire le variabili dove si preferisce // int i; // IMPROVEMENT // in teoria non è necessario ma e' meglio controllare di non uscire // dall'array for ( int i = 0; i != dim && s1[i] != '\0'; i++ ) { // IMPROVEMENT // Essere uguale a zero vuol dire falso nel C if ( !isalnum( s1[i] ) ) s1[i] = '_'; } // IMPROVEMENT // il return e' inutile // return; } // IMPROVEMENT // conviene passare la dimensione del buffer void sost2( char *restrict s1, size_t const dim ) { // IMPROVEMENT // dal C99 in poi il C permette di definire le variabili dove si preferisce // int i; // IMPROVEMENT // in teoria non è necessario ma e' meglio controllare di non uscire // dall'array for ( int i = 0; i != dim && s1[i] != '\0'; i++ ) { // IMPROVEMENT // Diverso da zero vuol dire vero nel C if ( isdigit( s1[i] ) ) s1[i] = '*'; } // IMPROVEMENT // il return e' inutile // return; } // IMPROVEMENT // conviene passare la dimensione del buffer int numparole( char *restrict s1, size_t const dim ) /* BUG I commenti si scrivono con lo slash e non il backslash \* CONTEGGIO DEL NUMERO DI PAROLE NELLA STRINGA *\ */ { int i; int parole = 0; // BUG // Stai accedendo all'elemento -1 dell'array // Inoltre devi considerare il \0 come se fosse un _ if ( dim == 0 || s1[0] == '\0' ) return 0; for ( i = 1; i != dim && s1[i] != '\0'; i++ ) { // if ( ( s1[i] == '_' ) && ( s1[i - 1] != '_' ) ) parole++; if ( s1[i] == '_' ) parole += ( s1[i - 1] != '_' ); } if ( i == dim ) return 0; else return parole + ( s1[i - 1] != '_' ); } // IMPROVEMENT // aggiunto il void per eliminare un warning di Pelles C int main( void ) { char s1[SIZE]; leggiStringa( s1, SIZE ); // IMPROVEMENT // E' inutile chiamare printf se devi solo stampare una stringa // printf("Codifica stringa:\n"); puts( "Codifica stringa:" ); maiusc( s1, SIZE ); sost1( s1, SIZE ); sost2( s1, SIZE ); // IMPROVEMENT // E' inutile chiamare printf se devi solo stampare una stringa // printf("%s\n\n", s1); puts( s1 ); puts( "" ); // questo serve per andare a capo una volta in più printf( "Il numero di parole nella stringa e':%d", numparole( s1, SIZE ) ); // IMPROVEMENT // Lo standard C afferma che se raggiungi la fine del main senza // che si abbia alcun return allora il return 0 è implicito. // Quindi anche questo return 0 è inutile // return 0; }
Qui trovi una versione senza commenti
#include <ctype.h> #include <stdio.h> #define SIZE 300 void leggiStringa( char *restrict s1, size_t const dim ) { puts( "Inserire il testo da analizzare:" ); fgets( s1, dim, stdin ); } void maiusc( char *restrict s1, size_t const dim ) { for ( int i = 0; i != dim && s1[i] != '\0'; i++ ) { s1[i] = toupper( s1[i] ); } } void sost1( char *restrict s1, size_t const dim ) { for ( int i = 0; i != dim && s1[i] != '\0'; i++ ) { if ( !isalnum( s1[i] ) ) s1[i] = '_'; } } void sost2( char *restrict s1, size_t const dim ) { for ( int i = 0; i != dim && s1[i] != '\0'; i++ ) { if ( isdigit( s1[i] ) ) s1[i] = '*'; } } int numparole( char *restrict s1, size_t const dim ) { if ( dim == 0 || s1[0] == '\0' ) return 0; int parole = 0; int i = 1; for ( ; i != dim && s1[i] != '\0'; i++ ) { if ( s1[i] == '_' ) parole += ( s1[i - 1] != '_' ); } if ( i == dim ) return 0; else return parole + ( s1[i - 1] != '_' ); } int main( void ) { char s1[SIZE]; leggiStringa( s1, SIZE ); puts( "Codifica stringa:" ); maiusc( s1, SIZE ); sost1( s1, SIZE ); sost2( s1, SIZE ); puts( s1 ); puts( "" ); printf( "Il numero di parole nella stringa e':%d\n", numparole( s1, SIZE ) ); }
Grazie mille, non avrei potuto ricevere una risposta più completa!