【问题标题】:while (end of array) - how to recognize而(数组结束) - 如何识别
【发布时间】:2011-10-12 14:23:40
【问题描述】:

我有一个数字数组 {1,2,3,4,5} 或一个字符数组或其他。我想写一个模板方法来打印出完整的数组。它有效,只是有一些问题。也许我先发布代码:

template <typename A>
void printArray(A start) {
    int i = 0;
    while (start[i] != 0) {
        std::cout << start[i] << std::endl;
        i++;
    }
}

int main(int argc, char **argv) {

    using namespace std;
    int xs[] = {1,2,3,4,5,6,7}; //works
    //int xs[] = {1,0,3,6,7}; of course its not working (because of the 0)
    int *start = xs;

    printArray(start);

    return 0;
}

你能看出问题吗? while(start[i] != 0) 不是读取数组以结束的最佳方式;)我还有什么其他选择?

谢谢!

【问题讨论】:

  • 你不是在传递一个数组,你是在传递一个指针。
  • 不要将普通数组视为 C 风格的空终止数组。

标签: c++ arrays templates while-loop


【解决方案1】:

选项1:传递一个指针和元素个数

 template<class T>
 void doSth(T* arr, int size)

优势 - 适用于动态和自动数组。
劣势 - 您必须知道大小。你必须通过它。

选项2:将模板参数化为自动推导出的尺寸

template <class T, int N>
void doSth(T(&arr)[N])

缺点 - 无法传递动态数组

选项 3: 成为一名优秀的程序员并使用 std::vector's

【讨论】:

  • 所有合理的解决方案,但建议是最好的部分。
【解决方案2】:

由于您使用的是 C++,所以从长远来看,vector&lt;int&gt;iterators 会更好。

【讨论】:

    【解决方案3】:

    如果你想使用数组,而不是指针,那么你可以将函数模板写成:

    template <typename T, size_t N>
    void printArray(T (&start)[N]) 
    {
        int i = 0;
        while ( i < N) {
            std::cout << start[i] << std::endl;
            i++;
        }
    }
    
    int xs1[] = {1,2,3,4,5,6,7}; 
    int xs2[] = {1,0,3,6,7}; 
    printArray(xs1); //okay
    printArray(xs2); //okay
    
    int *start = xs1;
    printArray(start); //error - cannot pass pointer anymore!
    

    所以更好的解决方案是:std::vector&lt;T&gt;

    或者甚至更好地使用 range (pair of iterators) 这是非常惯用的,如:

    template <typename FwdIterator>
    void printArray(FwdIterator begin, FwdIterator end) 
    {
        while (begin != end) {
            std::cout << *begin << std::endl;
            begin++;
        }
    }
    
    int xs1[] = {1,2,3,4,5,6,7}; 
    int xs2[] = {1,0,3,6,7}; 
    printArray(xs1, xs1 + sizeof(xs1)/sizeof(xs1[0])); //okay
    printArray(xs2, xs2 + sizeof(xs2)/sizeof(xs2[0])); //okay
    
    int *start = xs1;
    printArray(start, start + sizeof(xs1)/sizeof(xs1[0])); //okay!
    

    printArray 现在也可以与std::vector&lt;T&gt; 一起使用:

    std::vector<int> vec; //you can use std::list as well!
    //populate vec
    
    printArray(vec.begin(), vec.end());
    

    【讨论】:

    • 两个 cmets:除非您指望将它与几种不同类型的容器一起使用,否则将其用作函数模板是没有意义的;一个正常的功能就可以了。其次,当然,不是xs1, xs1 + sizeof(xs1)/sizeof(xs1[0]),而是通常的begin(xs1), end(xs1)
    • @James Kanze:1) OP 使用了模板,所以我也制作了这个模板,假设他想让它适用于许多不同的类型。2) std::begin()std::end() 可用使用 C++0x,我没有在我的解决方案中假设。 :-)
    • 好的,然后是模板:-)。至于beginend,我(我怀疑许多其他人)没有等待标准。 10 多年来,它在大多数人的工具包中或多或少已经成为标准。
    • @James:确实如此。诸如beginend 之类的实用程序可以用更少的努力实现,即使在C++03 中也是如此。
    【解决方案4】:

    同时传递数组的地址和长度。

    【讨论】:

      【解决方案5】:

      如果您使用的是编译时数组,则可以使用模板来执行此操作:

      template <typename T, size_t N>
      static inline void print_array(const T (&a)[N])
      {
        for (size_t i = 0; i < N; ++i)
          std::cout << a[i] << std::endl;
      }
      
      int main()
      {
        int a[] = {1,2};
        print_array(a);
      }
      

      如果您只需要打印数组,还请查看pretty printer,它在内部使用了这种东西。

      【讨论】:

      • @iammilind:Armen 也以 30 秒的优势击败了我 :-)
      猜你喜欢
      • 2018-11-23
      • 2011-07-30
      • 2020-11-12
      • 1970-01-01
      • 2017-01-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多