.. _Functions:

.. raw:: html

   <script>ODSA.SETTINGS.DISP_MOD_COMP = true;ODSA.SETTINGS.MODULE_NAME = "Functions";ODSA.SETTINGS.MODULE_LONG_NAME = "Functions and Scope";ODSA.SETTINGS.MODULE_CHAPTER = "Appendix A"; ODSA.SETTINGS.BUILD_DATE = "2021-06-14 17:15:26"; ODSA.SETTINGS.BUILD_CMAP = false;JSAV_OPTIONS['lang']='en';JSAV_EXERCISE_OPTIONS['code']='java';</script>


.. |--| unicode:: U+2013   .. en dash
.. |---| unicode:: U+2014  .. em dash, trimming surrounding whitespace
   :trim:


.. This file is part of the OpenCSF eTextbook project. It was
.. auto-generated by scripts from the OpenDSA eTextbook project.
.. See https://OpenCSF.org for more details. OpenCSF is distributed
.. under a Creative Commons Attribution-NonCommercial 4.0 International
.. License (see http://creativecommons.org/licenses/by-nc/4.0/),
.. Copyright (c) 2019-2021 by Michael S. Kirkpatrick. OpenDSA is
.. distributed under an MIT open source license, Copyright (c) 2012-2021
.. by the OpenDSA Project Contributors.

.. avmetadata::
   :author: Michael S. Kirkpatrick
   :requires:
   :satisfies:
   :topic:

Functions and Scope
===================

As with every modern programming language, C uses functions to create modularity as a step toward
robust software. Encapsulating portions of a program's code this way allows the programmer to
isolate the functions for the purposes of testing and debugging. One key aspect of writing functions
is to get the *scope* of variables correct. `Code Listing A.22 <#cla-22>`_ illustrates the
three main scopes for variables in C programs: *global*, *local*, and *static*.
The split of global and local is fairly straightforward: if the variable declaration occurs inside
the body of a function (see line 13), it is local to that function and unavailable to others; if the
declaration is outside any function definition (see line 7), the variable is global and accessible
by all functions for reading or modification.

.. _cla-22:

.. codeinclude:: CLang/CodeListing-A-22.c
   :linenos: true

In addition to their differences in visibility, local and global variables differ in another key
way: initialization. Global variables are always initialized, whether the code does so explicitly or
not. Consider changing line 7 from `Code Listing A.22 <#cla-22>`_ as shown here:

.. codeinclude:: CLang/Global.c

The variable ``global`` is still declared as an ``int`` variable. It is also initialized to the
value 0. One subtle difference is that the variable now exists in a different memory section than
before. Recall that we can collectively refer to the *data segment* as the portion of memory
storing global variables. This segment is subdivided into smaller sections, including ``.data``
(initialized global variables), ``.bss`` (*block started by symbol* for uninitialized global
variables), and ``.rodata`` (initialized read-only data, such as string constants). In the original
form of `Code Listing A.22 <#cla-22>`_, ``global`` was allocated space in ``.data``, and the
executable file would contain its initial value (1). In this modified version, ``global`` would be
allocated to ``.bss``. In the executable file, the ``.bss`` stores nothing, because it doesn't need
to; everything allocated to ``.bss`` has the same initial value of 0. As such, the executable only
needs to contain information about what variables map to ``.bss`` to know the total size that needs
to be allocated in memory when the process starts. All global variables are mapped into one of these
three sections, ensuring that they all start with some initial value.

.. _RSPLocation:

.. figure:: Images/CSF-Images.A.4.png
   :align: right
   :width: 90%
   :figwidth: 45%
   :alt: Location of %rsp before and after allocating the stack frame for helper()

   Location of %rsp before and after allocating the stack frame for helper()

Local variables are different. **Local variables are never initialized unless done so explicitly**.
Unlike global variables, in which there is a single instance that can be stored persistently in the
executable file, local variables are only created at run-time when a function is called. This
allocation happens in a single step: adjusting the stack pointer register (``%rsp`` in x86).
:num:`Figure<Figure #RSPLocation>` illustrates the portion of the stack before ``main()`` calls
``helper()`` and after doing so.

All global variables have their initial values loaded automatically when the program is first loaded
into memory. Local variables are automatically allocated space in the stack frame when the function
defining their scope is called. However, initializing the variable requires extra instructions, and
these are only performed if the program specifically requests it. That is, if you do not explicitly
initialize your local variables (as line 13 of `Code Listing A.22 <#cla-22>`_ does), then the
initial value of the local variable happens to be whatever was already in that memory location. Note
that, in general, other functions are likely to have been called before the function you are
currently writing; i.e., ``main()`` (or related start-up functions) likely called other functions
before ``helper()`` gets called the first time. Consequently, the initial value of ``local`` would
be whatever data was left over from those previous function calls.

.. topic:: Bug Warning

   .. figure:: Images/CSF-Images-BugWarning.png
      :align: left
      :width: 90%
      :alt: Decorative bug warning

   At the risk of overkill on this particular point, it is critical to develop the habit of always
   initializing local variables. When this is not done, the program can behave truly randomly. It may
   work fine nine times in a row before having a segmentation fault on the tenth run; when the program
   is then re-run to debug the segmentation fault, it goes back to working perfectly. It is incredibly
   common that such random behavior can be traced back to an uninitialized local variable. 

   This failure to initialize local variables often arises when working with non-primitive data types,
   such as arrays or structs. In this case, the simplest approach is to use ``memset()``. The first
   parameter is a pointer to a buffer to initialize, the second parameter is what value to write into
   each byte and the third parameter is the length of the buffer.

   .. codeinclude:: CLang/Memset.c

.. topic:: C library functions – <ctype.h>

   .. figure:: Images/CSF-Images-Library.png
      :align: left
      :width: 100%
      :alt: Decorative C library image

   ``void * memset(void *b, int c, size_t len);``
     Sets len consecutive bytes to the value c, starting at location b.
   
To return to the general discussion of scope, the third type of variable scope centers around the
``static`` keyword. Variables that are declared as ``static`` occupy a sort of middle ground between
global and local. Static scope indicates that the variable is **lexically bound but persistent**.
The phrase *lexically bound* means that the variable name can only be referenced by the code block
that contains the declaration; code blocks in C are defined by files, loop constructs (e.g., ``for``
or ``while`` loops) curly braces (``{ ... }``). In `Code Listing A.22 <#cla-22>`_, line 14 declares
``local_static`` so that it can only be accessed from within the helper() function; no other
function can have direct access to this variable. Line 23 declares hidden so that it is only
accessible within the block of code in lines 22 – 25; once that block is finished, as the comment on
line 26 indicates, the hidden variable can no longer be accessed, even within the ``helper()``
function. The ``global_static`` variable, declared on line 8, is visible throughout all of the
functions in this particular file. However, if this file is compiled and linked along with a
different piece of C code, that other code would not be able to access ``global_static``.

In addition to being lexically bound, static variables are persistent. Unlike normal local variables
that are created and destroyed with every call of a function, there is only one copy of each static
variable, and that copy persists for the duration of the process execution. In that way, static
variables are akin to global variables. `Code Listing A.23 <#cla-23>`_ demonstrates this fact by
calling ``helper()`` twice. Each time that ``helper()`` is called, the ``local`` variable is
initialized to 5 and incremented twice. In contrast, ``local_static`` is initialized once to the
value 10. With the first call of ``helper()``, line 20 of `Code Listing A.22 <#cla-22>`_ prints this
initial value and increments it to 11. This value is then used when ``helper()`` is called again. In
other words, the initialization on line 14 of `Code Listing A.22 <#cla-22>`_ is very deceiving; it
only executes once, rather than every time the function is called. Similarly, the static variable
hidden is also initialized once to 20 and incremented during the first call to ``helper()``; the
second call to the function begins with the modified value 21.

.. _cla-23:

.. codeinclude:: CLang/CodeListing-A-23.c
   :linenos: true

Lines 9 and 10 of `Code Listing A.23 <#cla-23>`_ illustrate behavior that is normally specified in a
header file. For instance, if `Code Listing A.22 <#cla-22>`_ was stored in a file called
``"scope.c"``, these two lines would likely be in a file called ``"scope.h"`` that would look like
`Code Listing A.24 <#cla-24>`_. The first line is a *function prototype* for helper(), which
serves the purpose of declaring the parameter types and return type for the function. The compiler
uses this information to know that any calls to the function are correctly formatted. The ``extern``
keyword is used for a global variable to indicate that this variable is defined *somewhere*. When
`Code Listing A.23 <#cla-23>`_ is compiled (before it is linked), the compiler only needs to know
that ``global`` is an ``int`` variable to know that lines 15 and 22 are valid. The linking process
will later tie these lines of code to the correct variable.

.. _cla-24:

.. codeinclude:: CLang/CodeListing-A-24.c
   :linenos: true

.. topic:: Bug Warning

   .. figure:: Images/CSF-Images-BugWarning.png
      :align: left
      :width: 90%
      :alt: Decorative bug warning

   Global variables should never appear in a header file without the ``extern`` keyword. Without this
   keyword, the C compiler will think that the programmer's intention is to create an instance of this
   global variable in the compiled object. As such, if the header file is included in multiple C
   source code files, the compiler will create such a global variable inside each of them. During the
   compilation stage, this is not a problem; the problem arises later during the linking stage.
   Specifically, C strictly indicates that there can be only one instance of a variable name in a
   given scope. (Note that the type doesn't matter; ``int x`` and ``char x`` would not be allowed in
   the same scope.) When the linker would try to combine the compiled objects into a single
   executable, it would report an error due to multiple global variables with the same name.

Function Parameters and Return Values
-------------------------------------

C functions can be defined to take any number of parameters and return a single value. This
definition follows from the mathematical definition of a function. For example, consider the
following mathematical function definition:

.. raw:: html

   <center>
   <span class="math inline" style="font-size: 1.5em">$f(x) = x^2$</span>
   </center>

The function f(x) takes one input parameter (x) and maps it to a single value by squaring it. C
functions operate on the same principle, as shown in `Code Listing A.25 <#cla-25>`_. In this
example, the ``add()`` function takes two input parameters, adds them together, and returns the
result; that is, ``add()`` would map two input values to a particular output in the traditional
mathematical sense. Observe that function parameters operate like local variables; the variables
``x`` and ``y`` can be accessed from within the function body and their values are not persistent
from one call to the next.

.. _cla-25:

.. codeinclude:: CLang/CodeListing-A-25.c
   :linenos: true

This traditional notion of a function does not completely match with the common use of C functions
as *subroutines*. The semantic difference is that a subroutine is simply a
modular piece of code to encapsulate some behavior; subroutines are not bound by the idea of mapping
inputs to a single return value. One common example of this is using a ``void`` return type, which
indicates that there is no mapped result. In mathematical terms, it would be nonsensical to talk
about a function f(x) that does not map any input value x to a specific output; such an f(x) would
not be a function [#f57]_ in the conventional sense. In C subroutines, it happens all the time.
Consider a function that takes two inputs and passes them to ``printf()`` along with a format
string; this function would have no need for a return type.

When working with subroutines rather than mathematical functions, there are several types of
behavior that C supports to create flexible programming styles. One such behavior is the ability to
specify a variable number of parameters. Perhaps the most common example of this behavior is the
``printf()`` function. The first parameter is a string constant to represent how the output is to be
formatted; the number of additional parameters depends on the number of format specifiers (such as
``%d`` or ``%s``). The function prototype for ``printf()`` is written as follows:

.. codeinclude:: CLang/Printf.c

The ellipsis (``...``) here is not this book's notation to indicate "more stuff here." Rather, the ellipsis is part of the C syntax to indicate that there are additional variables of unknown types. In the case of ``printf()``, only the first argument's type (``const char *``) is explicitly declared. `Code Listing A.26 <#cla-26>`_ demonstrates how to define a function with a variable-length parameter list. The first key feature is that the ``stdarg.h`` header file must be included (line 6). This header file defines a number of preprocessor macros—which look like functions—to process the arguments.

.. _cla-26:

.. codeinclude:: CLang/CodeListing-A-26.c
   :linenos: true

In `Code Listing A.26 <#cla-26>`_, the sum() function takes a ``size_t`` variable to indicate the number of integer values to add together. To begin processing these inputs, lines 13 and 14 declare and instantiate a variable-length argument list (type ``va_list``) of the specified length. From there, each argument can be accessed from the list exactly once, using the ``va_arg()`` macro (line 21). The second argument to this function indicates the type of the variable; in this case, each argument in the list will be converted to an ``int``. `Code Listing A.27 <#cla-27>`_ demonstrates how to use the ``sum()`` function. In both calls, the first argument is required to indicate the number of arguments that should be added together; line 5 only passes the value 42, whereas line 7 will calculate the sum 2 + 4 + 6 + 8.

.. _cla-27:

.. codeinclude:: CLang/CodeListing-A-27.c
   :linenos: true

.. topic:: Bug Warning

   .. figure:: Images/CSF-Images-BugWarning.png
      :align: left
      :width: 90%
      :alt: Decorative bug warning

   It is common to return pointers for a variety of reasons. For instance, a function might dynamically
   allocate some space (see the section on Pointers and Dynamic Allocation) to use as a buffer or make
   a copy of a string. However, it is critical that a **function should never return a pointer to a
   local variable**. This rule includes returning local copies of strings, as shown in the following
   example:

   .. codeinclude:: CLang/LocalReturn.c
      :linenos: true

   The problem with returning pointers to local variables is that the data associated with the variable
   exists in a stack frame that is linked to the function call; once the function returns, the stack
   frame is de-allocated, making any future access to this part of memory invalid. Unfortunately, such
   code occasionally works without crashing because the stack frame has not been overwritten yet; this
   makes debugging the code very difficult, because the crashes seem random.

Call-by-Reference Parameters
----------------------------

The limitation of returning only a single value can be frustrating, as a complex subroutine may need
to provide the caller with multiple pieces of data. One example of this need is a function that is
supposed to return a pointer. A common convention for such functions is to return the ``NULL``
pointer if an error occurs in the function. However, this approach does not explain what the error
was or how the caller should react; if the function took a file descriptor in as input, was the
problem that the file was closed, the user running the program did not have access to the file, or
the file had no contents? Clearly, it would be desirable to provide such information.

One approach to providing multiple returns is simply to cheat: use global variables. This is the
approach that is commonly used for error indications as in the previous example. If the function
returns ``NULL`` because of an error, it can also set the ``errno`` global variable to indicate the
reason why the failure occurred. With few clearly defined exceptions (such as ``errno``), **this
approach is undesirable and generally unsafe**. Global variables require the programmer to be
careful to avoid name collisions. Furthermore, the very nature of global variables allows any
function to change them at any point (assuming the variable name is made visible with ``extern``).
This global accessibility is particularly fraught in concurrent systems, as multiple threads might
simultaneously need to call the same function, potentially creating a race condition with
interleaved modifications of the variable.

A better approach is to use *call-by-reference* parameters. Consider performing traditional
integer division as taught in the early grades of school. Calculating 17 ÷ 5 has two parts to the
answer: a quotient of 3 and a remainder of 2 (since 5 * 3 + 2 = 17). `Code Listing A.28 <#cla-28>`_
demonstrates how to define a division function using a call-by-reference parameter.

.. _cla-28:

.. codeinclude:: CLang/CodeListing-A-28.c
   :linenos: true

.. _StackFrames:

.. figure:: Images/CSF-Images.A.5.png
   :align: right
   :width: 90%
   :figwidth: 30%
   :alt: Stack frames for main() and divide()

   Stack frames for ``main()`` and ``divide()``

In this function, the ``remainder`` parameter is a pointer to an ``int``. The ``assert()`` call on
line 10 is a safety check that will prevent anyone from passing a ``NULL`` pointer to this function.
Within the ``divide()`` function, we will use this pointer to change the original ``int``'s value.
Line 11 performs this by dereferencing the pointer and storing the result of the modulus operation
``dividend % divisor``. Once we have done this, line 12 returns the normal C integer division
quotient (``dividend / divisor``). `Code Listing A.29 <#cla-29>`_ demonstrates how to call this
function by passing the address of ``remainder``. (Recall that pointers store addresses, so the
address of a variable becomes a pointer.) :num:`Figure <Figure #StackFrames>` illustrates the
relationship between the stack frames for ``main()`` (`Code Listing A.29 <#cla-29>`_) and the call to
``divide()``. The remainder parameter for ``divide()`` contains a pointer back to the ``rem`` variable
in ``main()``'s stack frame.

|
|
|

.. _cla-29:

.. codeinclude:: CLang/CodeListing-A-29.c
   :linenos: true

.. topic:: Bug Warning

   .. figure:: Images/CSF-Images-BugWarning.png
      :align: left
      :width: 90%
      :alt: Decorative bug warning

   A very common mistake among programmers who are new to C's call-by-reference parameters is to try to
   match the variable declaration instead of using the address-of operator (``&``) as illustrated here:

   .. codeinclude:: CLang/UninitPtr.c

   This code would probably work successfully, but **it is wrong and very dangerous**. Yes, the types
   are correct. The ``remainder`` variable is an ``int*``, which matches the type that the
   ``divide()`` function expects. The problem lies in the answer to this question: What is the initial
   value of ``remainder``? In other words, what portion of memory is ``remainder`` *pointing to*?

   In C, local variables are never initialized unless the programmer explicitly does so. The example
   code above declares a pointer, but does not initialize it. When this happens, the value of the
   variable (``remainder`` in this case) is whatever random values happen to already be there on the
   stack. In other words, **this code tells the machine to initialize** ``remainder`` **so that it
   points to a random location**. In the context of a large, complex program, this code will produce a
   segmentation fault *if we are lucky*! The segmentation fault would be an indication that there is a
   problem. If we are unlucky, ``remainder`` (by random chance) points to a valid location; the
   problem is that the ``divide()`` function will overwrite the contents of that random location.
   Depending on that that memory location is supposed to be storing, this bug could cause a completely
   unrelated part of the program to crash seconds, minutes, or hours later, with no indication that
   this call to ``divide()`` is the cause.

   The difference between this code and `Code Listing A.29 <#cla-29>`_ is that the address-of operator
   requires us to know what we are initializing the pointer to. That is, it requires us to answer
   "address of *what*?" By passing ``&remainder`` for an ``int`` variable, rather than declaring and
   passing an ``int*``, we are providing the answer: the address of the local variable ``remainder``
   that was just declared.
   
Arrays as Parameters
--------------------

In the earlier discussion on arrays, we made the observation that array lengths must be passed as
explicit parameters when an array is passed to another function. The reason for this is that arrays
are always passed as call-by-reference parameters. `Code Listing A.30 <#cla-30>`_ provides an
example of a function that takes an array as a parameter and modifies the values stored in the
array. On line 6, the parameter list indicates that values is an array of int values. This
declaration is not entirely true; values is, in fact, just a pointer to an ``int``. Using the
declaration ``int values[]`` instead of ``int *values`` serves the purpose of indicating how values
will be used, but both declarations are acceptable.

.. _cla-30:

.. codeinclude:: CLang/CodeListing-A-30.c
   :linenos: true

.. _StackFramesDub:

.. figure:: Images/CSF-Images.A.6.png
   :align: right
   :width: 90%
   :figwidth: 30%
   :alt: Stack frames for main() and dub_all()

   Stack frames for ``main()`` and ``dub_all()``

:num:`Figure <Figure #StackFramesDub>` illustrates the relationship between ``main()`` and the first
call to ``dub_all()`` (for simplicity, the variable ``faker`` is not shown). Although ``data`` is
ostensibly passed to the ``dub_all()`` function, it is actually just the address of the first
element that is passed. This structure is consistent with an observation that we made earlier: array
names are simply aliases for the address of their first element.

To emphasize the point even further, observe that line 21 makes another call to ``dub_all()``. In
this call, we are passing the address of the local variable ``faker`` as an *array* of size 1. Since
array names and pointers can both be indexed using the array bracket notation, ``dub_all()`` can
still successfully access the faker variable and change its value. From the perspective of
``dub_all()``, there is no way to tell if the ``values`` parameter is pointing to a single ``int``
or something that was actually declared as an array. For this reason, the length of the array must
also be passed as a parameter to ``dub_all()`` to control the number of iterations in that
function's ``for``-loop on line 8.

.. [#f57] Pedantically, such an f(x) would fit the definition of a mathematical function with an
   empty codomain. Such a function would not be conventional, however.

