for loops, is using i-- bad practice?

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?
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.
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
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
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
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

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.