Iterate over NULL terminated array of strings using for_each
可以使用for-each迭代以空结尾的字符串:
1 2 3 4 5 6 7 8 9 10 11 | const char *name ="Bob"; void func(const char &arg) { cout << arg; } int main() { for_each(name, name + strlen(name), func); } |
对于以空结尾的字符串列表(不必首先确定列表的总长度),是否有类似的可能,例如:
1 | const char *names[] = {"Bob","Adam","Simon", NULL }; |
std::对于一个范围内的每个"迭代",因此要将它与一个长度不确定的数组一起使用,需要使用自定义迭代器来表示数组的结尾(在空成员上)。如果您坚持使用以空结尾的char*数组,您当然可以为它创建自己的for_每个函数,例如:
1 2 3 4 5 6 7 8 9 10 11 | 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); |
不过,我并不推荐这种解决方案。
编辑:是的,越一般越好,不是吗?
1 2 3 4 5 6 7 8 | template <typename T, typename Function> void for_each_in_null_terminated_array(T* array, Function f) { while (*array) { f(*array); array++; } } |
(这里是我前面提到的一个以空结尾的("false")迭代器的实现——根据下面的建议进行一两次更改。应该是个真正的住院医生)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | 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 }; |
以及它的使用方法:
1 2 3 4 5 6 7 8 9 | 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); } |
它可能比循环版本慢一点,因为等价性检查的数量增加了——当然,与打印文本相比,速度差异是微不足道的——但是应该注意的是,
扩大巴塞利夫的答案与充分工作的解决方案。
自定义迭代器的定义如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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; }; |
然后像这样使用:
1 2 3 4 5 | const char *names[] = {"Bob","Adam","Simon", NULL}; NullTerminatedIterator<char*> iter((char**)names); for_each(iter, NullTerminatedIterator<char*>::end(), func); |
nullTerminateEditor的基类取自此自定义迭代器问题。
这只会在每次调用for_期间按要求遍历列表。
用
1 | const char *names[] = {"Bob","Adam","Simon" }; |
你可以打电话
1 | std::for_each(names, names + sizeof(names)/sizeof(names[0]), func ); |
或者,更好的是,使用两个助手函数:
1 | std::for_each(begin(names), end(names), func ); |
当然,当数组衰减为指针时,这会失败(但至少编译器那时不会接受它)。如果您必须依赖尾随的
1 2 3 4 | std::ptr_diff_t num = std::find( names , names + std::numeric_limits<std::size_t>::max() , NULL); std::for_Each( names, names+num, func ); |
有很多答案告诉你你可以做什么。然而,对您的特定问题的回答只是"不,您不能":)
1 2 3 4 5 6 7 | // C version const char* vars[16]={"$USER","$HOME","$DISPLAY","$PASSWORD",0}; for(const char** pc = vars; *pc!=0; pc++) { printf("%s",*pc); } |
我知道这不是针对每个人的,但我想用旧的正则for循环来做同样的事情。这一个来自msdn博客:
This reinterpretation of a double-null-terminated string as really a list of strings with an empty string as the terminator makes writing code to walk through a double-null-terminated string quite straightforward:
1 2 3 | for (LPTSTR pszz = pszzStart; *pszz; pszz += lstrlen(pszz) + 1) { // ... do something with pszz ... } |
我觉得有点干净!
1 2 3 4 5 6 7 8 9 10 11 | 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;} } |
不能将传递给func的参数替换为指向const char的指针的引用,以实现所需的功能。就像这样:
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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 ); } |
显然,对于以空结尾的字符串数组,只需从数组大小中减去1…
将它们添加到一个容器中,并使用for-each迭代它们我用一个向量作为例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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; } |
可以对编译时大小的数组使用sizeof()。
1 2 3 4 5 6 | const char *names[] = {"Bob","Adam","Simon" }; std::for_each(names, names + sizeof(names)/sizeof(*names), [](const char* arg) { std::cout << arg <<" "; }); std::cin.get(); |
对于动态调整大小的数组,您应该使用
请原谅我使用了lambda,您的编译器(可能)不支持它们。