I have a program that separates words by spaces. I need to count which words in the text contain 4 different vowels. It didn't seem complicated, until I realized that I know how to save the divided words of the function (strtok
) that returns the separated words, and of course, I can't count a single word because the function only prints. I don't know how to save the word individually to calculate how many vowels it contains and continue with the other words, one by one.
#include <stdio.h>
#include <string.h>
#define MAX 100
int main() {
char phase[MAX];
char temp [50];
char delim[] = " ";
printf("Ingrese un texto corto: ");
gets(phase); //Short text with spaces
printf("\n");
for (i = 0; x < phase[x] != '\0'; x) {
if (phase[x] == ' ' || phase[x] == '\t' || phase[x] == '\v') {
//Detect space.
}
}
char *ptr = strtok(phase, delim);
while (ptr != NULL) {
printf("%s\n", ptr); //I need to keep all the words separate.
ptr = strtok(NULL, delim);
}
return 0;
}
Result:
Ingrese un texto corto: Ana come en el refrigerador.
Ana
come
en
el
refrigerador.
CodePudding user response:
I believe this code will solve the task. It's tempting to use strtok()
again to search for vowels, but that would erase any information about word bounds from strtok
's internal memory. So, instead, use strpbrk()
(docs and more docs)
#include <stdio.h>
#include <string.h>
#define MAX 100
int main() {
char text[MAX];
// all isspace() characters for "C" locale
char delimiters[] = " \t\n\v\f\r";
char vowels[] = "aeiou";
printf("Input a string of text: ");
// replaced unsafe gets() with more safe fgets()
fgets(text, sizeof(text), stdin);
char* word = strtok(text, delimiters);
while (word != NULL) {
// strpbrk() does roughly the same thing as strtok(), but it doesn't
// modify a string nor does it remember anything on future calls
char* ptr_to_vowel = word;
int count = 0;
while (NULL != (ptr_to_vowel = strpbrk(ptr_to_vowel, vowels))) {
count ;
// otherwise we'd stay on the same vowel
ptr_to_vowel ;
}
printf("found %d vowels in %s\n", count, word);
word = strtok(NULL, delimiters);
}
return 0;
}
CodePudding user response:
A few issues:
- The
for
loop for counting spaces is incorrect. - We should have a separate function to count vowels.
- Never use
gets
(usefgets
instead). - The code did not preserve the original buffer as the code comments suggested.
I need to count which words in the text contain 4 different vowels.
So, we can only count unique vowels in a word (e.g.):
fleece
has only 1 unique vowel and not 3.great
has 2 vowelsgreet
has 1 vowelincombustible
has 4 [unique] vowels and not 5.
It's not totally clear, but I interpret this to mean that a candidate word has at least 4 unique vowels (i.e. it could have 5)
I had to refactor quite a bit of the code. It is annotated:
#include <stdio.h>
#include <string.h>
#include <stddef.h>
#include <ctype.h>
#define MAX 100
// vcount -- count _unique_ vowels
// RETURNS: number of _unique_ vowels
int
vcount(const char *str)
{
const char *vowels = "aeiou";
int vfreq[5] = { 0 };
int vsum = 0;
// loop through all chars in string
for (int chr = *str ; chr != 0; chr = *str ) {
// get lower case
chr = tolower((unsigned char) chr);
// is it a vowel?
const char *vptr = strchr(vowels,chr);
if (vptr == NULL)
continue;
// get index into frequency table
ptrdiff_t vidx = vptr - vowels;
// have we seen it before?
if (vfreq[vidx])
continue;
// mark as already seen
vfreq[vidx] = 1;
// count new unique vowel
vsum;
}
return vsum;
}
int
main(void)
{
char phrase[MAX];
char temp[MAX];
const char *delim = " \t\v";
printf("Ingrese un texto corto: ");
// Short text with spaces
// NOTE/BUG: _never_ use gets
#if 0
gets(phrase);
#else
fgets(phrase,sizeof(phrase),stdin);
#endif
printf("\n");
// NOTE/BUG: loop condition is incorrect
#if 0
for (i = 0; x < phrase[x] != '\0'; x) {
if (phrase[x] == ' ' || phrase[x] == '\t' || phrase[x] == '\v') {
// Detect space.
}
}
#else
int space_count = 0;
for (int i = 0; phrase[i] != '\0'; i) {
switch (phrase[i]) {
case ' ':
case '\t':
case '\v':
space_count;
break;
}
}
printf("Spaces: %d\n",space_count);
#endif
// I need to keep all the words separate.
#if 0
char *ptr = strtok(phrase, delim);
#else
strcpy(temp,phrase);
char *ptr = strtok(temp, delim);
#endif
while (ptr != NULL) {
#if 0
printf("%s\n", ptr);
#else
printf("%s -- has enough vowels: %s\n",
ptr,(vcount(ptr) >= 4) ? "Yes" : "No");
#endif
ptr = strtok(NULL, delim);
}
return 0;
}
In the above code, I used cpp
conditionals to denote old vs new code:
#if 0
// old code
#else
// new code
#endif
#if 1
// new code
#endif
For the input:
Ana come en el refrigerador.
Here is the program output:
Ingrese un texto corto:
Spaces: 4
Ana -- has enough vowels: No
come -- has enough vowels: No
en -- has enough vowels: No
el -- has enough vowels: No
refrigerador. -- has enough vowels: Yes
CodePudding user response:
Instead of splitting words and then count vowels inside them, you can count vowels and upon a delimiter, check the vowel count and reset the count. This way, you do not need to modify the string. You actually do not even need an array to store the string: you can just read one byte at a time.
Here is a modified version:
#include <stdio.h>
int main() {
int c;
int mask = 0;
int vowels = 0;
int matches = 0;
int done = 0;
printf("Ingrese un texto: ");
while (!done) {
switch (getchar()) {
case EOF:
case '\n':
if (vowels >= 4)
matches ;
vowels = mask = 0;
done = 1;
break;
case ' ':
case '\t':
case '\n':
case '\v':
case '\f':
case '\r':
if (vowels >= 4)
matches ;
vowels = mask = 0;
break;
case 'a':
case 'A':
if (!(mask & 1)) {
mask |= 1;
vowels ;
}
break;
case 'e':
case 'E':
if (!(mask & 2)) {
mask |= 2;
vowels ;
}
break;
case 'i':
case 'I':
if (!(mask & 4)) {
mask |= 4;
vowels ;
}
break;
case 'o':
case 'O':
if (!(mask & 8)) {
mask |= 8;
vowels ;
}
break;
case 'u':
case 'U':
if (!(mask & 16)) {
mask |= 16;
vowels ;
}
break;
}
}
printf("%d\n", matches);
return 0;
}