Iterate over a NULL complete array of strings using for_each

Iterating over a NULL terminated string using for_each is possible:

const char *name = "Bob"; void func(const char &arg) { cout << arg; } int main() { for_each(name, name + strlen(name), func); } 

Is something like this possible for NULL with a complete list of strings (without having to determine the total length of the list), for example:

 const char *names[] = { "Bob", "Adam", "Simon", NULL }; 
+4
source share
10 answers

std :: for_each "iterates" over a range, so to use it with an array of indefinite length you need to use custom iterators to signal the end of the array (on a NULL member). If you insist on using the NULL-end char * array, you can, of course, create your own for_each function for it, for example, for example:

 template <typename Function> void for_each_in_null_terminated_cstring_array(const char** array, Function f) { while (*array) { f(*array); array++; } } const char *names[] = { "Bob", "Adam", "Simon", NULL }; for_each_in_null_terminated_cstring_array(names, func); 

I do not recommend this solution.

edit: Yes, a more general one is always better, isn't it?

 template <typename T, typename Function> void for_each_in_null_terminated_array(T* array, Function f) { while (*array) { f(*array); array++; } } 

(Here's the implementation of the null-terminated (false-terminated) iterator that I mentioned earlier with a change or two based on the suggestions below. It should be a real InputIterator)

 template <class T> class nt_iterator: public std::iterator<std::input_iterator_tag, T> { public: typedef typename nt_iterator<T>::pointer pointer; typedef typename nt_iterator<T>::value_type value_type; nt_iterator(): p(), pte(true) {} nt_iterator(pointer p_): p(p_), pte(!p_) {} nt_iterator(const nt_iterator<T>& rhs): p(rhs.p), pte(rhs.pte) {} nt_iterator<T>& operator++() { ++p; if (!*p) pte = true; // once past-the-end, always past-the-end return *this; } nt_iterator<T> operator++(int) { nt_iterator n(*this); operator++(); return n; } bool operator==(const nt_iterator<T>& rhs) { return pte && rhs.pte || p == rhs.p; } bool operator!=(const nt_iterator<T>& rhs) { return !(operator==(rhs)); } value_type operator*() { return *p; } private: pointer p; bool pte; // past-the-end flag }; 

And how is it used:

 void print(const char* str); int main() { const char* array[] = {"One", "Two", "Three", NULL, "Will you see this?"}; std::for_each(nt_iterator<const char*>(array), nt_iterator<const char*>(), print); } 

It is probably a little slower than the version of the loop, due to the increased number of equivalence checks - the difference in speed is, of course, insignificant compared, for example, with the text, but it should be noted that std::for_each does not magically do (actually in fact, you may be surprised to see how your compiler provider defines a function, that is, if you expect too much).

+8
source

WITH

 const char *names[] = { "Bob", "Adam", "Simon" }; 

you can just call

 std::for_each(names, names + sizeof(names)/sizeof(names[0]), func ); 

or, better, using two helper functions :

 std::for_each(begin(names), end(names), func ); 

Of course, this fails when the array decays to a pointer (but at least the compiler will not accept it then). If you must rely on this NULL trailing, you either need to write your own looping function, or count in front of you, as with std::strlen() :

 std::ptr_diff_t num = std::find( names , names + std::numeric_limits<std::size_t>::max() , NULL); std::for_Each( names, names+num, func ); 
+3
source

The extension on Basilevs meets a fully working solution.

A custom iterator can be defined as follows:

 template <class T> class NullTerminatedIterator :public std::iterator<std::forward_iterator_tag, T,ptrdiff_t,const T*,const T&> { public: typedef NullTerminatedIterator<T> NTI; NullTerminatedIterator(T * start): current(start) {} NTI & operator++() {current++; return *this;} T & operator*() { return *current; } static NTI end() { return NTI(0); } bool operator==(const NTI & that) { return *current == *that.current; } bool operator!=(const NTI & that) { return *current != *that.current; } private: T * current; }; 

And then used like this:

 const char *names[] = {"Bob", "Adam", "Simon", NULL}; NullTerminatedIterator<char*> iter((char**)names); for_each(iter, NullTerminatedIterator<char*>::end(), func); 

The base class for NullTerminatedIterator is taken from this custom iterator .

This only happens while going through the list while calling for_each on demand.

+3
source

There were several answers that tell you what you can do instead. However, the answer to your specific question is simply "no, you cannot" :)

+1
source

You can use sizeof () for compile-time size arrays.

 const char *names[] = { "Bob", "Adam", "Simon" }; std::for_each(names, names + sizeof(names)/sizeof(*names), [](const char* arg) { std::cout << arg << "\n"; }); std::cin.get(); 

For arrays with dynamic size, you should use std::vector<std::string> and iterate over them.

Sorry for using lambdas, your compiler (maybe) does not support them.

0
source

instead, add them to the container and swipe them using for_each
I use a vector for my example:

 void function(string name) { cout << name; } int main() { vector<string> nameVector; nameVector.push_back("Bob"); nameVector.push_back("Adam"); nameVector.push_back("Simon"); for_each(nameVector.begin(), nameVector.end(), function); return 0; } 
0
source

Could you replace the argument passed to func with a pointer to a const char pointer to achieve what you want. A view like this:

 const char *names[] = { "Bob", "Adam", "Simon" }; void func( const char* &arg ) { cout << arg << endl; } int main() { for_each( names, names + sizeof( names ) / sizeof( names[ 0 ] ), func ); } 

And, obviously, for a string array ending with NULL, just subtract 1 from the size of the array ...

0
source
 template <class T> struct NullTerminatedIterator { typedef NullTerminatedIterator<T> NTI; T * current; NTI & operator++() {current++; return this;} T & operator*() {return *current;} NullTerminatedIterator(T * start): current(start) {} static NTI end() {return NTI(0);} bool operator==(const NTI & that) {return current==that.current;} } 
0
source

I know this is not for_each, but I wanted to use the old regular for-loop to do the same. This is from the MSDN blog :

This reinterpretation of a line with a terminating double zero, as indeed a list of lines with an empty line as a terminator, makes the written code a fairly simple way through a line with a double zero completion:

 for (LPTSTR pszz = pszzStart; *pszz; pszz += lstrlen(pszz) + 1) { // ... do something with pszz ... } 

It looks somehow pure to me!

0
source
  // C version const char* vars[16]={"$USER","$HOME","$DISPLAY","$PASSWORD",0}; for(const char** pc = vars; *pc!=0; pc++) { printf("%s",*pc); } 
0
source

All Articles