I am trying to validate a single-line input string in C 11 to see if it contains any leading / trailing whitespaces. My code now looks like this:
bool is_valid(const std::string& s) {
auto start = s.begin();
auto end = s.end();
if (std::isspace(*start) || std::isspace(*end)) {
return false;
}
return true;
}
int main() {
std::string name{};
std::getline(std::cin, name);
if (!is_valid(name)) {
std::cout << "Invalid!";
}
return 0;
}
But now the program can only detect leading whitespaces. For example, for John
it would print Invalid!
but for Mary
it would classify it as valid input, which is not. Does anyone know what's wrong with my program? Thanks!
CodePudding user response:
A simple test for std::string::front() and std::string::back() could have been done after testing for the empty string:
bool is_valid(const std::string& s)
{
return s.empty() ||
(!std::isspace(static_cast<unsigned char>(s.front())) &&
!std::isspace(static_cast<unsigned char>(s.back())));
}
CodePudding user response:
s.end()
is one pass the end of the string just like any other containers in C , so accessing it invokes undefined behavior. You need to use std::prev(s.end())
instead (which is valid only the string contains at least 1 character though, so you need to check the string length first)
CodePudding user response:
The end iterator does not point to an element in the container. It points one past the last element. You may not dereference the end iterator. For a std::string
you can use it's operator[]
:
char last_char = s[s.size()-1];
advance the begin iterator:
auto it = s.begin() s.size()-1;
char last_char = *it;
or decrement the end iterator:
auto it = s.end() -1;
char last_char = *it;
Other alternatives are back()
or using the reverse iterator rbegin()
.
Note that they all require s.size() != 0
. For an empty string s.begin() == s.end()
. You should check that first in the function and return true
for that case.
CodePudding user response:
.end
is used to get an iterator to past the last element. You can use std::string::rbegin
to get the last element.
auto end = s.rbegin();
NB: std::string::starts_with
and std::string::ends_with
are available from C 20.
CodePudding user response:
Yes, .end()
is to the past-the-end element. Then why not using .back()
instead?
bool is_valid(std::string const& str) {
return str.empty() || !(std::isspace(str.front()) || std::isspace(str.back()));
}