22A. Arrays and Functions


Passing arrays to functions

We have seen that an array is a pointer to a chunk of memory. Naturally, arrays are typically passed by pointer. For example, here is a function that sets the first n variables of an array of integers to 0.

  void zero(int* A, const int n)
  {
    for(int k = 0; k < n; k++)
    {
      A[k] = 0;
    }
  }

Here is an example of using zero. Assume that constant Bsize has previously been defined.

  int B[Bsize];
  zero(B, Bsize);
Notice that the argument, B, does not have any decoration. Don't add [] after it. Nothing needs to be done to convert B to a pointer; it already is a pointer. Array B is being passed, so just call it B.


Alternative notation

C++ offers an alternative notation for passing arrays to functions. Instead of writing int* A in the function heading, you can write int A[]. Heading

  void zero(int A[], const int n)
is equivalent to heading
  void zero(int* A, const int n)
The former form has the advantage that it clearly indicates that A is an array, not a pointer to just one thing. For that reason, it is typically preferred.

Note that Java notation int[] A is not allowed in C++. The brackets come after the name of the parameter.


Issues for passing arrays to functions

No implicit copying

Since an array is passed as a pointer, the array's chunk of memory is not copied. The function uses the memory of the same array that is passed to it, and can change what is in that memory.

Passing an array by reference

Because arrays are already pointers, there is usually no reason to pass an array explicitly by reference. For example, parameter A of function zero above has type int*, not int*&.

The only reason for passing an array by reference is so that you can change the pointer to point to a different array.


Constant arrays

If a function only looks at the contents of an array, and does not change what is in the array, you usually indicate that by adding const to the parameter. For example, the following function firstPositive does not change what is in array A.
  // firstPositive(A,n) returns the first of
  // A[0], ..., A[n-1] that is positive.  If
  // none of them is positive, then it returns 0.

  int firstPositive(const int* A, const int n)
  {
    for(int i = 0; i < n; i++)
    {
      if(A[i] > 0)
      {
        return A[i];
      }
    }
    return 0;
  }

logical and physical array size

Often, not all of the memory in an array is used. For example, you might have an array with 100 spots, but you are only currently using the first 10 of them. Think of the array as similar to a hotel. There are a certain number of rooms available, but on a given night, not all of the rooms are occupied. Unlike a hotel, however, the occupied part is typically at the beginning, using indices 0, …, n−1 for some value n.

For arrays that are partially full, there are two notions of the size of the array.

  1. The physical size of the array is the total number of slots that are available. For example, if array A is created by

      double A[15];
    
    then A has physical size 15.

  2. The logical size of an array is the total number of occupied slots. It must be less than or equal to the physical size.

When you think about the size of an array, be sure to distinguish these two concepts of size. Sometimes, you are interested in the physical size. Often, you are interested in the logical size. For example, to show the entire content of an array, you would show up to the logical size, since you don't want to see the unoccupied part.


Passing the array size

Recall that you cannot ask an array how big it is. Typically, you pass the size of an array along with the array. Functions zero and firstPositive, above, pass array A along with its size n.

When you do pass the size, it is important to understand whether you are passing the logical size or the physical size of the array. Most often, you find that you want to pass the logical size. Sometimes you want to pass both sizes, as separate parameters.



Example

The following program function reads a list of integers from the standard input until it sees integer 0. Then it writes them to the standard output backwards. It is a silly function, but it illustrates use of arrays.

  #include <cstdio>
  using namespace std;

  const int maxNums = 100;

  // ReadNumbers(A) reads numbers up to a 0.  It stores
  // the first value read into A[0], the second value
  // into A[1], etc.  It does not store the end marker 0
  // into array A.
  //
  // ReadNumbers returns the number of values that it read,
  // excluding the 0 at the end.

  int readNumbers(int A[])
  {
    int i;

    //----------------------------------------------
    // Read the numbers into array A, stopping at 0.
    // Refuse to put too many values into the array.
    //----------------------------------------------

    for(i = 0; i < maxNums; i++)
    {
      scanf("%i", &(A[i]));
      if(A[i] == 0) 
      {
        break;
      }
    }
    return i;
  }

  // WriteNumbers(A, howmany) writes A[howmany-1], ...,
  // A[0], in that order, each on a separate line.

  void writeNumbers(const int A[], const int howmany)
  {
    for(i = howmany - 1; i >= 0; i--)
    {
      printf("%i\n", A[i]);
    }

  }

  int main()
  {
    int howmany;
    int A[maxNums];

    howmany = readNumbers(A);
    writeNumbers(A, howmany);
    
    return 0;
  }  


Summary

Since an array is a pointer, arrays are usually passed by pointer. Passing an array by value is the same as passing it by pointer.

You usually mark an array as const if you do not intend to change its contents.

Some arrays have two sizes: a physical size, which is the number of cells that have been allocated, and a logical size, which is the number of cells that are currently being used.

When you pass an array to a function, you usually need to pass its size too. Sometimes, you pass just the logical size. Other times, you pass both the logical and physical size.


Exercises

  1. Write a definition of function sum(A, n) which takes an array if ints A and its logical size n and returns the sum of all of the integers in the array. Include a contract. Answer

  2. The following function uses a pointer to look at each cell in an array. There is something peculiar about it, other than that it uses a pointer instead of an array index. What is wrong?

      // sum(A,n) returns A[0] + A[1] + ... + A[n-1].
    
      int sum(const int* A, int n)
      {
        int  s = 0;
        int* p = new int;
        for(p = A; p < A + n; p++)
        {
          s = s + *p;
        }
        return s;
      }
    
    Answer

  3. Write a definition of procedure cpy(A, B, n) that copies B[0, ..., n−1] into A[0, ..., n−1]. Make A and B each be arrays of ints. Include a contract. Answer

  4. Write a definition of function copyPositives(A, B, n), which copies all of the positive numbers in array B into array A, where B has logical size n.

    The values put in A should be in the same order as those in B, but if there are k positive numbers in array B then they must be put into A[0,...,k−1]. copyPositives should return the number k of values stored in array A.

    Make arrays A and B be arrays of ints. Include a contract.

    Answer

  5. Write a definition of procedure reverse(A, n), which reverses the order of the values in A[0, ..., n−1]. Make A be an array of longs. For example, if n = 3 and A contains

      A[0] = 10
      A[1] = 20
      A[2] = 30
    
    before calling reverse(A,3), then A contains
      A[0] = 30
      A[1] = 20
      A[2] = 10
    
    after calling reverse(A,3). Answer

  6. You are given a collection of rectangular buildings as seen from a particular vantage point. Your goal is to construct the skyline as seen from that vantage point.

    There are 101 horizontal positions numbered 0 to 100 that can be horizontal building boundaries. Each building profile has a three features: the position of its left edge, the position of its right edge and its height.

    The goal is to write out the height of the skyline for each length 1 horizontal position. The first number gives the skyline height from position 0 to position 1, the second is for the segment from position 1 to position 2, etc. The last height is for the skyline from 99 to 100. If there is no building at a given position then the skyline height is 0. Write one number per line.

    The input is a sequence of lines of the form

    L R H
    
    where L, R and H are integers representing the left-side position, the right-side position and the height of a building. The input ends on a line that only contains 0.

    Hints.

    1. Store an array, skyline, where skyline[i] holds the height of the skyline from position i to position i+1.

    2. Write a function to install a single building given by features L, R and H into the skyline. Think this out. The skyline height at a particular place is the height of the tallest building that occupies that place.

    3. Write a function to read all f the buildings and install them into the skyline.

    4. Write a function to write out the skyline.

    Answer