wowels/consonants

closed account (4wpL6Up4)
Hi,

I am writing a program that inputs a string, gets rid of the vowels, and
if two consonants typed right after one another are the same, the output should print only one of those two.
I have been trying but it looks like that only the first double consonant is
printed as one, the rest remain the same.
How come?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
 #include "pch.h"
#include <stdlib.h>
#include<iostream>
#include<cstdlib>
#include<cctype>
#include <sstream>
#include <string>
#include<cmath>
#include <algorithm>
#include <iterator>
#include <ctype.h>
#include <iomanip>
#include <limits>

using namespace std;

int main()
{
	string str;
	int i=0, j;
    j = i + 1;
	cout << "enter a string" << endl;
	getline(cin, str);

	for (int i = 0; str[i] != '\0'; i++)
	{
		if (str[i] == 'a' || str[i] == 'e' || str[i] == 'i' || str[i] == 'o' || str[i] == 'u' || str[i] == 'A' || str[i] == 'E' || str[i] == 'I'
			|| str[i] == 'O' || str[i] == 'U')
		{
			str[i] = ' ';
			
		}
	}
	
	for (int i = 0; str[i] != '\0'; i++)
	{
		if (str[i] == str[j])
		{
			str[j] = ' ';
		}
	}

	cout << "coded word \: " << str;

	return 0;
}
j was declared to have the value i+1, so it had the value 1. j's value was never changed from that so it remained to be 1.

so you have to update j in the for-loop, also you must use str[j] instead of str[i] (in the looping condition) to make sure you will not access a memory out of reach.
1
2
3
4
5
6
7
for (int i = 0; str[i - 1] != '\0'; i++, j = i + 1) 
	{
 		if (str[i] == str[j])
		{
			str[j] = ' ';
		}
	}
Last edited on
Hi @nypran,

Grime has already noted how you can fix your program, but you should also probably make sure that the headers you are including are actually required. Almost all of them are not.

Anyway, just for fun I got curious about writing the code in a slightly different way, and the result is below (you can run it by clicking on the little wheel, top right of code box). As you can see, you really don't need most of the headers you had included (albeit the program is a little different to your own).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include<iostream>
#include <string>
#include <algorithm>

int main()
{
    std::string str;
    std::cout << "Enter a string: " << std::endl;
    std::getline(std::cin, str);
    std::transform(str.begin(), str.end(), str.begin(), ::toupper);

    for (int i = 0; i<=str.size(); i++)
    {
	if (str[i] == 'A' || str[i] == 'E' || str[i] == 'I' || str[i] == 'O' || str[i] == 'U') 
	{
	str[i] = ' ';
	}
	else
	{
	if (str[i] == str[i+1]) str[i+1] = ' ';
	}
    }

    std::cout << "coded word: " << str;

return 0;
}


Program output:
Enter a string: 
testingthisthaagoooout
coded word: T ST NGTH STH  G     T 


PS. Modified loop (24-Feb)
Last edited on
closed account (4wpL6Up4)
Hi, thanks for your hints.
I continued the code to make sure that the consonant output
would be taken by the first 3 characters and the last 2.
My code seems to run very smoothly, but after a few trials,
it stops working and a window appears saying: "debug assession failed"
so I have to click "abort" to start again.
Not sure why is doing that.

Here is my code.

#include "pch.h"
#include <stdlib.h>
#include<iostream>
#include<cstdlib>
#include<cctype>
#include <sstream>
#include <string>
#include<cmath>
#include <algorithm>
#include <iterator>
#include <ctype.h>
#include <iomanip>
#include <limits>

using namespace std;

int main()
{
string str;
int i = 0, j;
j = i + 1;

char answer;
do {
cout << "enter a string" << endl;
getline(cin, str);

for (int i = 0; str[i] != '\0'; i++)
{
if (str[i] == 'a' || str[i] == 'e' || str[i] == 'i' || str[i] == 'o' || str[i] == 'u' || str[i] == 'A' || str[i] == 'E' || str[i] == 'I'
|| str[i] == 'O' || str[i] == 'U')
{
str[i] = ' ';

}
}


for (int i = 0; str[j] != '\0'; i++, j = i + 1)
{
if (str[i] == str[j])
{
str[j] = ' ';
}
}
str.erase(remove_if(str.begin(), str.end(), isspace), str.end());


if (str.length() > 5)

cout << str[0] << str[1] << str[2] << str.substr(str.length() - 2) << endl;

else

cout << "coded word \: " << str;

cout << "try again (Y/N)?" << endl;
cin >> answer;
cin.ignore();
} while (answer == 'Y' || answer == 'y');

return 0;
}
Sorry my mistake.
for (int i = 0; str[j] != '\0'; i++, j = i + 1)
should be
for (int i = 0; str[i - 1] != '\0'; i++, j = i + 1)

Could write str[i] too, just that you do one extra unnecessary check.
Last edited on
What's with the
str[i] != '\0'
?
It's a std::string. Use str.size() or str.length() in indexed loops.

Also, what is so special about a length > 5 (final if block)?
Last edited on
By the way lastchance, technically, std::strings are also null-terminated right, so it would be proper too .-.
closed account (4wpL6Up4)
Hi, thanks for your hints.
I continued the code to make sure that the consonant output
would be taken by the first 3 characters and the last 2.
My code seems to run very smoothly, but after a few trials,
it stops working and a window appears saying: "debug assession failed"
so I have to click "abort" to start again.
Not sure why is doing that.

I also wanted to ask? Would it actually be a big deal to include libraries that are not used?
What does that imply?

Here is my code.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#include "pch.h"
#include <stdlib.h>
#include<iostream>
#include<cstdlib>
#include<cctype>
#include <sstream>
#include <string>
#include<cmath>
#include <algorithm>
#include <iterator>
#include <ctype.h>
#include <iomanip>
#include <limits>

using namespace std;

int main()
{
string str;
int i = 0, j;
j = i + 1;

char answer;
do {
cout << "enter a string" << endl;
getline(cin, str);

for (int i = 0; str[i] != '\0'; i++)
{
if (str[i] == 'a' || str[i] == 'e' || str[i] == 'i' || str[i] == 'o' || str[i] == 'u' || str[i] == 'A' || str[i] == 'E' || str[i] == 'I'
|| str[i] == 'O' || str[i] == 'U')
{
str[i] = ' ';

}
}


for (int i = 0; str[j] != '\0'; i++, j = i + 1)
{
if (str[i] == str[j])
{
str[j] = ' ';
}
}
str.erase(remove_if(str.begin(), str.end(), isspace), str.end());


if (str.length() > 5)

cout << str[0] << str[1] << str[2] << str.substr(str.length() - 2) << endl;

else

cout << "coded word \: " << str;

cout << "try again (Y/N)?" << endl;
cin >> answer;
cin.ignore();
} while (answer == 'Y' || answer == 'y');

return 0;
}

As I had said after you posted it the first time,
change for (int i = 0; str[j] != '\0'; i++, j = i + 1
to
for (int i = 0; str[i - 1] != '\0'; i++, j = i + 1
That's what's causing the assertion.

Also
str.erase(remove_if(str.begin(), str.end(), isspace), str.end());
should be just remove_if(str.begin(), str.end(), isspace);
remove_if takes care of the "removing" part (it's in the name man..), you wrote this on another thread too (sorry if it isn't you).

Nothing wrong with including extra headers, it's just that it's going to take you longer to compile, nothing else. But in my opinion it's better you have a habit of including only the headers you need, even if you're just playing around and testing.

Also .h headers are C headers.
1
2
#include <stdlib.h>
#include <ctype.h> 


Use the C++ counterparts (add c at the beginning and remove the .h)
1
2
#include <cstdlib>
#include <cctype> 

grime wrote:
By the way lastchance, technically, std::strings are also null-terminated right, so it would be proper too .-.


See what this code gives, Grime.
1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>
#include <string>
using namespace std;

int main()
{
   string test = "ABCDEFGH";

   test[4] = '\0';
   cout << test << '\n';
   cout << test.size();
}


So I still think that, if str is a std::string, then
for (int i = 0; str[i] != '\0'; i++)
is not reliable.
Last edited on
lastchance I know that std::string don't rely on '\0' but instead their size.
However that being said, I have noticed that identifier_of_string[size] seems to be a '\0'. Might be a coincidence.
Last edited on
My point was that you could put '\0' INSIDE a std::string and it wouldn't affect the size of it.

However, if you coded a loop to finish at the first incidence of a null character (as in C-strings) then you would have finished early.
Owkie yush thaz rite 0+0
closed account (4wpL6Up4)
Sorry,

I have made all the changes I was told, but the assertion remains.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#include "pch.h"
#include <stdlib.h>
#include<iostream>
#include<cstdlib>
#include<cctype>
#include <sstream>
#include <string>
#include<cmath>
#include <algorithm>
#include <iterator>
#include <ctype.h>
#include <iomanip>
#include <limits>

using namespace std;

int main()
{
	string str;
	int i = 0, j;
	j = i + 1;

	char answer;
	do
	{
		cout << "enter a string" << endl;
		getline(cin, str);

		for (int i = 0; str[i] != '\0'; i++)
		{
			if (str[i] == 'a' || str[i] == 'e' || str[i] == 'i' || str[i] == 'o' || str[i] == 'u' || str[i] == 'A' || str[i] == 'E' || str[i] == 'I'
				|| str[i] == 'O' || str[i] == 'U')
			{
				str[i] = ' ';

			}
		}


		for (int i = 0; str[i - 1] != '\0'; i++, j = i + 1)
		{
			if (str[i] == str[j])
			{
				str[j] = ' ';
			}
		}
		remove_if(str.begin(), str.end(), isspace);


		if (str.length() > 5)

			cout << str[0] << str[1] << str[2] << str.substr(str.length() - 2) << endl;

		else

			cout << "coded word \: " << str;

		cout << "try again (Y/N)?" << endl;
		cin >> answer;
		cin.ignore();
	} while (answer == 'Y' || answer == 'y');

	return 0;
}
Ugh I forgot what I was thinking when I said str[i-1], that's wrong now that I see it.
Anyways screw all of that.

Change for (int i = 0; str[i] != '\0'; i++) to for(int i = 0, size = str.size(); i < size; i++)

Also change for (int i = 0; str[i] != '\0'; i++) to for (int i = 0, size = str.size(); i < size; i++) for reasons lastchance pointed out.
Last edited on
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#include <iostream>
#include <string>

int main()
{
    char answer ;

    do
    {
        std::string str ;
        std::cout << "enter a string: " ;
        std::getline( std::cin, str ) ;
        if( str.empty() ) return 0 ; // empty string, nothing to be done

        // if two consonants typed right after one another are the same,
        // get rid of the second one
        // we need to do this before removing the vowels.
        // eg. if the string is "tata", he two consonants are not typed right after one another
        // note that this will also remove duplicate vowels; but we are required to remove all vowels anyway
        {
            std::string str_no_dup ;
            str_no_dup += str[0] ; // the first character is not a repeating character

            // the first character has no previous character
            // so we start this loop from the second character (position 1)
            for( std::size_t i = 1 ; i < str.size() ; ++i )
            {
                if( str[i] != str[i-1] ) // if it is not a repeating character
                    str_no_dup += str[i] ; // append it to str_no_dup
            }

            str = str_no_dup ; // str with duplicates removed
        }

        // get rid of all the vowels now
        {
            const std::string vowels = "aeiouAEIOU" ;

            std::string str_no_vowels ;
            for( std::size_t i = 0 ; i < str.size() ; ++i )
            {
                const char c = str[i] ;
                if( vowels.find(c) == std::string::npos ) // if the character is not a vowel
                    str_no_vowels += c ; // append it to str_no_vowels
            }

            str = str_no_vowels ; // str with vowels removed
        }

        std::cout << "endoded string: " << str << '\n' ;

        std::cout << "try again (y/n)? " ;
        std::cin >> answer ;
        std::cin.ignore( 1000, '\n' ) ;
    }
    while( answer == 'Y' || answer == 'y' ) ;
}
for (int i = 0; str[i - 1] != '\0'; i++, j = i + 1) That produces undefined behavior the very first time through the loop because it tests str[-1].
I have noticed that identifier_of_string[size] seems to be a '\0'.
This type of thinking is a common source of bugs. Don't rely on things that seem to work because they might work that way purely by accident. Look it up and determine if the behavior is supported or not.

In the case of str[str.size()], one of the more recent standards requires that std::string's be null terminated, but if you're using an earlier compiler, it isn't true.

Bottom line: always use string::size() to tell where a string ends.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <iostream>
#include <string>
#include <cctype>
using namespace std;

string filter( const string &text )
{
   const string vowels = "aeiouAEIOU";
   string result;
   char last = 'a';

   for ( char c : text )
   {
      if ( vowels.find( c ) == string::npos && tolower( c ) != last ) result += c;
      last = tolower( c );
   }
   return result;
}

int main()
{
   string text;
   cout << "Input a string: ";   getline( cin, text );
   cout << filter( text ) << '\n';
}


Input a string: FuDdY-dUdDy
FDY-ddy
Topic archived. No new replies allowed.