[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!