Given Question:
Output "Valid" if input doesn't start with a letter. Otherwise, output "Invalid".
My Issue:
Can only ouput "invalid" statements for words that begin with letters from the alphabet but CANNOT output "valid" statements for words that begin with nonalphabetic characters(eg. 7961, $zt93v, and 51903784).
#include <iostream>
using namespace std;
int main() {
bool passwordValid;
string keyString;
cin >> keyString;
/// restricted from editing above this
while (!(isalpha(keyString.at(0)) ) ){
passwordValid == true;
the behavior of std::isalpha is undefined if the argument's value is neither representable as unsigned char nor equal to EOF. To use these functions safely with plain chars (or signed chars), the argument should first be converted to unsigned charhttps://en.cppreference.com/w/cpp/string/byte/isalpha
To be blunt, that is an (unnecessary) abomination.
To use those functions "safely" in these excessive terms the keyboard device (or any other input device) would have to be using the same locale as whoever compiled the program and you would have to have consensus as to which letters would return isalpha as non-zero (true).
For any reasonable input from a standard keyboard a cast is unnecessary pedantry. For any ASCII input (int = 0 to 127) - all that isalpha seems to be unambiguously defined for - the cast is unnecessary.
> For any reasonable input from a standard keyboard a cast is unnecessary pedantry.
Use std::isupper from <locale>; it does not require a cast.
Or program in a language (eg. Java) which by and large steers clear of undefined behaviour.
In C++, these are the options:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
#include <iostream>
#include <cctype>
#include <locale>
int main()
{
char c = 0 ;
std::cin >> c ;
[[maybe_unused]] bool a = std::isupper( static_cast< unsignedchar >(c) ) ; // alpha as per the current C locale
[[maybe_unused]] bool b = std::isupper( c, std::cin.getloc() ) ; // alpha as per the current stdin input locale
[[maybe_unused]] bool d = std::isupper( c, std::locale::classic() ) ; // alpha as per the current C locale
[[maybe_unused]] bool e = std::isupper( c, std::locale() ) ; // alpha as per the global C++ locale
[[maybe_unused]] bool f = std::isupper(c) ; // potential undefined behaviour
}
#include <iostream>
#include <cctype>
#include <limits>
int main()
{
int i1 = std::numeric_limits<char>::min();
int i2 = std::numeric_limits<char>::max();
std::cout << "char range " << i1 << " to " << i2 << '\n';
for ( int i = i1; i <= i2; i++ )
{
// char c = i;
// unsigned char u = c;
char c = static_cast<char>( i );
unsignedchar u = static_cast<unsignedchar>( c );
std::cout << i << '\t' << c << '\t' << u << '\t' << std::isalpha( c ) << '\t' << std::isalpha( u ) << '\n';
}
}
"Potential undefined behaviour" can be taken to ridiculous extremes.
For example, int i = 123456;
would be "potential undefined behaviour" because the C++ standard only requires int to have a minimum range -32767 to 32767.
However, I don't think anyone would baulk at writing int i = 123456;
> For example,
> int i = 123456;
> would be "potential undefined behaviour" because ...
No. Narrowing conversions do not engender undefined behaviour.
Enable warnings, and the compiler can help you detect loss of information owing to narrowing.
1 2 3 4 5 6 7 8
int main()
{
// *** warning: implicit conversion from 'long long' to 'int' changes value from 123456789087654321 to ...
[[maybe_unused]] int i = 123456789087654321 ;
// *** warning: implicit conversion from 'int' to 'char' changes value from 123456 to ...
[[maybe_unused]] char c = 123456 ;
}