CSC 101 Lecture Notes Week 6
Selected Topics Relevant to Programming Assignment 3
More on Arrays and Strings


Relevant Reading: Chapters 7, 8, and 9





  1. Selected Topics You Need to Know for Program 3

    1. The typedef declaration.

      1. Typedef is used to give types a mnemonic name.

      2. It's particularly handy when the C definition of a type gets complicated, for example the two-dimensional array of strings that we're using for a deck of cards in Program 3.

      3. Here's the definition of this type from cards.h:
        typedef char Deck[DECK_SIZE][CARD_STR_LEN];
        

      4. With this definition we can use the type named Deck anywhere we want to define a variable or parameter that's a deck of cards.

      5. So, for example, we can define the prototype for the shuffle function like this
        void shuffle(
            Deck unshuffled_deck,       /* Unshuffled input deck */
            Deck shuffled_deck          /* shuffled output deck */
        );
        
        instead of the much bulkier version like this
        void shuffle(
            char unshuffled_deck[DECK_SIZE][CARD_STR_LEN], /* Unshuffled input deck */
            char shuffled_deck[DECK_SIZE][CARD_STR_LEN]    /* shuffled output deck */
        );
        

      6. Typedefs are discussed Chapter 7 of the book, in the context of enumerated types in; however, it's not at all limited to enums, as uses in cards.h illustrate.

    2. Subdividing a C program into separate .c and .h files.

      1. For assignment 3, the program is subdivided into C header and program files.

      2. These have the file extensions ".h" and ".c", respectively.

      3. This subdivision is standard practice for C programs.

      4. The header files most typically contain type definitions, and function prototypes.

      5. The .c program files implement the functions.


  2. Memory Pictures of Functions with Array Parameters

    1. The read_values function covered last week is a prime example of how array values can be passed to and from functions.

    2. Here again is the stats program in which read_values appears.
      
      /****
       *
       * This program computes simple statistics for up to 1000 real numbers read
       * from standard input.  The numbers are read up to EOF or 1000 input values,
       * which ever occurs first.  The statistics computed are the sum of the
       * numbers, the arithmetic mean, and the standard deviation.  The results are
       * output to standard output, in the following form:
       *
       * Sum =
       * Mean =
       * Standard Deviation =
       *
       * The precise formulae for mean and standard deviation are as defined here:
       *
       *    http://www.gcseguide.co.uk/statistics_and_probability.htm
       *
       *
       * Author: Gene Fisher (gfisher@calpoly.edu)
       * Created: 31mar11
       * Last Modified: 3apr11
       *
       */
      
      #include <stdio.h>
      #include <math.h>
      
      #define MAX_DATA_POINTS 1000
      
      /*
       * Declare the prototypes for functions used in the program.
       */
      int read_values(double data[], int max);
      double compute_sum(double data[], int n);
      double compute_mean(double data[], int n);
      double compute_std_dev(double data[], int n);
      
      int main () {
      
          /*
           * Declare an array to hold the numbers, and an int for the number of
           * values read in.  Decclare a double to check if stdin is emmpty.
           */
          double data[MAX_DATA_POINTS];
          int n;
          double datum;
      
          /*
           * Prompt the user for the data values.  From the terminal, the user
           * generates an EOF by typing control-D.  If input is redirected from a
           * file, EOF is produced after the last value is read from the file.
           */
          printf(
              "Enter up to %d numeric values, terminating input with control-D:\n",
                  MAX_DATA_POINTS);
      
          /*
           * Call the read_values function to read the numbers into the data array,
           * and return the number of values read.
           */
      
          n = read_values(data, MAX_DATA_POINTS);
      
          /*
           * Determine if there are any remaining data values on stdin, and tell the
           * user that they will be ignored.
           */
      
          if (scanf("%lf", &datum) != EOF) {
      
              printf("\n  NOTE: The program will use the first 1000 numbers only.\n\n");
          }
      
          /*
           * Compute and output the results.
           */
          printf("Sum = %f\n", compute_sum(data, n));
          printf("Mean = %f\n", compute_mean(data, n));
          printf("Standard Deviation = %f\n\n", compute_std_dev(data, n));
      
          return 0;
      
      }
      
      /*
       * Read up to max values from standard input, and put the values in the given
       * data array.  Return the number of values read, up to EOF or the given max,
       * whichever occurs first.  It is the caller's responsibility to ensure that
       * the given data array has at least max elements.
       */
      
      int read_values(double data[], int max) {
      
          int i;
          for (i = 0; i < max && scanf("%lf", &data[i]) != EOF; i++)
              ;
      
          return i;
      
      }
      
      /*
       * Return the sum of the first n values of the given data array.
       */
      
      double compute_sum(double data[], int n) {
      
          int i;
          double sum;
          for (i = 0, sum = 0; i < n; i++) {
              sum += data[i];
          }
          return sum;
      }
      
      /*
       * Return the arithmetic mean of the first n values of the given data array.
       */
      double compute_mean(double data[], int n) {
          return compute_sum(data, n) / n;
      }
      
      /*
       * Return the standard deviation of the first n values of the given data array.
       */
      double compute_std_dev(double data[], int n) {
          int i;
          double mean = compute_mean(data, n);
          double sum_squares = 0;
      
          for (i = 0; i < n; i++) {
              sum_squares += pow(data[i] - mean, 2);
          }
      
          return sqrt(sum_squares / (n - 1 ));
      }
      
      

    3. This program illustrates how array parameters can be used as both inputs and outputs to a function.

      1. The read_values function uses its array parameter for output.

      2. The three compute_ functions use the array parameter for input.

      3. In other programs of upcoming lectures, we'll see array parameters used for both input and output.

    4. The reason array parameters work as outputs is because any array variable or parameter is actually a pointer to array memory.

      1. Figure 1 is a picture of program memory after the following steps of execution have been completed:

        1. the user has entered the values 1,2,3,4,5 on stdin, followed by EOF

        2. main has called read_values, on line 60 of the program

        3. read_values has completed its loop, and is about to execute the return statement on line 91



        Figure 1: Array parameter to read_values function.



      2. The picture shows that the main function and the read_values function share the same piece of array storage, since the value of the array variable and parameter point to the same storage.

      3. Note that at this point of execution, the values of the main variables n and datum have not yet be set, so they're shown blank in the picture.

        1. The variable n will be set after the read_values return statement is executed, and line 60 of the program has completed execution.

        2. The value of datum will be set on line 66 , after the scanf function reads its value from stdin.

  3. The Precise Steps of a Function Call

    1. We have seen a variety of different kinds of functions so far in 101.

    2. All functions follow the same steps when they're called.

    3. The steps are:

      1. evaluate the actual parameters

      2. assign actual parameter values to the formal parameters

      3. run the function body

      4. return from the function

  4. Focus Specifically on Reading Values into an Array.

    1. In the Week 5 notes, the last stats program example showed the finished result of a program that uses arrays properly.

    2. A key aspect of the array-based stats example is reading data into an array.

    3. We'll now spend some time focusing on this specific aspect of array processing.

    4. To start with, here's an example that reads values from stdin into an array; it's in the online examples in the program named store.c
      /*
       * Read positive numbers from stdin, store them in an array.  Print out the
       * array when done.  !No bounds checking!
       */
      #include <stdio.h>
      
      int main() {
      
          int i = 0;                  /* Array index for input. */
          int j = 0;                  /* Array index for output. */
          double x;                   /* Input value */
          double a[5];                /* Array to hold numbers */
      
          /*
           * Prompt and read first number.
           */
          printf("Input positive numbers, negative to stop: ");
          scanf("%lf", &x);
      
           /*
            * Loop until negative number input.
            */
          while (x > 0) {
      
              /*
               * Store input in next array element.
               */
              a[i] = x;
      
              /*
               * Increment array index.
               */
              i = i + 1;
      
              /*
               * Read in next number.
               */
              scanf("%lf", &x);
      
          }
      
          /*
           * Print out the array.
           */
          while (j < i) {
              printf("a[%d] = %f\n", j, a[j]);
              j++;
          }
      
          return 0;
      }
      


  5. Bounds Checking Arrays

    1. The program comment in store.c noted that it does !No bounds checking!.

    2. This means that the program does not check that the array is big enough to hold the number of values being read from stdin.

    3. Fundamentally bad things happen when a program tries to access or store values past the declared end of an array.

    4. Suppose for example that a user gave 6 input values to the store program, by running it like this:
      store
      Input positive numbers, negative to stop: 1 2 3 4 5 6 -1
      

    5. Here's a picture of the memory for the array a after this run

    6. The problem is that array a was declared to hold 5 elements, but the program has tried to store something in the non-existent sixth element, at location a[5], which is shown with dashed lines to indicate that it is out of the declared bounds of the array.

      1. Attempting to store a value beyond declared array bounds leads to undefined program behavior.

      2. Sometimes the program can get lucky, and it'll run just fine. This happens when a[5] is not occupied by some other used data value of the program.

      3. Other times, the program gets unlucky, and does not work properly. This happens when a[5] is in use by some part of the program, or worse yet, completely out of bounds for the program.

      4. In some cases, "not work properly" means that the program does not have a fatal error, but does not behave as expected. E.g., some garbage value ends up being stored in a[5].

      5. In the worst case, the program will have a fatal error, that will be indicated by one of the following messages:
        Segmentation violation
        Bus error
        Illegal instruction
        

      6. The exact meaning of these messages is unimportant at the moment.

      7. What these messages indicate is that a C program performed a fundamentally improper action.

      8. One of the most common causes of C program bugs is to write past the declared bounds of an array.

    7. For this reason, C programs should always be written to check that the bounds of an array are not exceeded.

    8. An example of how this is done for the simple store.c program is shown in the updated version of the program named store-chk.c.

    9. Here's its code.

      1. Changes are shown in red.

      2. Note that it doesn't take a lot of code to do the bounds checking; it's simply a matter of making sure that we don't allow the array index to assume a value past the end of the array.
      /*
       * Read positive numbers from stdin, store them in an array.  Print out the
       * array when done.  !With bounds checking!
       */
      #include <stdio.h>
      
      int main() {
      
          int i = 0;                  /* Array index for input. */
          int j = 0;                  /* Array index for output. */
          double x;                   /* Input value */
          double a[5];                /* Array to hold numbers */
      
          /*
           * Prompt and read first number.
           */
          printf("Input positive numbers, negative to stop: ");
          scanf("%lf", &x);
      
           /*
            * Loop until negative number input, or we run out of room in the array,
            * which ever occurs first.
            */
          while (x > 0 && i < 5) {
      
              /*
               * Store input in next array element.
               */
              a[i] = x;
      
              /*
               * Increment array index.
               */
              i = i + 1;
      
              /*
               * Read in next number.
               */
              scanf("%lf", &x);
      
          }
      
          /*
           * Print out the array.
           */
          while (j < i) {
              printf("a[%d] = %f\n", j, a[j]);
              j++;
          }
      
          return 0;
      }
      


  6. Some Other Array Examples.

    1. The 101 examples page has some additional examples of array use.

    2. Goto 101/examples/week5 and 101/examples/week6 to check them out.




index | lectures | handouts | programs | labs | examples | solutions | grades