Boolean function does not work properly - c++

I have trouble to come up with a Boolean function as expected by the assignment. I just need some explanations as I want to write my own code. I am supposed to write a MIPS code that actually counts the number of Uppercase, Lowercase, Vowels, Consonants and Digits in a string. I am writing the code in C++, then I will translate into MIPS assembly. I pasted the requirement below followed by the way the function bool consonant(char c) should look like (idea given by my professor). The problem is that it seems I am missing some information to make that function work. Can anyone provide me more information regarding that function? I don't need a code, just the missing details. Your help will be very appreciated.
//requirement of assignment bellow
To determine if an ASCII character c is a vowel or a consonant, write two functions bool vowel(char c) and
bool consonant(char c). Use the stack to pass the character argument to these functions. Avoid long conditional
expressions when testing a character for being a vowel and a consonant. Instead, use two global arrays
(tables) containing Boolean flags to implement vowel() and consonant(). For example, an array named
is_vowel would have true for characters ’a’ and ’A’ but false for ’b’ and ’B’.
// function that returns 0 if c is a consonant, or 1 if c is not a consonant
bool consonant(char c)
{
const bool is_conson[30]={0,0,...1,1,1,0,0...};
return is_conson[c];
}
//Here is The Code (C++) that I wrote for testing purpose only using Dev-C++
#include <iostream>
#include <math.h>
#include <cstdlib>
using namespace std;
bool consonant(char c)
{
const bool is_conso[30]= {1,1,1,1,0,0,0,0,0,1,0,1,1,0,0,0,1,0,1,0,1,1,1,1,0,1,0,1,0,1};
return is_conso[c];
}
int main()
{
int i;
bool result;
char c;
char sentence[]="aaaabbbbb";
cout<<"the array: ";
cout<<sentence<<endl;
for (i=0; i<9; i++)
{
c=sentence[i];
result=consonant(c);
if (result==0)
cout<<c<<" is a Consonant"<<endl;
}
return 0;
}

If you want to call bool consonant(char c) like consonant('a'), then you need to translate c into an index first (because 'a' != 0) or use another approach.
In portable C++, you could do it with a big switch:
switch(c) {
case 'b': case'B': case 'c': case 'C': .... return true;
default: return false;
}
In non-portable C++, you could offset c:
c = lower_case(c); // <-- left as exercise
const auto array_size = std::end(is_conson) - std::begin(is_conson);
if (c>=0 && c<array_size)
return is_conson[c - 'a']
throw std::logic_error(...);
This is non-portable because the C++ standard does not require the characters [a..z] to be contiguous. I don't know if your compiler at hands does support this.
A third, non-portable variant requires separate some special initialization, but allows direct indexing:
std::array<bool,std::numeric_limits<char>::max()> meh() {
std::array<bool,std::numeric_limits<char>::max()> ret;
ret['a'] = true;
ret['A'] = true;
...
return ret;
}
....
static const auto is_conson = meh();
if (c >= begin(is_conson) && c<= end(is_conson))
return is_conson[c];
throw std::logic_error(....);
Non-portable, because it assumes that all consonants are positive. It is, however, more portable than the previous variant. You could make it portable by also introducing std::numeric_limits<char>::min().

As it stands your function won't work because ASCII A is 65, you'll need to increase your array to cover all ASCII characters or subtract 'A' (which gives the ASCII value of A) to scale the number to your array. ASCII a is 97, so lowercase letters would have to be scaled by subtracting 'a'

Letters are represented by values 65 through 90 (uppercase) and 97 through 122 (lowercase) in ASCII. You're using the array as if they were starting at index 0. Do something like this:
if (c >= 'A' && c <= 'Z')
return is_conson[c-'A'];
if (c >= 'a' && c <= 'z')
return is_conson[c-'a'];
return false;
Also, you should declare the is_conson array as static, so that it's only constructed once and not each time the function is called.

Related

Simple Word Guessing Game

bool guess(char c)
{
if (guesses[c])
{
guesses[] = c;
return true;
}
else if (c > ='a' && c <= 'z')
{
guesses[] = c;
return false;
}
}
bool guesses[255] = {};
I need to use this to see if the person has enter a char between a - z and if they haven't I return true else I will return false. either way I will also update guesses with the char. Right now I don't understand how to add char to the array, so that next time I check the it will be false and tell them it was already guessed. I understand this is using the ASCII table but beyond that I am lost. Could anyone explain why this won't work.
I currently get the error
expected primary-expression before']'
but if I take bracket out I get
incompatible type char to bool
which make sense but then how do I make it so where char c is will be mark true in the Boolean array
You've left your brackets empty, so you currently aren't providing an index:
guesses[c] = c;
But you also don't want to assign the char to guesses, you'd want to assign a bool:
guesses[c] = true;
That will compile* and fix your problem.
* Note you also have a syntax error with > =, which I assume was just a copy+paste issue from the editor to the question, but you should fix that also to be >=. Your function guess can also potentially not return (if neither the if or else if are true), which is undefined behaviour. You should ensure all control paths return a value, and you should make sure you compile at the highest warning level so you are warned about these things.
But not your design.
Since you're only dealing with characters a-z, you don't need to allocate all 255 elements like you do. You could simply minus the character to obtain the correct index:
bool guesses[26];
if (c >='a' && c <= 'z')
guesses[c-'a'] = true;
Consider instead using a std::set, a container of unique elements, to track whether a character has been pressed:
#include <set>
std::set<char> guesses;
bool guess(char c)
{
// Have we already inserted this character?
if (guesses.find(c) != std::end(guesses))
{
// Character has already been guessed:
std::cout << "This character has already been guessed";
return true;
}
else if (c >= 'a' && c <= 'z')
{
// Valid guess:
guesses.insert(c);
return false;
}
}

Code ignoring if statements - C++ [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I've been working on a password generator for my College coursework, and one of the parts to this involves creating 'Complex' passwords, which are passwords which are nothing more than strings of random characters, and the user should be able to specify what types of characters are used. However, the set of if statements which control if a function is used don't activate based on the values within uppertrue numbertrue and lowertrue, they all act as if the statement returns true, and so the function is always run.
#include
#include
#include
#include
int upper(), lower(), number(), symbol(); //initializing functions to be used to generate the ascii code
int clength = 15;
int pass[30];
int uppertrue = 0, numbertrue = 1, symboltrue = 0;
int main()
{
srand (time(NULL)); //seed random generator
int i = 0; //counter
int which = 0;
do
{
which = rand() % 4 + 1; //randomly decides which type of character will be shown - probablity is unweighted for complex module
if (which == 1)
{
pass[i] = lower(); //inserts the code returned by the function into the array
i++;
}
else if ((uppertrue == 1) && (which == 2))
{
pass[i] = upper();
i++;
}
else if (numbertrue == 1 && which == 3)
{
pass[i] = number();
i++;
}
else if (symboltrue == 1 && which == 4)
{
pass[i] = symbol();
i++;
}
}while (i!=(clength+1)); //terminates loop when the array is complete
std::string strpass;
int x=0;
do
{
char tempchar;
tempchar = pass[x];
std::cout << tempchar;
x++;
}while (x!=15);
return 0;
}
int upper() //creates random number between the range of ascii characters that results in caps
{
return rand() % 65 + 26;
}
int number() //same as upper but for numbers
{
return rand() % 48 + 9;
}
int lower() //same as upper but for lower case
{
return rand() % 122 + 26;
}
int symbol() //same as upper but for symbols (currently only supporting a few characters
{
return rand() % 63 + 6;
}
if anyone can point me in the correct direction it would be much appreciated, it seems like it's a logical error but I can't see anything logically wrong with it. Is it perhaps to do with some sort of quirk with C++? (bearing in mind I was taught C and this is the first thing I've done in C++)
Many thanks
(A comment said to remove the part where i'd usually enter the values for uppertrue etc so i've hardcoded the values to show the problem instead)
Your problem is here:
int lower() // same as upper but for lower case
{
return rand() % 122 + 26;
}
It will produce random number in range 26 ... 147. Which is something completely different than range for lower case characters. You want this:
return rand() % ('z' - 'a' + 1) + 'a';
You should fix the other functions in similar manner.
Note to those who worry about their code being able to run on, for example, mainframes using EBCDIC character encoding: This assumes that a..z have continuous character codes.
The specific problem is that you have bugs in the functions that return, at random, the various characters.
The C++ standard is intentionally vague as to the numeric values that it associates with characters. The precise mapping is down to the implementation and the scheme is called the encoding.
Whilst ASCII encoding is common, it's by no means universal and so in order to achieve portability it's best not to make assumptions about your platform unless you really need to.
So, you really ought to recast lower on the lines:
char lower
{
const char* s = "abcdefghijklmnopqrstuvwxyz";
return s[rand() % 26];
}
which is truly portable. I've also taken the liberty of changing your function return type.
You ought to do similar for upper. Your symbols function will drop out similarly.
I'd be tempted to adopt the same approach for number too but here the C++ standard does say something about the digits: the encoding must arrange the characters 0 to 9 to be in a contiguous block and in that order, so the statement
return rand() % ('9' - '0' + 1) + '0';
is portable. As a final remark, you could use static char[] s = "abc...z"; and (sizeof(s) - 1) in place of the hardcoded 26. This is a quite advanced technique and not obvious to a beginner but do research it as your programming skills develop.

Efficiency & Readabilty of a C++ For Loop that Compares two C-style Strings

So I've created my own function to compare two C Strings:
bool list::compareString(const char array1[], const char array2[])
{
unsigned char count;
for (count = 0; array1[count] != '\0' && array2[count] != '\0' && (array1[count] == array2[count] || array1[count + 32] == array2[count] || array1[count] == array2[count+32]); count++);
if (array1[count] == '\0' && array2[count] == '\0')
return true;
else
return false;
}
The parameter of my for loop is very long because it brings count to the end of at least one of the strings, and compares each char in each array in such a way that it their case won't matter (adding 32 to an uppercase char turns that char into its lowercase counterpart).
Now, I'm guessing that this is the most efficient way to go about comparing two C Strings, but that for loop is hard to read because of its length. What I've been told is to use a for loop instead of a while loop whenever possible because a for loop has the starting, ending, and incrementing conditions in its starting parameter, but for this, that seems like it may not apply.
What I'm asking is, how should I format this loop, and is there a more efficient way to do it?
Instead of indexing into the arrays with count, which you don't know the size of, you can instead operate directly on the pointers:
bool list::compareString(const char* array1, const char* array2)
{
while (*array1 != '\0' || *array2 != '\0')
if (*array1++ != *array2++) return false; // not the same character
return true;
}
For case insensitive comparison, replace the if condition with:
if (tolower(*array1++) != tolower(*array2++)) return false;
This does a safe character conversion to lower case.
The while loop checks if the strings are terminated. It continues while one of the strings is not yet terminated. If only 1 string has terminated, the next line - the if statement, will realize that the characters don't match (since only 1 character is '\0', and returns false.
If the strings differ at any point, the if statement returns false.
The if statement also post-increments the pointers so that it tests the next character in the next iteration of the while loop.
If both strings are equal, and terminate at the same time, at some point, the while condition will become false. In this case, the return true statement will execute.
If you want to write the tolower function yourself, you need to check that the character is a capital letter, and not a different type of character (eg. a number of symbol).
This would be:
inline char tolower(char ch)
{
return (ch >= 'A' && ch <= 'Z' ? (ch + 'a' - 'A') : ch);
}
I guess you are trying to do a case-insensitive comparison here. If you just need the fastest version, use a library function: strcasecmp or stricmp or strcmpi (name depends on your platform).
If you need to understand how to do it (I mean, is your question for learning purpose?), start with a readable version, something like this:
for (index = 0; ; ++index)
{
if (array1[index] == '\0' && array2[index] == '\0')
return true; // end of string reached
if (tolower(array1[index]) != tolower(array2[index]))
return false; // different characters discovered
}
Then measure its performance. If it's good enough, done. If not, investigate why (by looking at the machine code generated by the compiler). The first step in optimization might be replacing the tolower library function by a hand-crafted piece of code (which disregards non-English characters - is it what you want to do?):
int tolower(int c)
{
if (c >= 'A' && c <= 'Z')
return c + 'a' - 'A';
}
Note that I am still keeping the code readable. Readable code can be fast, because the compiler is going to optimize it.
array1[count + 32] == array2[count]
can lead to an OutOfRangeException, if the length of the array is smaller than 32.
You can use strcmp for comparing two strings
You have a few problems with your code.
What I'd do here is move some of your logic into the body of the for loop. Cramming everything into the for loop expression massively reduces readability without giving you any performance boosts that I can think of. The code just ends up being messy. Keep the conditions of the loop to testing incrementation and put the actual task in the body.
I'd also point out that you're not adding 32 to the character at all. You're adding it to the index of the array putting you at risk of running out of bounds. You need to test the value at the index, not the index itself.
Using an unsigned char to index an array gives you no benefits and only serves to reduce the maximum length of the strings that you can compare. Use an int.
You could restructure the code so that it looks like this:
bool list::compareString(const char array1[], const char array2[])
{
// Iterate over the strings until we find the string termination character
for (int count = 0; array1[count] != '\0' && array2[count] != '\0'; count++) {
// Note 0x20 is hexadecimal 32. We're comparing two letters for
// equality in a case insensitive way.
if ( (array1[count] | 0x20) != (array2[count] | 0x20) ) {
// Return false if the letters aren't equal
return false;
}
}
// We made it to the end of the loop. Strings are equal.
return true;
}
As for efficiency, it looks to me like you were trying to reduce:
The size of the variables that you're using to store data in
memory
The number of individual lines of code in your solution
Neither of these are worth your time. Efficiency is about how many steps (not lines of code, mind you) it will take to perform a task and how those steps scale as the inputs get bigger. For instance, how much slower would it be to compare the content of two novels for equality than two single word strings?
I hope that helps :)

ERROR char and const char

I am quite new to programming and the code that I made has confused me. can you please explain the following errors.
int getBill(char seat)// a return function.
{
int b=0;
char FS, fs, LBS, lbs, UBS, ubs, GPS, gps;
char seat;
if(seat=="FS"||seat=="fs")
b=15000;
if(seat=="LBS"||seat=="lbs")
b=10000;
if(seat=="UBS"||seat=="ubs")
b=5000;
if(seat=="GPS"||seat=="gps")
b=1500;
return b;
}
ERROR: Operand types are incompatible( char and const char)
Change your function to take a std::string rather than a single char. And remove the extra char declarations.
int getBill(const std::string &seat)// a return function.
{
int b=0;
if(seat=="FS"||seat=="fs")
....
Note that it's usually much more efficient to pass in structures by const reference as shown above.
Your code looks like C code. In C "strings" are arrays of bytes. Most functions figure out the end of said array by whats known as a "zero terminator" (a byte with the value of zero). Individual elements of the string (or "array") are referred to as "char" for character.
Logic operations can only be performed on "items" which fit into CPU registers i.e. comparing a single byte to another byte, an integer to another integer. In order to compare strings, you need to perform a loop, comparing each character (byte) of the strings (arrays). Luckily C comes with a standard library, which among lots of other useful stuff, contains functions for manipulating strings. Specifically the function strcmp will compare two strings, and return the difference of first non-matching character or zero if a zero-terminator is encountered.
To implement you getBill routine using strcmp, you would do something like:
#include <string.h> /* contains definition of strcmp() */
int getBill(char *seat)
{
int b=0;
char seat;
if(0 == strcmp(seat, "FS") || 0 == strcmp(seat,"fs"))
b=15000;
if(0 == strcmp(seat, "LBS") || 0 == strcmp(seat, "lbs"))
b=10000;
if(0 == strcmp(seat, "UBS") || 0 == strcmp(seat, "ubs"))
b=5000;
if(0 == strcmp(seat, "GPS") || 0 == strcmp(seat, "gps"))
b=1500;
return b;
}
/* example use: */
getBill("FS);
A little more "advanced" solution, would be to use a "case-insensitive" compare function, and put definied values in a "table". Something like:
#include <string.h> /* contains definition of stricmp() */
static const char* bill_types_str[] =
{
"fs", "lbs", "ubs", "gps"
};
static const int bill_type_ids[] =
{
15000, 10000, 5000, 1500
};
int getBill(char *seat)
{
for(i=0; i < sizeof(bill_types_str)/sizeof(bill_types_str[0]; i++)
if (0 == stricmp(seat, bill_types_str[i]))
return bill_types_id[i];
return 0;
}
Doing it like this, makes it really easy to add new "bill types", and also allows for later functionality to list the supported "bill types".
You are trying to compare sting (or char array) with char.
Do you mean?
char seat[SOME_INT_VALUE];
instead of just
char seat

Accepting a grammar in C++

This is a lab assignment I am stuck on.
I need to accept this grammar (ab)*b, which basically means any number of "ab" and ending with b.
I have written this code but somehow, it checks only the first 2 letters.
#include <iostream.h>
#include <conio.h>
#include <string.h>
enum track {true, false};
void main()
{
clrscr();
char*str;
enum track track_pos, track_pos_2;
cout<<"enter the string: ";
cin>>str;
int len=strlen(str);
cout<<"length of the string is "<<len;
getch();
int i;
for(i=0;i<len; i++)
{
++str;
cout<<"loop"<<i;
if(*str=='a' && i%2==0)
{
cout<<"\nchecking a...";
track_pos=true;
cout<<"\na.check";
++str;
if (*str=='b')
{
cout<<"\nchecking b...";
track_pos=true;
cout<<"\nb.check";
}
else{
track_pos=false;
cout<<"\nb.uncheck";
}
}
}
if(*str=='b')
track_pos_2=true;
else
track_pos_2=false;
if(track_pos==true && track_pos_2==true)
cout<<"\nThe string is accpeted.";
else
cout<<"\nThe string is rejected.";
getch();
cout<<"\n\nDo you want to continue (Y/N)? ";
char ch;
cin>>ch;
if(ch=='y' || ch=='Y')
main();
}
I'm going to regret this, but each time I look at this question I see something else wrong with your code. Here is the line by line. I've probably missed a lot.
The correct name for this header is "iostream", not "iostream.h" - the ".h" version is deprecated. Similarly, use "string", not "string.h" in modern C++, and use the modern STL string classes.
#include <iostream.h>
#include <conio.h>
#include <string.h>
As pointed out, don't do this. You have redefined the standard bool type to have the opposite value from the standard types. I don't even know that this is legal.
enum track {true, false};
The return value of the main function is int, not void.
void main()
{
clrscr();
Do you know what a buffer overflow is? You have defined str as a pointer here, with no allocated memory, and you write to that undefined bit of memory a bit later on. This is undefined behaviour, and you are pretty much guaranteed to crash. I recommend, you should defined str as a std::string - this will nicely avoid the buffer overflow, and it has many useful methods that you can use in your program.
char*str;
enum track track_pos, track_pos_2;
cout<<"enter the string: ";
This is the buffer overflow right here. You are writing to who knows what area of memory.
cin>>str;
If str was a std::string - you would do size_t len=str.length();
int len=strlen(str);
cout<<"length of the string is "<<len;
It's probably not a good idea to mix console IO functions like this with iostreams functions - there are some buffering issues that can lead to difficulties.
getch();
Declare i in the body of the loop, since you aren't using it again. Like so:
for (int i=0; i<len; i++) etc...
int i;
for(i=0;i<len; i++)
{
Instead of using poiter arithmetic, since you are keeping track of the index of the current character in i, just use that and treat str as an array. This way, you don't have to keep str in synch with i all of the way through. This is the cause the bug you are reporting, by the way.
++str;
cout<<"loop"<<i;
You should change this to:
if (str[i]=='a' && i%2==0)
(That works even if str is a std::string by the way, unlike the pointer arithmetic version).
if(*str=='a' && i%2==0)
{
You really should drop out at some point, if you figure out that the string doesn't match, then there is no point going on to the end of the string.
cout<<"\nchecking a...";
I don't favour status flags like this - your code is partly hard to understand because of the proliferation of these flags, you cannot keep track of the proper behaviour. The name track_pos is not mnemonic, that makes it hard to work out what it is meant to signify without detailed study of the code.
I would recommend that you would refactor your code inside the body of the for loop to call a function, the purpose of which is simply to match a single group of "ab" - this function could return true if it did, and false if it did not.
track_pos=true;
cout<<"\na.check";
Note that since we are dealing with the buffer overflow mentioned before, you are iterating undefined memory. Also note that you did not increment i here.
++str;
if (*str=='b')
{
cout<<"\nchecking b...";
track_pos=true;
cout<<"\nb.check";
}
else{
track_pos=false;
cout<<"\nb.uncheck";
}
}
}
When we get to here, according to your for loop, we have iterated the whole string, so we must be looking past the end of the string (even ignoring the buffer overflow) so there is no possible way this test can succeed. In short, your for loop must be going too far.
if(*str=='b')
track_pos_2=true;
else
track_pos_2=false;
if(track_pos==true && track_pos_2==true)
Should I mention the spelling mistake?
cout<<"\nThe string is accpeted.";
else
cout<<"\nThe string is rejected.";
getch();
cout<<"\n\nDo you want to continue (Y/N)? ";
char ch;
cin>>ch;
If you refactor your code into appropriate sub-routines, you will find the structure of the program takes care of itself. Note that calling main recursively is not strictly illegal, but it is kind of weird and has an obvious vulnerability that will lead to an eventual stack overflow, if the program never exits.
if(ch=='y' || ch=='Y')
main();
}
Implement a simple state machine. It has these states:
0 = start
1 = 'received a of (ab)'
2 = 'received b of (ab)'
3 = 'received final b'
-1 = error, invalid grammar
Then you just need a function like this:
int nextState(int currentState, char inputChar) {
if (currentState == 0 && inputChar == 'a') return 1; // handled string is "a"
if (currentState == 0 && inputChar == 'b') return 3; // handled string is "b"
if (currentState == 1 && inputChar == 'b') return 2; // handled string is "ab", or "abab", or ...
if (currentState == 2 && inputChar == 'a') return 1; // handled string is "aba", or "ababa", or ...
if (currentState == 2 && inputChar == 'b') return 3; // handled string is "abb", or "ababb", or ...
return -1;
}
Iterate this "state machine" over your input chars, starting with state 0, and if you end up in state 3, your input is valid.
int isValid(char* inputString) {
int state = 0;
for(int i=0; i<str_len(inputString); i++) {
state = nextState(state, inputString[i]);
}
return (state == 3);
}
Things wrong with your code:
#include <iostream.h>
should be:
#include <iostream>
The following is a non-standard (and very old) header:
#include <conio.h>
The following is illegal - true and false are reserved words.
enum track {true, false};
In C and C++, main must return an int:
void main()
Non standard function:
clrscr();
No memory allocated to this pointer:
char*str;
which is then used here - result undefined behaviour:
cin>>str;
Illegal call to main:
main();
I suspect you are using a very old and obsolete C++ compiler. You should replace it with something like MinGW.
Don't do this!
enum track {true, false};
Here your true is equal to 0 and false is equal to one! When you later assign track_pos, you may get the wrong value! (Because when converting bool to int, true converts to 1 and false converts to 0.)
That's only a guess though. Maybe it's something else that matters.