Concepts / Subroutine Parameters

Subroutine Parameters

A subroutine parameter lets the same subroutine perform its task on different inputs, with the caller choosing the input on each call.

  • Programming

Why a Fixed Subroutine Needs Inputs

Suppose you have written a subroutine that prints a line of output. Every time the program calls it, the same line appears. That is useful, but limited. Most useful subroutines need to know something about the situation they are working in: which number to display, which list to process, which label to attach to a result.

A subroutine parameter is the mechanism that supplies that information. The caller hands a value to the subroutine, and the subroutine uses that value while it does its job. A parameter is a value passed to a subroutine so that one fixed procedure can handle different inputs. The procedure stays the same. The value changes from call to call.

Many programming tasks are the same from one run to the next, but the details change each time. Printing a list of numbers is a good example. The act of printing never changes, yet which numbers appear depends on the situation. Rewriting the subroutine for every variation would be wasteful, so we give it a way to receive the details it needs at the moment it is called. This article introduces that mechanism through a problem we have already met: the 3N+1 sequence.

Tracing the 3N+1 Sequence by Hand

Recall the rule that generates a 3N+1 sequence. Begin with a number N. If N is odd, replace it with three times N plus one. If N is even, replace it with N divided by two. Keep applying this step until N becomes 1. Starting from N equal to 3, the steps produce 3, 10, 5, 16, 8, 4, 2, 1.

Now take the job we want a subroutine to do: print out such a sequence. The job itself is fixed. The subroutine always follows the same rule. What changes from call to call is the number the sequence begins with. Two different starting values produce two different printed lists, even though the procedure that produces them is identical.

Work through a second starting value by applying the rule step by step. Starting from 6, which is even, the next value is 3. Three is odd, so the next value is 3 times 3 plus 1, which is 10. From there the sequence continues 5, 16, 8, 4, 2, 1. Notice that the procedure never changed: only the first value you fed into it was different.

6starting value from caller36 is even, halve it103 is odd, 3N+1510 is even, halve it165 is odd, 3N+1816 is even, halve it48 is even, halve it24 is even, halve it12 is even, halve it; stopapply ruleapply ruleapply ruleapply ruleapply ruleapply ruleapply ruleapply rule
Following the starting value 6 through the fixed rule, how does the value change at each step, and what final output does it produce?

Reading the Parameter in a Function Header

The parameter is named in the subroutine's header, and that name is used inside the body. The header below is an illustration written for this article, not a listing from the source textbook. Its header names a parameter called n, and the body applies the 3N+1 rule to whatever value that name holds when the function runs. The function prints the whole sequence as a list, so the caller only has to supply the starting value.

python
Output (expected)
[3, 10, 5, 16, 8, 4, 2, 1]
[6, 3, 10, 5, 16, 8, 4, 2, 1]
Notes on the code
  • n in the header is the parameter: the name the subroutine uses for the value it receives
  • The while loop is the fixed task: it never changes between calls
  • Each call supplies a different starting value, so the printed list differs

Caller and Subroutine Exchanging a Value

It helps to separate two roles. The caller decides which starting value to use and hands it over. The subroutine receives that value and uses it to carry out the fixed procedure. Once the subroutine finishes its job, control returns to the caller, which continues with the rest of the program. The same subroutine can serve many different purposes, because the purpose is determined by what arrives rather than by a rewritten body.

Callermain programprint_sequencefixed 3N+1 procedurecall with 3n receives 3, rule appliedreturns after printingcall with 6returns after printing
When the caller invokes the subroutine with a value, where does that value go, and when does control return to the caller?

Passing a Whole Array as One Parameter

A parameter does not have to hold a single number or a single word. Its type can be an array type. When that happens, the caller does not pass the array's elements one at a time. The entire array of values travels into the subroutine as a single parameter, and the subroutine has access to all of the values through that one parameter.

Consider a concrete need. Imagine a subroutine whose job is to display every value in an integer array in a neat format: the values separated by commas and wrapped in a pair of square brackets. The subroutine has to know which array to display. The way to tell it is to give the subroutine a parameter of type int[ ], the notation for an array of integers. The caller supplies the array when it makes the call, and the subroutine works on that array.

java
Output
[4,7,2]
Notes on the code
  • int[] values is the int[ ] parameter: one parameter standing for the whole array
  • No comma is printed before the first value; a comma is printed before each later value
  • Brackets wrap the whole list
values[0]4values[1]7values[2]2
When an array is passed as one parameter, what does the subroutine receive, and how does that relate to the array the caller holds?

The printing task has a precise formatting rule. A subroutine that prints an array neatly must handle the separators carefully: no comma before the first value, a comma before each later value, and brackets around the whole list. The loop in the example above follows exactly that rule, which is why the output has no leading comma and no trailing comma.

Mistakes When Reading Parameters

  • Common mistake

    Thinking the subroutine's body must be rewritten for each new input

    What it looks like

    Writing a separate print routine for starting value 3 and another for starting value 6

    Why it fails

    The fixed procedure is the same on every call. Only the value supplied by the caller changes.

    Do this instead

    Write the procedure once with a parameter such as n, and pass different values at each call.

  • Common mistake

    Assuming the caller's variable and the parameter name are the same thing

    What it looks like

    Calling print_sequence(start) and then expecting the body to refer to start

    Why it fails

    The subroutine receives the value under its own name, which is n in the header.

    Do this instead

    Use the parameter name from the header inside the body, and remember the caller's name is separate.

  • Common mistake

    Passing an array as separate values when the parameter is int[ ]

    What it looks like

    Expecting printArray(4, 7, 2) to work when the header declares int[] values

    Why it fails

    An int[ ] parameter receives the whole array as one item.

    Do this instead

    Create the array first, such as new int[] {4, 7, 2}, and pass that array as the single argument.

Practice: Predict the Printed Sequence

EASY

Using the print_sequence subroutine from earlier, what list does print_sequence(5) print? Apply the rule step by hand before you check.

Hints
  • 5 is odd, so the next value is 3 times 5 plus 1
  • Keep applying the rule until the value becomes 1
  • The subroutine's body is unchanged; only the starting value differs

What do you think happens?

What list does print_sequence(5) print?

Reveal answer
Answer:

[5, 16, 8, 4, 2, 1]

5 is odd, so it becomes 16. Then 16 is halved to 8, 8 to 4, 4 to 2, and 2 to 1, where the sequence stops.

Key Takeaways

  • A parameter is a value passed to a subroutine so that one fixed procedure can handle different inputs.
  • The caller chooses the input on each call, while the subroutine's task stays the same.
  • Inside the subroutine, the parameter is referred to by its own name in the header, such as n.
  • A parameter of type int[ ] receives an entire array as a single parameter rather than as separate values.
  • Each subroutine is a subtask of a larger program, and designing how to split a program into subtasks is a separate skill.