What's the best way to do a backwards loop in C/C#/C++?

后端 未结 14 2596
终归单人心
终归单人心 2020-11-28 01:39

I need to move backwards through an array, so I have code like this:

for (int i = myArray.Length - 1; i >= 0; i--)
{
    // Do something
    myArray[i] =          


        
相关标签:
14条回答
  • 2020-11-28 01:50

    In C++ you basicially have the choice between iterating using iterators, or indices. Depending on whether you have a plain array, or a std::vector, you use different techniques.

    Using std::vector

    Using iterators

    C++ allows you to do this using std::reverse_iterator:

    for(std::vector<T>::reverse_iterator it = v.rbegin(); it != v.rend(); ++it) {
        /* std::cout << *it; ... */
    }
    

    Using indices

    The unsigned integral type returned by std::vector<T>::size is not always std::size_t. It can be greater or less. This is crucial for the loop to work.

    for(std::vector<int>::size_type i = someVector.size() - 1; 
        i != (std::vector<int>::size_type) -1; i--) {
        /* std::cout << someVector[i]; ... */
    }
    

    It works, since unsigned integral types values are defined by means of modulo their count of bits. Thus, if you are setting -N, you end up at (2 ^ BIT_SIZE) -N

    Using Arrays

    Using iterators

    We are using std::reverse_iterator to do the iterating.

    for(std::reverse_iterator<element_type*> it(a + sizeof a / sizeof *a), itb(a); 
        it != itb; 
        ++it) {
        /* std::cout << *it; .... */
    }
    

    Using indices

    We can safely use std::size_t here, as opposed to above, since sizeof always returns std::size_t by definition.

    for(std::size_t i = (sizeof a / sizeof *a) - 1; i != (std::size_t) -1; i--) {
       /* std::cout << a[i]; ... */
    }
    

    Avoiding pitfalls with sizeof applied to pointers

    Actually the above way of determining the size of an array sucks. If a is actually a pointer instead of an array (which happens quite often, and beginners will confuse it), it will silently fail. A better way is to use the following, which will fail at compile time, if given a pointer:

    template<typename T, std::size_t N> char (& array_size(T(&)[N]) )[N];
    

    It works by getting the size of the passed array first, and then declaring to return a reference to an array of type char of the same size. char is defined to have sizeof of: 1. So the returned array will have a sizeof of: N * 1, which is what we are looking for, with only compile time evaluation and zero runtime overhead.

    Instead of doing

    (sizeof a / sizeof *a)
    

    Change your code so that it now does

    (sizeof array_size(a))
    
    0 讨论(0)
  • 2020-11-28 01:50
    // this is how I always do it
    for (i = n; --i >= 0;){
       ...
    }
    
    0 讨论(0)
  • 2020-11-28 01:52

    In C#, using Visual Studio 2005 or later, type 'forr' and hit [TAB] [TAB]. This will expand to a for loop that goes backwards through a collection.

    It's so easy to get wrong (at least for me), that I thought putting this snippet in would be a good idea.

    That said, I like Array.Reverse() / Enumerable.Reverse() and then iterate forwards better - they more clearly state intent.

    0 讨论(0)
  • 2020-11-28 01:55

    In C# using Linq:

    foreach(var item in myArray.Reverse())
    {
        // do something
    }
    
    0 讨论(0)
  • 2020-11-28 01:59

    I would always prefer clear code against 'typographically pleasing' code. Thus, I would always use :

    for (int i = myArray.Length - 1; i >= 0; i--)  
    {  
        // Do something ...  
    }    
    

    You can consider it as the standard way to loop backwards.
    Just my two cents...

    0 讨论(0)
  • 2020-11-28 01:59

    That's definitely the best way for any array whose length is a signed integral type. For arrays whose lengths are an unsigned integral type (e.g. an std::vector in C++), then you need to modify the end condition slightly:

    for(size_t i = myArray.size() - 1; i != (size_t)-1; i--)
        // blah
    

    If you just said i >= 0, this is always true for an unsigned integer, so the loop will be an infinite loop.

    0 讨论(0)
提交回复
热议问题