Reputation: 109
So I have a homework asking to remove all vowels in a string w/o using an additional string. My problem is that I wanna make it working even if I have some consecutive vowels like aabbbceee, I want it to print bbbc but instead of that it would print something weird.
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <stdlib.h>
bool isVowel(char a) {
if (a == 'a' || a == 'e' || a == 'i' || a == 'o' || a == 'u') return
true;
return false;
}
void main () {
char* sir = (char*)calloc(256, sizeof(char));
scanf("%[^\n]s", sir);
int numarVocale = 0, lungimeSir = strlen(sir);
for (int i = 0; i < lungimeSir; ++i) {
if (isVowel(sir[i])) numarVocale++;
}
for (int i = 0; i < lungimeSir; ++i) {
if (isVowel(sir[i])) {
int pozitie = i;
pozitie++;
while (isVowel(sir[pozitie]) && pozitie < lungimeSir) {
pozitie++;
}
sir[i] = sir[pozitie];
sir[pozitie] = '\0';
}
}
sir = realloc(sir, lungimeSir - numarVocale);
printf("The string after I deleted the vowels: %s", sir);
}
My thinking was to find a first vowel, then save its position and if next character is also a vowel loop through them until I find a consonant.
Upvotes: 1
Views: 247
Reputation: 61
sir[pozitie] = '\0';
is what's messing with you.
Try walking through an example on paper.
aabbbceee
will find that a
is a vowel at the beginning.
while (isVowel(sir[pozitie]) && pozitie < lungimeSir) {
pozitie++;
}
The above code runs until it finds the first b
. sir[i] = sir[pozitie];
replaces your a
with b
so now you're looking at babbbceee
.
sir[pozitie] = '\0';
then replaces the first b
with \0
. Now you're looking at ba\0bbceee
.
You advance to the next vowel, which is the second a
. You then look for the next character that fails IsVowel()
, which is the \0
you just inserted. At the end of this if-statement, you're now looking at b\0\0bbceee
.
At this point you should be able to see the error in your logic. As for what it's outputting, it only shows the first consonant because \0
is the terminating delimiter for C strings. So, printf()
only sees b\0
and prints b
.
Upvotes: 1
Reputation: 33621
There is no need to count the number of vowels beforehand.
Just do a single loop and process one character at a time.
There's no need to use strlen
. Just stop the loop if the current character is EOS (e.g. 0).
The important point is to not copy the current character if it is a vowel.
Maintain two index variables: (1) the source/input index (e.g. isrc
) and (2) the destination/output index (e.g. idst
).
Only advance idst
if you're copying a character (i.e. a non-vowel).
A refinement is to not copy the character if idst
is isrc
. (i.e. you'd just be copying the same character to itself). But, you still have to increment the output index (idst
).
And, you have to add a new EOS (string terminator) at the end of the loop.
Here's the refactored code (with some annotations):
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <stdlib.h>
bool
isVowel(char a)
{
if (a == 'a' || a == 'e' || a == 'i' || a == 'o' || a == 'u')
return true;
return false;
}
void
main(void)
{
// NOTE/BUG: don't cast the result of malloc
#if 0
char* sir = (char*)calloc(256,sizeof(char));
#else
char* sir = calloc(256,sizeof(*sir));
#endif
scanf("%[^\n]s",sir);
printf("The string before I deleted the vowels: '%s'\n",sir);
int isrc = 0;
int idst = 0;
while (1) {
// get next char (and advance the source index)
char chr = sir[isrc++];
// end of string
if (chr == 0)
break;
// skip any vowel
if (isVowel(chr))
continue;
// copy over char [if different]
// NOTE: using the "if" is a nicety/speedup
if (idst != (isrc - 1))
sir[idst] = chr;
// advance destination index
++idst;
}
// add EOS to new [possibly] shorter string
sir[idst] = 0;
// trim the output string
sir = realloc(sir,idst + 1);
printf("The string after I deleted the vowels: '%s'\n",sir);
}
Upvotes: 1