for loops, is using i-- bad practice?

May 22, 2022 at 5:14am
New to C++, I have a question about for loops that I need some help with. I understand the condition of using the for loop and how it increments/decreases but I'm wondering whether using a for loop using the i-- condition is good programing practice or just sloppy?

For example the for loop I'm using is i++ which means it loops the amount of entries I have in a dynamic array/struct which means it repeats asking what entry I want to delete according to how many entries I have inputted. The only way I've been able to get it to ask only once is by using i--. Is it OK to use i-- in a for loop to make the condition only run once or is this bad practice?
May 22, 2022 at 5:28am
Decrementing instead of incrementing to make the index access consistent while erasing or moving data is fine.

Is it OK to use i-- in a for loop to make the condition only run once
Huh? If you're only running something once, why use a loop?

Anyway, the answer to your question is "it's OK". If it makes your code easier to understand, while still being correct, then I don't see a downside. If you gave more concrete examples, people could provide better feedback.
May 22, 2022 at 5:41am
it sounds like you have a logic problem or a misunderstanding.
I can't think of any reason your code needs to run backwards to prevent some sort of user prompt, but if you can show it, maybe we can give you a ++ version or something.

from what you said...
1
2
3
4
5
6
7
8
cout "what to delete?" //prompt once only!
cin >> data;
for(int i = 0; i < yourmax; i++)
{
   if(array[i].data == data) 
     //delete and break or delete multiple(?) keep going
}

it also sounds like you may want to delete just the last element (??) or last few elements (??).
in that case, if using a vector, pop back what you need covers it.

more generally, no, its not bad practice to iterate what you need in a for loop. Its what they do, even if the loop has a wonky 'increment' like *=3 or +=42 or ^=0xAAC. The 'good practice' is that when doing something other than ++ or --, explain it in a comment nearby.
Last edited on May 22, 2022 at 5:46am
May 22, 2022 at 6:48am
When using a for loop:

1
2
for(int i = 0; i < 5; i++) //Does: 0 1 2 3 4
{ ... }


However, converting this to an i-- format can come in many forms:

1
2
3
//Will loop through a different set of numbers:
for(int i = 5; i > 0; i--) //Does: 5 4 3 2 1 - STILL LOOPS 5 TIMES
{ ... }


OR:

1
2
3
//Now loops through the same set of numbers, still looping 5 times
for(int i = 4; i >= 0; i--) //Does: 4 3 2 1 0 - Notice the i >= 0 instead of i > 0
{ ... }



But no, there's nothing wrong with i++ vs i--. There are valid reasons to want to increment forward or backwards.

However, needing to use i-- to prevent your code from "repeating" something twice seems like a logical error that i-- HAPPENS to solve, and you'd benefit more from solving the real issue rather than simply decrementing.
Last edited on May 22, 2022 at 6:51am
May 22, 2022 at 7:54am
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>

using namespace std;

int main()
{
    int NUMBER_OF_ELEMENTS{5};
    
    for( int i = 0; i < NUMBER_OF_ELEMENTS; i++)
        cout << i << ' ';
    cout << '\n';
    
    for( int i = 0; i < NUMBER_OF_ELEMENTS; i++)
        cout << NUMBER_OF_ELEMENTS - 1 - i << ' ';
    cout << '\n';
    
    for( int i = NUMBER_OF_ELEMENTS; i > 0; i--)
        cout << i - 1 << ' ';
    cout << '\n';
    
    return 0;
}



0 1 2 3 4 
4 3 2 1 0 
4 3 2 1 0 
Program ended with exit code: 0
May 22, 2022 at 10:35am
If dealing with a container, then range-for can be used to iterate over the container

https://en.cppreference.com/w/cpp/language/range-for

If dealing with removing elements from a container, then an iterator can be used in a for loop. Also std::remove(_if) and std::erase(_if). Consider:

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
#include <vector>
#include <iostream>
#include <algorithm>

std::ostream& operator<<(std::ostream& os, const std::vector<int> v) {
	for (const auto& e : v)
		os << e << ' ';

	return os;
}

int main() {
	std::vector v { 1, 2, 3, 4, 5, 6, 7, 8, 9 };

	std::cout << v << '\n';

	for (auto itr { v.begin() }; itr != v.end(); )
		if (*itr % 2)
			itr = v.erase(itr);
		else
			++itr;

	std::cout << v << '\n';

	v.erase(std::remove_if(v.begin(), v.end(), [](const auto e) {return e % 4; }), v.end());
	std::cout << v << '\n';

	// Since C++20
	std::erase_if(v, [](const auto e) {return e % 8; });
	std::cout << v << '\n';
}



1 2 3 4 5 6 7 8 9
2 4 6 8
4 8
8

May 22, 2022 at 1:58pm
There are 3 ways to iterate through a regular array:
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
#include <iostream>
#include <iterator>

int main()
{
   const int SIZE { 5 };

   // a regular array
   int arr[SIZE] { 5, 10, 15, 20, 25 };

   // old school for loop
   for (size_t i { }; i < SIZE; ++i)
   {
      std::cout << arr[i] << ' ';
   }
   std::cout << '\n';

   // (const) iterators can be used on regular arrays
   for (auto itr { std::cbegin(arr) }; itr != std::cend(arr); ++itr)
   {
      std::cout << *itr << ' ';
   }
   std::cout << '\n';

   // range-based for loops work with regular arrays
   // https://en.cppreference.com/w/cpp/language/range-for
   for (const auto& itr : arr)
   {
      std::cout << itr << ' ';
   }
   std::cout << '\n';
}
5 10 15 20 25
5 10 15 20 25
5 10 15 20 25

There are three ways to reverse loop through a regular array:
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
33
#include <iostream>
#include <iterator>
#include <ranges>   // for std::views::reverse

int main()
{
   const int SIZE { 5 };

   // a regular array
   int arr[SIZE] { 5, 10, 15, 20, 25 };

   // old school reverse for loop
   for (size_t i { SIZE }; i > 0; --i)
   {
      std::cout << arr[i - 1] << ' '; // notice the indexing!
   }
   std::cout << '\n';

   // reverse for loop with const iterators
   for (auto itr { std::crbegin(arr) }; itr != std::crend(arr); ++itr)
   {
      std::cout << *itr << ' ';
   }
   std::cout << '\n';

   // https://www.fluentcpp.com/2020/02/11/reverse-for-loops-in-cpp/
   // C++20
   for (const auto& itr : arr | std::views::reverse)
   {
      std::cout << itr << ' ';
   }
   std::cout << '\n';
}
25 20 15 10 5
25 20 15 10 5
25 20 15 10 5

Using an iterator for loop or a range-based for loop on regular arrays "falls apart" when passing the array into a function, it devolves to a pointer. Using a C++ container, say a vector, doesn't suffer this problem. That is one of the reasons why C++ code should use a C++ container whenever possible.

As seeplus showed there are easier ways to manipulate a C++ container's contents using iterators or a range-based for loop, yet another reason to use C++ containers in C++ code.
Topic archived. No new replies allowed.