How to check string is only letters - c++

I know that I can check if a "word" is all letters by:
bool checkAlpha(string str){
bool retVal;
for(int i = 0; i < str.size(); i++){
if(isalpha(str[i]) == 0){
retVal = true;
cout << "Input must only contain letters\n";
break;
}
else{
retVal = false;
cout << "all good\n";
}
}
return retVal;
}
Because of how I use the function return value, I need it to return TRUE if it is NOT all letters, and FALSE if it IS all letters. There's probably an easier way to do this but I just started C++ so this works for my current purpose.
My question is how do I check if a string is multiple "words"? When it reaches a space the function (correctly) says the space is not an alpha and tells me the input must only be letters. I tried doing
if((isalpha(str[i]) != 0) || (str[i] == " "))
and changing the "if" to return false (input only letters & space) and "else" to return true, but when I tried this I got a compiler error:
ISO C++ forbids comparison between pointer and integer [ -fpermissive]
So what can I do to get that a string of user input is only letters or space? (Preferably the simplest method)

This statement:
str[i] == " "
Is incorrect, it should be:
str[i] == ' '
but even better
isspace( str[i] )
as your condition does not check for other symbols like tab etc.
Also you have break in logic, in case you meet not alpha and not space you can set retVal to true (and also should terminate loop as you already got the answer), but you cannot set it to false otherwise. So your corrected code could be:
bool checkAlpha(const string &str){
bool retVal = false;
for(int i = 0; i < str.size(); i++){
if( !isalpha(str[i]) || !isspace(str[i]){
retVal = true;
cout << "Input must only contain letters\n";
break;
}
}
if( !retval )
cout << "all good\n";
return retVal;
}
if you do not need to provide diagnostic messages, function can be as simple as:
bool checkAlpha(const string &str){
for(int i = 0; i < str.size(); i++)
if( !isalpha(str[i]) || !isspace(str[i])
return true;
return false;
}
And your function name is confusing, based on return values it should be called checkNotAlpha

I guess it should be enought to fix it as follows:
if((isalpha(str[i]) != 0) || (str[i] == ' '))

Related

What is wrong with my program to find the longest word in a sentence?

#include <iostream>
using namespace std;
int main() {
char a[101]{0};
cin>>a;
cin.getline(a,101);
cin.ignore();
int currLen{0};
int maxLen{0};
int startInd{-1};
int endInd{-1};
for(int i=0; i<101; i++) {
if(a[i]!=' ' ) {
++currLen;
} else if(a[i]==' '||a[i]=='\0') {
if(currLen>maxLen) {
maxLen=currLen;
startInd=i-currLen;
endInd=i-1;
}
if(a[i]=='\0')
break;
currLen=0;
}
}
cout<<maxLen<<endl;
if(startInd==-1)
cout<<-1;
else
for(int i=startInd; i<=endInd; i++)
cout<<a[i];
return 0;
}
If I take an input here, for example, "My name is Manav Kampani"
It will output 5
Manav instead of 7
Kampani
But if I write "My name is Manav Kampani ", with space after the last word
than it is considering Kampani too printing Kampani.
Also when I input "Kampani Manav is my name" then too it's displaying the wrong output. That means it is not considering the first word of the sentence.
if(a[i]!=' ' )
{
++currLen;
}
else if(a[i]==' '||a[i]=='\0')
{
....
}
Consider the case of a[i] == 0. Which of these if-statements will apply.
Answer: the first one. Which means you'll never look at the final word in the string. You also don't exit at the end of the string, but instead loop through whatever is in your string all the way out to character 101.
As a general structure, be very, very careful with this:
if (condition)
else if (condition)
// without a final else section
If you do that, you need to think about what you're doing. In this particular case, you can have:
if (a[i] != 0 && a[i] != ' ')
else
It may not solve all your issues, but it should solve some.
A nice sliding window pattern implementation.
You have 3 problems in your code
You must not write cin >> a;
You must not write cin.ignore();
You need to modify your if statement like so: if (a[i] != ' ' && a[i] != '\0') Otherwise you will not detect the last word.
Your complete working code with that minor fixes will lokk like that.
int main()
{
char a[101]{ 0 };
//cin >> a;
cin.getline(a, 101);
//cin.ignore();
int currLen{ 0 };
int maxLen{ 0 };
int startInd{ -1 };
int endInd{ -1 };
for (int i = 0; i < 101; i++)
{
if (a[i] != ' ' && a[i] != '\0')// Add comparison
{
++currLen;
}
else if (a[i] == ' ' || a[i] == '\0')
{
if (currLen > maxLen)
{
maxLen = currLen;
startInd = i - currLen;
endInd = i - 1;
}
if (a[i] == '\0')
break;
currLen = 0;
}
}
cout << maxLen << endl;
if (startInd == -1)
cout << -1;
else
for (int i = startInd; i <= endInd; i++)
cout << a[i];
return 0;
}
Additionally. You should not use C-Style arrays in C++. And please use std::string
There is a couple of things here:
1- You don't need to do a cin>>a this is actually consuming the first word, and afterwards the content is overrided by cin.getline(). So removing the firsst cin>>ayou'll be fine.
2- The last word is not read because there isn't any if condition that matches the condition aka.
if(a[i]!=' ' ) case of not a space
//not end of word
else if(a[i]==' '||a[i]=='\0') case of space or null
//end of word
So your last character is not a space nor null, that means you don't detect the last word.

A loop never starts

I'm writing a simple function that is supposed to read an input from a user as a string. Check if the strings solely consist of digits then converts it to and int and returns it. The problem is the loop never used regardless of the input. I'm struggling to find the root of the problem.
int correctInt()
{
string temp;
int input;
bool m;
do
{
m = false;
getline(cin, temp);
int length=temp.length();
for (int a = 0; a < length; a++)
{
if (temp[a] < '0' && temp[a]>'9')
{
cout << "ID should consist of numbers. Try again: ";
m = true;
break;
}
}
if (!m)
{
return input = atoi(temp.c_str());
}
} while (1);
}
Thank you in advance
You should use OR instead of AND:
temp[a] < '0' || temp[a]>'9'
Try to change && (and) condition to || (or) condition
if (temp[a] < '0' || temp[a]>'9')

Problem with boolean variable in email validation program [duplicate]

This question already has answers here:
What is a debugger and how can it help me diagnose problems?
(2 answers)
Closed 3 years ago.
I am trying to create an email validation program without using the regex library. In one of my functions, I want to return a Boolean to check if there is an # sign in the email address and also if it is in a valid position (the # sign cannot be one of the first three characters of the string). However I am having problems with it because every time I run the program by entering in an email address with the # sign in an invalid position, it keeps telling me that the email is valid. Please help!
valid = checkEmail(email); //function call
if(valid == true)
cout << "Your email is valid!" << endl;
else
cout << "Your email is invalid!" << endl;
bool checkEmail(string email)
{
int counter;
int length;
bool firstThree; //checks to make sure # is not in the first three chars
counter = 0;
length = email.length();
firstThree = false;
for(int i = 0; i < length; i++)
{
if(email[i] == '#')
counter++;
}
for(int y = 0; y < length; y++)
{
if(email[0] == '#' || email[1] == '#' || email[2] == '#')
firstThree = true;
else
firstThree = false;
}
cout << "\n" << counter << endl; //check to see if counter works
if(counter != 1 && firstThree == true)
return false;
else
return true;
}
I guess you need to define the function bool checkEmail(string email) at the begining of the program. Basically flip if else and the function definition.
bool checkEmail(string email)
{
int counter;
int length;
bool firstThree; //checks to make sure # is not in the first three chars
counter = 0;
length = email.length();
firstThree = false;
for(int i = 0; i < length; i++)
{
if(email[i] == '#')
counter++;
}
for(int y = 0; y < length; y++)
{
if(email[0] == '#' || email[1] == '#' || email[2] == '#')
firstThree = true;
else
firstThree = false;
}
valid = checkEmail(email); //function call
if(valid == true)
cout << "Your email is valid!" << endl;
else
cout << "Your email is invalid!" << endl;
There seem to be a lot of beginner mistakes here, so I suggest learning the basics of programming and c++ first and like others suggested, use a debugger. Here are some of the mistakes:
Function definition
c++ is not like other common languages in the sense that functions need to be defined before they can be used. This means that you either need to move your checkEmail function above the function call, or create a separate definition above the function call like:
bool checkemail(string email);
as an exmaple.
Incorrect if-statement logic; Unnecessary for loop:
I'm assuming that based on how emails are formatted, you want the checkEmail function to return false if it doesn't match the correct formatting, and based on what your function currently does, that means that it will return false if the first three characters are # or if there isn't exactly one # symbol in the email. However, you used a && operator, which signifies and, meaning it will return true even when you don't want it to (much like how #Yastanub stated in his first comment). Better yet, that entire logic and if statement can be simplified greatly using std::string::find with a while loop and a vector (similar to this method):
vector<size_t> posVec;
size_t pos = email.find('#', 0); //note that this can be an int instead of size_t, but it can cause stack overflow with bigger numbers
while(pos != string::npos){
posVec.push_back(pos);
pos = email.find('#', pos+1);
}
switch(posVec.size()){
//if there is only one # symbol found
case 1:
bool firstThree = false;
for(int i = 0; i <= 2; i++)
//if there is only one # but it's in the first 3 positions, the email isn't valid
if(posVec[0] == i)
firstThree = true;
return !firstThree;
//otherwise the email doesn't work
default:
return false;
}
Remember to include the required libraries in order for this part to work:
#include <string>
#include <vector>
This also eliminates the second for loop in your function that is useless because the variable y is not being used, and the counter that was being used for testing
Another note
Using if (valid == true) is unnecessary as well. You can just use if (valid) because of how booleans work with if-statements.

c++ getting weird crashes in my program [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 5 years ago.
Improve this question
#include <iostream>
using namespace std;
int main()
{
int a = 0, skrb = 0, j = 0;
char b, simboliai[2000];
char zodis[50][20];
char check[1][20] = {'f'};
cout << "Prasome irasykite sakini: ";
cin.getline(simboliai,sizeof(simboliai));
//----------------- Zodziu skaidymas ----------------------------------------------------------------------------------------------------------
a = 0;
for (int i = 0; i > -1; i++)
{
if ((simboliai[i] == 's' && simboliai[i++] == ' ') || (simboliai[i] == 's' && simboliai[i++] == '\n'))
{
check[0][a] = 't';
}
if (simboliai[i] == ' ')
{
a++;
}
else
{
zodis[i][a] = simboliai[i];
}
if (simboliai[i] == '\n')
{
break;
}
}
a = 0;
while (1)
{
if (simboliai[a] == '.' || simboliai[a] == ',' || simboliai[a] == '!' || simboliai[a] == '?')
{
skrb++;
}
a++;
if (simboliai[a] == '\n')
{
break;
}
}
a = 0;
cout << "Jus ivedete tokius zodius kurie baigiasi raide 's'" << endl;
while(1)
{
if (zodis[j][a] == 'Ì')
{
cout << '\n';
a++;
}
if (check[0][a] == 't')
{
cout << zodis[j][a];
}
if (zodis[0][a] == 'Ì')
{
break;
}
}
cout << "Pas jus yra (.','!'?) simboliu: " << skrb << endl;
cin.ignore();
cin.get();
}
Basically this program would work but that for part just ruins everything. It doesn't put characters one by one. And when I debug it shows that program have put symbol in its place but then there is Ì.
So it looks just like so
input: word word
zodis[0][0] goes like wÌÌÌÌÌÌÌÌÌÌ zodis [1][0] goes oÌÌÌÌÌÌÌÌÌÌ and so on and it breaks. Thank you in advance.
If you are saying the for loop wouldn't put characters 1 by 1, it was in your "simboliai[i++] == ' '" logic. integer 'i' been incremented twice each loop when current character is 's' which mean it will be incremented from i=2 to i=4 if simboliai[i] = 's'. Use i+1 instead for your checking.
for (int i = 0; i > -1; i++)
{
...
}
is the main problem. There might be others but I don't look too closely for them.
The values of i will be 0, 1, 2. etc.
All of them are greater than -1.
The loop will go on until the value i reaches INT_MAX. (Not sure what happens when i is incremented at that time).
That is way larger than the size of the array simboliai anyway. Your program will access the array simboliai beyond valid limits and cause undefined behavior.
I think what you need is:
size_t len = strlen(simboliai);
for (size_t i = 0; i < len; i++)
{
...
}
Other Problems
Some of the errors result from the assumption that there is a newline character in simboliai. That assumption is not correct. std::istream::getline reads and discards the newline character.
If Google Translate is correct, zodis is supposed to contain a list of words. When you are iterating over the characters of simboliai, you need three counters.
One to iterate over the characters of simboliai.
One to keep track of the number words.
One to keep track of the number of characters in the current word.
Your for loop is not doing that.
When you are trying to access the contents of an array, you need to always write defensive code and make sure that you never access the array using out of bounds indices. In the last while loop, you are not doing that.
In the last while loop, you are incrementing a only in the first if block. If the conditional of that if statement evaluates to false, a never gets incremented and you get stuck in an infinite loop.
In the last loop you use j as an index but its value is initialized to 0 at the start of the function and never gets updated. It's not clear what the intent of the last while loop is. Hence, I can't say whether it's a bug but it sounds like it could be.
Here's a cleaned up version of your posted code with still a few unknowns.
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
int a = 0, skrb = 0, j = 0;
char b, simboliai[2000];
char zodis[50][20];
char check[1][20] = {'f'};
cout << "Prasome irasykite sakini: ";
cin.getline(simboliai,sizeof(simboliai));
//----------------- Zodziu skaidymas ----------------------------------------------------------------------------------------------------------
int word_counter = 0;
a = 0;
size_t len = std::strlen(simboliai);
for (size_t i = 0; i < len; i++)
{
if ((simboliai[i] == 's' && simboliai[i+1] == ' ') || (simboliai[i] == 's' && simboliai[i+1] == '\0'))
{
check[0][a] = 't';
}
if (simboliai[i] == ' ')
{
zodis[word_counter][a] = '\0';
a = 0;
++word_counter;
}
else
{
zodis[word_counter][a] = simboliai[i];
++a;
}
}
a = 0;
while ( simboliai[a] != '\0' )
{
if (simboliai[a] == '.' || simboliai[a] == ',' || simboliai[a] == '!' || simboliai[a] == '?')
{
skrb++;
}
a++;
}
a = 0;
cout << "Jus ivedete tokius zodius kurie baigiasi raide 's'" << endl;
while( j < 50 && a < 20 )
{
if (zodis[j][a] == 'Ì')
{
cout << '\n';
}
if (check[0][a] == 't')
{
cout << zodis[j][a];
}
if (zodis[0][a] == 'Ì')
{
break;
}
a++;
}
cout << "Pas jus yra (.','!'?) simboliu: " << skrb << endl;
cin.ignore();
cin.get();
}

How can I fix this c++ palindrome code? [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 9 years ago.
Improve this question
So I'm trying to write a c++ palindrome program. I've come up with two functions so far.
void isPal(string str)
{
int a = 0, b = str.length();
string checker1 = "", checker2 = "";
for (; a != str.length(); a++)
checker1 += str[a];
for (; b >= 0; b--)
checker2 += str[b];
cout << checker1 << " " << checker2 << endl;
if (checker1 == checker2)
cout << "Palindrome baby!" << endl;
if (checker1 != checker2)
cout << "Not palindrome!" << endl;
}
bool isit(string str)
{
int x = str.length(), counter = 0;
if (str.length() <= 1)
return true;
else
{
while (counter != str.length())
{
string strNew = str.erase(0, 1);
strNew = strNew.erase(strNew.length() - 1);
string strNewer = str.replace(1, x, strNew);
return str[0] == str[str.length()] && isit(strNewer);
counter++;
}
}
}
Why does the first function always returns the "Not palindrome!" if-statement?
I'll admit that the second is a mess. I'm not even sure I completely understand my thinking when I wrote it. My intentions was to come up with a similar answer to the recursive Python palindrome code.
In python the inductive case was simply
return str[0] == str[-1] and isit( str[1:-1] )
How can I write an inductive c++ palindrome code?
Update: -4 for a beginner's question!! really ? :)
The simplest way to check whether a string is palindrome is to write
if ( s == std::string( s.rbegin(), s.rend() ) ) std::cout << "The string is palimdrome." << std::endl;
As for your approach with recursion then the function could look the following way
bool isPal( const std::string &s )
{
return ( s.size() < 2 || ( s[0] == s[s.size() - 1] && isPal( s.substr( 1, s.size() - 2 ) ) ) );
}
You have a lot of problems in both of your functions. To test for a palindrome, you only need to loop through the string once:
bool isPalindrome(const std::string& s)
{
for (int i = 0; i < s.length() / 2; ++i)
{
if (s[i] != s[s.length() - 1 - i])
{
return false;
}
}
return true; // if every element has a mirror, it is a palindrome
}
In your second version:
return str[0] == str[str.length()] && isit(strNewer);
counter++;
The second line will never get executed.
Writing a recursive version of the function would be a waste, but would require either copying the substrings, or providing an index to the function:
Copy Version
bool isPalindrome(const std::string& s)
{
if (s.length() <= 1)
return true;
if (s[0] != s[s.length() - 1]) // or s.front() != s.back() in C++11
return false;
std::string t = s.substr(1, s.length() - 2));
return isPalindrome(t);
}
Indexed Version
bool isPalindrome(const std::string& s, int index = 0)
{
if (index <= s.length() / 2)
{
return s[index] == s[s.length() - 1 - index] && isPalindrome(s, ++index);
}
return true;
}
There are two key things you should know about how strings work:
Every quoted string, aka "c-string" or "string literal", consists of an array of 0 or more char followed by a null character '\0', e.g. the string "bar" has three printable characters ( 'b', 'a', & 'r' ) and one non-printing character '\0' (the null character). So, str.c_str() would be equivalent to char str[4] = {'b','a','r','\0'} in this case.
The length() of a string is equal to the number of printable characters.
The first iterator for (; a != str.length(); a++) counts from a=0 up to a=(str.length()-1) (as it should). That means that only the characters of the string (and not the null-terminus) will be appended by your checker1 += str[a]; line. Internally, a '\0' will be automatically put at the end.
The second iterator -- for (; b >= 0; b--) -- is does not properly mirror the first. It counts from b=str.length() down to b=0. Following from points 1 and 2, it should not be obvious that the character at str[str.length()] will always be '\0'. That means that your appended string, checker2 is first assigned the null-terminator, and then the rest of the string. That means that when you check the two for inequality, is will appear as if it were a zero-length string, i.e. "". As such, it will always evaluate as != for any non-zero-length str, and your function will always print "Not palindrome!".