Search code examples
c++pointersiteratorstdstl-algorithm

Get an iterator from a char pointer (C++)


I am challenging myself to write a Palindrome tester using only SL algorithms, iterators etc. I also want to program to work with raw strings. Below, I use the raw pointer pal in the copy_if algorithm, but instead, how could I define an iterator to go here, i.e. by using something like begin(pal) and end(pal + size)?

#include <algorithm>
#include <iterator>
#include <cctype>

using namespace std;

bool isPalindrome(const char* pal) {
    if (!pal) { return(false); }

    int size = strlen(pal);
    string pal_raw;
    pal_raw.reserve(size);

    // Copy alphabetical chars only (no spaces, punctuations etc.) into pal_raw
    copy_if(pal, pal+size, back_inserter(pal_raw),
        [](char item) {return isalpha(item); }
    );

    // Test if palindromic, ignoring capitalisation
    bool same = equal(begin(pal_raw), end(pal_raw), rbegin(pal_raw), rend(pal_raw),
        [](char item1, char item2) {return tolower(item1) == tolower(item2); }
    );

    return same;
}

int main(){
    char pal[] = "Straw? No, too stupid a fad. I put soot on warts.";
    bool same = isPalindrome(pal);
    return 0;
}

Bonus Question: Is it possible to eliminate the need to copy_if() by incrementing the iterators 'in place' from within equal() i.e. when !isalpha(item)?


Solution

  • Iterators implement the concept of pointers, when it comes to C++ library algorithms. And, as you've discovered, C++ library algorithms that take iterators are perfectly happy to also take pointers. It's the same concept.

    And when you already have pointers to begin with there is no iterator, of some kind, that the pointers can be converted to.

    It is true that

    std::begin(arr)
    

    and

    std::end(arr)
    

    are defined on flat arrays. But, guess what: they return a pointer to the beginning and the end of the array, and not an iterator class of some kind.

    However, you cannot use std::begin(), and std::end() because by the time you need to use it, inside your function, the array was already decayed to a char *. std::begin() and std::end() works on real arrays, and not decayed pointers.

    If you insist on using iterators, you should pass a std::string to your palindrome function, instead of a char *. std::string implements a begin() and an end() method that return a std::string::iterator, that you can use.