11E.4. Only One Loop per Function

Each function body must contain no more than one loop. This requirement forces you to break your program into shorter functions, which is consistent with the goals of this course.


Nested loops

We say that loops are nested when one loop is inside another. Here is an example of a function that contains nested loops.

  void nestdemo()
  {
    printf("  i  j\n");
    int i = 1;
    while(i <= 4)
    {
      int j = 1;
      while(j <= 4)
      {
         printf("%3i%3i\n", i, j);
         j++;
      }
      i++;
    }
  }

Calling nestdemo() prints

  i  j
  1  1
  1  2
  1  3
  1  4
  2  1
  2  2
  2  3
  2  4
  3  1
  3  2
  3  3
  3  4
  4  1
  4  2
  4  3
  4  4

Since the standards require each function to have only one loop, you will not write nested loops for this course.


What if you need nested loops?

How can you avoid nested loops? Pull the inner loop out into a separate function.

  void dorow(const int i)
  {
    int j = 1;
    while(j <= 4)
    {
       printf("%3i%3i\n", i, j);
       j++;
    }
  }

  void nestdemo()
  {
    int i = 1;
    while(i <= 4)
    {
      dorow(i);
      i++;
    }
  }  

Nested loop emulation

Upon seeing that the standards disallow directly nested loops, some students try using nested loop emulation, which uses one loop to emulate two nested loops. Typically, there are two control variables (say, i and j) that are managed in the loop body so that the values of i and j change in a way that is like the nestdemo example above. Here is conversion of the above nested loops into a single emulating loop.

  int i = 1;
  int j = 1;
  while(i <= 4)
  {
    printf("%3i%3i\n", i, j);
    j++;
    if(j == 5)
    {
      j = 1;
      i++;
    }
  }

Notice that, when j = 5, the loop body moves to the next value of i and restarts the loop on j. That is not an improvement. It is much more difficult to understand than the original two nested loops, and it is not an acceptable thing to do. The standards disallow nested loop emulation like that.

To deal with nested loops, pull the inner loop out into a separate function, as shown above.


Exercises

  1. What is nested-loop emulation, and why shouldn't you use it? Answer

  2. Rewrite the following by pulling the inner loop out into a separate function.

      // countOrderedPairs(n) returns a count of the number of
      // ordered pairs (i,j) where 1 <= i,j <= n and j < i.
      // For example, the ordered pairs containing integers from
      // 1 to 3 are: (1,1), (1,2), (1,3), (2,1), (2,2), (2,3),
      // (3,1), (3,2), (3,3).  In 3 of those ordered pairs, the first
      // number is larger than the second number.  So countOrderedPairs(3)
      // returns 3.
    
      int countOrderedPairs(const int n)
      {
        int i, j, count = 0;
    
        i = 1;
        while(i <= n)
        {
          j = 1;
          while(j <= n)
          {
            if(j < i)
            {
              count++;
            }
            j++;
          }
          i++;
        }
        return count;
      }
    

    Hint. The function that performs the inner loop will need to know the value of i as well as the value of n. It can return the number of ordered pairs of the form (i, j) where j < i > and 1 ≤ jn.

    Note. For this problem, it is easy to avoid the inner loop altogether since, for a given i, the number of ordered pairs (i, j) where i > j and 1 ≤ jn is just i − 1. But, since this is an exercise in pulling an inner loop out, don't make that improvement. Keep the algorithm the same.

    Answer