I have an assignment that asks me to "Write a recursive function vowels(s,low,high) that returns the number of vowels in an input string s[]." We are also limited by "Do not use the C++ string type. Read the characters into an array one at a time using cin.get()." I think I solved the task at hand, but it doesnt compile so I am unsure. If anyone could assist me and show how to fix my error and any errors I've made towards my solution that would be great.
Here is my error message.
***main.cpp:24:37: error: invalid conversion from ‘char*’ to ‘char’ [-fpermissive]
vowelCount = vowels(s, low, high);**
Here is my code:
#include <iostream>
#include <cstring>
using namespace std;
int vowels(char, int, int);
int main()
{
char s[500];
int high,
vowelCount,
low = 0;
cout << "Enter a string of characters: ";
cin.get(s, 500);
high = strlen(s);
vowelCount = vowels(s, low, high);
cout << "The string contains " << vowelCount << " vowels." << endl;
return 0;
}
int vowels(char s[], int low, int high)
{
if (s[low] == 'a' || 'A' || 'e' || 'E' || 'i' || 'I' || 'o' || 'O' || 'u' || 'U') {
return 1 + vowels(s, low + 1, high - 1);
} else {
return vowels(s, low + 1, high - 1);
}
}
We are talking about a so called XY-Problem here.
The teacher wants to cover recursive functions. The vowel counting is just some noise. Unfortunately the given example is a bad one, because it could be implemented by far better with an iterative approach.
The recursion is just adding unnecessary time and space complexity. So, the performance is worse compared to a simple loop in all cases.
If the teacher wants that you learn about recursion, you may want to first look at this description or that more practical example.
After having read this, you will understand that a loop can be simply converted into a recursive function.
I am not sure, why there is a "low" and a "high" parameter. Maybe because of the usage of C-strings stored in a char array (what is nonsense in C++). I doubt that 2 self calls should be established and the function should walk from the begin and the end of the string to the middle. That would even further reduce the performance. So, let us assume the standard case.
Next to your problem with the comparison. What you have written is wrong. The correct comparison in C++ would be:
if ((s[low] == 'a') || (s[low] == 'A') || (s[low] == 'e') ||
(s[low] == 'E') || (s[low] == 'i') || (s[low] == 'I') ||
(s[low] == 'o') || (s[low] == 'O') || (s[low] == 'u') ||
(s[low] == 'U'))
Of course, nobody would write such a long statement, because you can simply calculate, without any comparison, if an ASCII character is a vowel. You could simply write:
if (std::isalpha(s[low]) && ((0x208222 >> (s[low] & 0x1f)) & 1))
and thats it. If you are interested, I can explain the theory later, but not needed for this example.
Then, next, your recursive function is dangerously wrong, because it does not have an end condition. it will run forever or until the stack overflows.
So, you need to rework that, It could be done like this:
#include <iostream>
#include <cstring>
using namespace std;
int vowels(char[], int, int);
int main()
{
char s[500];
int high,
vowelCount,
low = 0;
cout << "Enter a string of characters: ";
cin.get(s, 500);
high = strlen(s);
vowelCount = vowels(s, low, high);
cout << "The string contains " << vowelCount << " vowels." << endl;
return 0;
}
int vowels(char s[], int low, int high)
{
int sum = 0;
if (low != high) {
if ((s[low] == 'a') || (s[low] == 'A') || (s[low] == 'e') ||
(s[low] == 'E') || (s[low] == 'i') || (s[low] == 'I') ||
(s[low] == 'o') || (s[low] == 'O') || (s[low] == 'u') ||
(s[low] == 'U'))
{
++sum;
}
sum += vowels(s,low+1,high);
}
return sum;
}
If we go a little bit more into the direction of C++ and use meaningful variable names and comments, then we could come up with that:
#include <iostream>
#include <cstring>
// A recursive function to count the vowels in a rang of a text
int countVowelsRecursive(char textToEvaluate[], unsigned int startPositionForEvaluation, unsigned int endPositionOfText)
{
// Here we will store the number of vowels. We will use tail recursion
// So, the overall calculation will be done at the end
unsigned int numberOfVowelsInThisRecursion = 0u;
// Now we are evaluating this character from the text
const char currentChar = textToEvaluate[startPositionForEvaluation];
// Check, for the end of recursion condition
if (startPositionForEvaluation != endPositionOfText) {
// Check, if it is a vowel
if ((currentChar == 'a') || (currentChar == 'A') || (currentChar == 'e') ||
(currentChar == 'E') || (currentChar == 'i') || (currentChar == 'I') ||
(currentChar == 'o') || (currentChar == 'O') || (currentChar == 'u') ||
(currentChar == 'U'))
{
// Vowel found. Increase counter by one
++numberOfVowelsInThisRecursion;
}
// Tail recursion. Self call, starting at next position of the string
numberOfVowelsInThisRecursion +=
countVowelsRecursive(textToEvaluate,startPositionForEvaluation + 1, endPositionOfText);
}
// This will be the final result
return numberOfVowelsInThisRecursion;
}
// We will allow a maximal input text length like this
constexpr unsigned int MaxTextLength = 500u;
// Driver code / test function
int main()
{
// Here we will store the text from the user
char text[MaxTextLength]{};
// Give instructions and get the text
std::cout << "Enter a string of characters: ";
std::cin.get(text, MaxTextLength);
// Set text parameters for the evaluation
unsigned int startOfText = 0u;
unsigned int endOfText = static_cast<unsigned int>(strlen(text));
// Calculate the vowels
unsigned int vowelCount = countVowelsRecursive(text, startOfText, endOfText);
// Show result to user
std::cout << "The string contains " << vowelCount << " vowels." << std::endl;
return 0;
}
And if we would be allowed to use C++ then we would write:
#include <iostream>
#include <string>
#include <algorithm>
int main()
{
// Give instructions and get the text
std::cout << "\nEnter a text:\n";
if (std::string text{}; std::getline(std::cin, text))
// Show result to user
std::cout << "\n\nThe string contains "
<< std::count_if(text.begin(), text.end(), [](const char c){ return std::isalpha(c) && ((0x208222 >> (c & 0x1f)) & 1);})
<< " vowels.\n";
return 0;
}
Have fun . . .
Related
I am trying to create a for loop that has a conditional statement which reads until an operation is found, ex. (+,-,/,*), but every time I try I get an error:
Unhandled exception at 0x7936F2F6 (ucrtbased.dll) in CIS310 Project 44.exe: An invalid parameter was passed to a function that considers invalid parameters fatal.
while (getline(infile, hex))
{
n = hex.length();//find the length of the line
for (i = 0; hex[i] != '/'||'+'||'-'||'*'; i++,++k) //loop to split the first hexadecimal number
h1 = h1 + hex[i];
for (i++; i < n - 1; i++) //loop to get the second hexadecimal number
h2 = h2 + hex[i];
n1 = convertDecimal(h1); //convert the first hexadecimal number to decimal
n2 = convertDecimal(h2);
Your condition hex[i] != '/'||'+'||'-'||'*' is malformed. C++ requires that you specify both sides of the operator each time, so you will need something more similar to hex[i] != '/' || hex[i] != '+' || ....
You have to check after every ' | | '(OR), like:
hex[i] != '/' || hex[i] != '+' || hex[i] != '-' || hex[i] != '*'
This is a similar code to what you wrote:
while(getline(file,line))
{
string firstPart = "";
unsigned int i;
//We can use the algorithm library to search for them but its ok
for(i=0;(line[i] != '+') || (line[i] != '-') || (line[i] != '*') || (line[i] != '/') || (line[i] != '\0');i++ );
firstPart = line.substr(0,i);
}
now if you tried this, it will cause the same error (or atleast similar to it), if we even try to print every character in the loop
for(/*stuff*/)
cout << line[i];
Then notice this will become an infinite loop, the problem is that you're checking the character line[i] if it wasn't a + or - or * or / all at the same time, fix this by changing the || to &&.
I'll suppose that your file (named testfile.txt) has the content below:
0xAB+0xCD
0x11-0x03
Sample working code:
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
int main()
{
ifstream file("testfile.txt");
///Don't forget to check if file has opened
if(!file.is_open())
{
cout << "File didn\'t open :(";
return 0;
}
string line;
while(getline(file,line))
{
string firstPart = "",secondPart = "";
char operation;
unsigned int i;
//We can use the algorithm library to search for them but its ok
for(i=0;(line[i] != '+') && (line[i] != '-') && (line[i] != '*') && (line[i] != '/') && (line[i] != '\0');i++ );
firstPart = line.substr(0,i);
operation = line[i];
secondPart = line.substr(i+1,firstPart.size());
}
file.close();
return 0;
}
I have an assignment where I have to make a program that allows a person to input a seven letter word and converts it to a telephone number (1-800-PAINTER to 1-800-724-6837 for example). I'm trying to make each letter convert to a specific number to be outputted to the user, with each letter corresponding to its number on a telephone keypad (so a, A, b, B or c, C equals 1, i.e, more info: https://en.wikipedia.org/wiki/Telephone_keypad).
Currently I have it set up so that each letter of the input word represents a char variable of one, two, three, four, five, six, or seven respectively. Then, using switch and if statements, the idea was to convert a char to an int variable of xtwo = 2, xthree = 3, etc. This isn't working however. Is there a better way to do this?
Example of code (up to first switch, though mostly it's a repeating pattern like so):
int main()
{
char one, two, three, four, five, six, seven;
cout << "Enter seven letter word (1-800-***-****): " << "\n";
cin >> one >> two >> three >> four >> five >> six >> seven;
int xtwo = 2; int xthree = 3; int xfour = 4; int xfive = 5; int xsix = 6; int xseven = 7; int xeight = 8;
int xnine = 9;
switch (one)
{
case 1:
if (one == 'a' || one == 'b' || one == 'c' || one == 'A' || one == 'B' || one == 'C')
{
one = xtwo;
}
break;
case 2:
if (one == 'd' || one == 'e' || one == 'f' || one == 'D' || one == 'E' || one == 'F')
{
one = xthree;
}
break;
case 3:
if (one == 'g' || one == 'h' || one == 'l' || one == 'G' || one == 'H' || one == 'L')
{
one = xfour;
}
break;
case 4:
if (one == 'j' || one == 'k' || one == 'l' || one == 'J' || one == 'K' || one == 'L')
{
one = xfive;
}
break;
case 5:
if (one == 'm' || one == 'n' || one == 'o' || one == 'M' || one == 'N' || one == 'O')
{
one = xsix;
}
break;
case 6:
if (one == 'p' || one == 'q' || one == 'r' || one == 's' || one == 'P' || one == 'Q' || one == 'R' || one == 'S')
{
one = xseven;
}
break;
case 7:
if (one == 't' || one == 'u' || one == 'v' || one == 'T' || one == 'U' || one == 'V')
{
one = xeight;
}
break;
case 8:
if (one == 'w' || one == 'x' || one == 'y' || one == 'z' || one == 'W' || one == 'X' || one == 'Y' || one == 'Z')
{
one = xnine;
}
break;
}
So, in essence, how can a char variable of a letter be converted to a specific int variable?
You could use a std::map.
For example, you could have
std::map<char,int> char_to_dig {
{'a',1}, {'b',1}, {'c',1},
{'d',2}, {'e',2}, {'f',2}
};
Then
char_to_dig['a']
will give you 1.
Alternatively, you could write a function that does the mapping. Something along the lines of this:
int char_to_dig(char c) {
static const char _c[] = "abcdefghi";
static const int _i[] = { 1,1,1,2,2,2,3,3,3 };
for (unsigned i=0; i<9; ++i) {
if (_c[i]==c) return _i[i];
}
return -1; // some value to signal error
}
Or, instead of using arrays, you could perform arithmetic on the chars (since they are just small integers).
int char_to_dig(char c) {
c = std::toupper(c);
if (c < 'A' || c > 'Z') return -1;
if (c == 'Z') return 9;
if (c > 'R') --c;
return ((c-'A')/3)+2;
}
This will give you numbers like on this pad:
Apparently, there's been a similar code golf question.
It has been years since I wrote any c/c++ code and I don't even have a compiler installed to test with .. but this should get you started on the right track
Check functions and syntax...all out of my head. Needs checking.
//
int numArray[7];
char inputStr[10];
cout << " give me 7 characters";
cin >> input;
/*
use a for loop to read the string letter by letter (a string in c is an
array of characters)
convert the characters to uppercase
fall through case statements for each group of letters
assing value to output array to do wiht as you like.
*/
for(i=0; i < 7; i++){
inputStr[i] = toupper(inputStr[i]);
switch(input[i]){
case 'A':
case 'B':
case 'C':
numArray[i] = 2;
break;
case 'D':
case 'E':
case 'F':
numArray[i] = 3;
break;
and so on and so foth....
}
}
I am trying to check if each character of a string in a string array is equal to any of the five vowels. However, when I test it to see when a vowel character in a string is equal to 'vowel', I get that they are not equal. The problem with the code is the bolded part below. Also, when I try to do "a" || "e" || "i" || "o" || "u", I get the error that ISO C++ forbids comparison between pointer and integer. How can I be able to check if they are equal? Thank you for your time.
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <vector>
#include <cmath>
#include <cstdlib>
using namespace std;
int l, c; //l is amount of letters in password, c is amount of letters being inputted
char letters[1000000]; //the letters being inputted
vector <string> pass; //string vector of the stored passwords
void rec(string current, int index, int x){ //determining all possible passwords
if (index >= 4){
pass.push_back(current);
}
else{
for (int i=0; i<c; i++){
if (x<i){
int old;
old = x;
x = i;
rec(current + letters[i], index+1, x);
x = old;
}
}
}
}
int main (int argc, char ** argv)
{
cin >> l >> c;
int x = -1;
for (int i=0; i<c ;i++){
cin >> letters[i];
}
sort(letters, letters + c); //sorted from least to greatest
rec("", 0, x);
for (int i=0; i<pass.size(); i++){
int vl=0; //number of vowels
int nvl=0; //number of non-vowels (consonants)
for (int j=0; j<l; j++){
**if (pass.at(0)[j] == 'a' || 'e' || 'i' || 'o' || 'u'){**
vl++;
}
else{
nvl++;
}
if (j == l-1){
if (vl >= 1 && nvl >= 2){
cout << pass.at(0) << endl;
}
}
}
}
return 0;
}
In C++, X || Y means:
Test if X is true. If so, result of whole expression is true
Otherwise, test if Y is true. Result of Y is result of expression.
So your code:
pass.at(0)[j] == 'a' || 'e'
(omitting for now the i etc. as they don't change anything).
We tested pass.at(0)[j] == 'a' . That was false, so now we test 'e'. Not that you did NOT test pass.at(0)[j] == 'e'. You just tested 'e'. This is the same as testing 'e' != 0, which is true. So your expression evaluates to true at this point (and does not go onto check 'i' etc.)
You probably intended to test whether pass.at(0)[j] held any of the values 'a', 'e', etc. If so then one way to encode that is:
if ( std::strchr("aeiou", pass.at(0)[j]) )
You should make sure j < strlen(pass.at(0)) before doing this though; using [] to generate an out of bounds index causes undefined behaviour.
Because you are using the || wrong. The part either side of || is a "true or false" expressin in itself, so you need something like:
if (pass.at(0)[j] == 'a' || pass.at(0)[j] == 'e' ... )
Otherwise, the expression is always true, since || is true if the expression on left or right is true, and 'e' is true by not being zero.
This does not do what you think...
(pass.at(0)[j] == 'a' || 'e' || 'i' || 'o' || 'u')
You need to explicitly compare,
char t = pass.at(0)[j];
if (t == 'a' || t == 'e' || t == 'i' || t == 'o' || t == 'u') {
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
This program is going very slowly when I call the sort arrays function. If i print out elements of the array before it is sorted it runs in seconds. If not, it will take sometimes a minute to run with a farily short text file. My first command line argument this program takes is a "book" (a text file with all lowercase words) and the second command line argument(x) tells how many times the most frequent x words occured. Any help on how to quicker sort the array of structs would be super helpful!
using namespace std;
//void insertionSort(struct count array[],int size);
void sortArray(struct count array[], int size);
bool ExcludeCommon(string word);
struct count
{
string word;
int frequency;
};
int main(int argc, char *argv[])
{
ifstream filename;
filename.open(argv[1]);
ifstream num_words;
int num = stoi((argv[2]));
string one_word;
int size = 100;
count *count_array = new count[size];
int total_non_comm=0;
int words_in_arr = 0;
int double_count=0;
while (filename >> one_word)
{
int i;
int freq = 1;
bool found = false;
if(ExcludeCommon(one_word)==0)
{
if(total_non_comm>=size)
{
count *new2= new count[size*2];
for(int i=0; i<size; i++)
{
new2[i]=count_array[i];
}
size = size*2;
delete[] count_array;
count_array=new2;
double_count++;
}
for(i=0; i<=words_in_arr; i++)
{
if(count_array[i].word == one_word)
{
count_array[i].frequency++;
found=true;
total_non_comm++;
}
}
if(found == false)
{
struct count add;
add.word = one_word;
add.frequency = freq++;
count_array[words_in_arr]=add;
words_in_arr++;
total_non_comm++;
}
found = false;
}
}
sortArray(count_array, size);
for(int i=0; i<num;i++)
{
cout<<count_array[i].frequency<< " - " << count_array[i].word<<endl;
}
cout<<"#"<<endl;
cout<<"Array doubled: "<<double_count-3<<endl;
cout<<"#"<<endl;
cout<<"Unique non-common words: " <<words_in_arr<<endl;
cout<<"#"<<endl;
cout<<"Total non-common words: " << total_non_comm <<endl;
};
bool ExcludeCommon(string word)
{
if (word == "the" || word == "be" || word == "to" || word == "of" ||
word == "and" || word == "a" || word == "in" || word == "that" ||
word == "have" ||word == "i" || word == "it" || word == "for" || word == "not" ||
word == "on" || word == "with" || word == "he" || word == "as" ||
word == "you" || word == "do" || word == "at" || word == "this" ||
word == "but" || word == "his" || word == "by" || word == "from"||
word == "they" || word == "we" || word == "say" || word == "her" ||
word == "she" || word == "or" || word == "an" || word == "will" ||
word == "my" || word == "one" || word == "all" || word == "would" ||
word == "there" || word == "their" || word == "what" || word == "so" ||
word == "up" || word == "out" || word == "if" || word == "about" ||
word == "who" || word == "get" || word == "which" ||word == "go" || word == "me")
{return 1;
}
return 0;
};
void sortArray(struct count array[],int size)
{
int cur_pos = 0;
string the_word;
for(int i=0; i<(size); i++)
{
for(int j=size-1; j>=i; j--)
{
if((array[j+1].frequency)>(array[j].frequency))
{
cur_pos = array[j].frequency;
the_word = array[j].word;
array[j].frequency = array[j+1].frequency;
array[j].word = array[j+1].word;
array[j+1].frequency = cur_pos;
array[j+1].word = the_word;
}
}
}
};
You have a struct count and then you also have using namespace std;. Did you realize there is a std::count?
Try not to use
using namespace std;
Also, change struct count to struct Count.
Coming to the issue of the sorting function, you can implement it using std::sort.
struct CountCompare
{
bool operator()(Count const& lhs, Count const& rhs)
{
return (lhs.frequency < rhs.frequency);
}
};
void sortArray(struct Count array[],int size)
{
std::sort(array, array+size, CountCompare());
};
That should go a lot faster than what you have (N.logN vs N^2).
I have a char array that has number 0-8 in it in char form
Board[0] = '0';
Board[1] = '1';
Board[2] = '2';
Board[3] = '3';
Board[4] = '4';
Board[5] = '5';
Board[6] = '6';
Board[7] = '7';
Board[8] = '8';
and some of them are changed to either an 'x' or an 'o' based on user input however I need to figure out a way so that I can tell the total number of them that aren't an 'x' or an 'o'.
What I mean is if say 4 of the 9 are either an 'x' or an 'o' I need to be able to get the fact that there are 5 left. I was attempting to use for each(char c in Board) and I got far enough to where I got it to list the chars that aren't an 'x' or an 'o' but I can't figure out how to get it to send how many are left to an int value. This is as far as I got.
for each(char c in Board)
{
if (c != 'x' && c != 'o')
{
}
}
You could try
auto n = std::count_if(Board, Board+9, std::isdigit);
You should define a counter that counts the number of these characters (by incrementing it):
int n = 0;
for (char c : Board)
{
if (c != 'x' && c != 'o')
{
n++; // increment n by 1
}
}
std::cout << n << '\n'; // use the result
You can use a combination of std::isdigit and std::count_if
#include <cctype> // for std::isdigit
#include <algorithm> // for std::count_if
int num = std::count_if(Board, Board+9, std::isdigit);
Assuming you don't just want any digit, and only those between 0 and 8 you could do this:
int count = 0;
for each(char c in Board)
{
if (c >= '0' && c <= '8')
{
count++;
}
}
cout << count << " are digits between 0 and 8 (inclusive)" << endl;