CSC 161 Schedule Readings Labs & Projects Homework Deadlines Resources

Functions and Pointer Parameters

Finding the Perimeter and Area of a Rectangle

In the previous lab, you were asked to write two functions related to circles: one computed the circumference given the radius, and the second computed the area given the radius. Following the same approach, program perim-area-1.c computes the perimeter and area of a rectangle, given the lengths of the two sides.

  1. Copy perim-area-1.c to your account. Compile and run it, and review how the program works.
    1. Following the approach of the previous lab, draw a schematic diagram of main memory after the function calculate_perimeter has been called; and draw a second schematic diagram of main memory after the function calculate_area has been called.
    2. In C, the address operator (&) allows one to determine the location or address in main memory where a variable is located. Make the following insertions into perim-area-1.c:

      Insert into calculate_perimeter just before the return statement:

      printf("parameter side1:  location: %lu, value: %lf\n",
             (unsigned long)&side1, side1);
      printf("parameter side2:  location: %lu, value: %lf\n", 
             (unsigned long)&side2, side2);
      printf("local lengthPlusWidth:  location: %lu, lengthPlusWidth: %lf\n", 
             (unsigned long)&lengthPlusWidth, lengthPlusWidth);

      Insert into calculate_area just before the return statement:

      printf("parameter side1:  location: %lu, value: %lf\n", 
             (unsigned long)&side1, side1);
      printf("parameter side2:  location: %lu, value: %lf\n", 
             (unsigned long)&side2, side2);

      Insert into main just before the return statement:

      printf("variable length:  location: %lu, value: %lf\n",
             (unsigned long)&length, length);
      printf("variable width:   location: %lu, value: %lf\n",
             (unsigned long)&width, width);
      printf("variable perim:   location: %lu, value: %lf\n",
             (unsigned long)&perimeter, perimeter);
      printf("variable area:    location: %lu, value: %lf\n", 
             (unsigned long)&area, area);

      Note: In this code, format %lu prints a long decimal integer, but ignores any initial minus sign. (We will talk more about signed and unsigned integers later in the course, when we study the representation of different types of data within a computer.) To avoid compiler warnings about passing a double * when the printf format '%lu' expects an unsigned long, we explicitly make the cast to the appropriate type.

      Recompile and run your program. To interpret the output, suppose that the first printf statement in the calculate_perimeter function produced the output:

      parameter side1:  location: 28580, value: 5.00000

      This indicates that the parameter side1 corresponds to memory location 28580, and the value 5.0 is stored there. This part of the schematic diagram might look like:


      main


      Use the address information from the inserted print statements to annotate the schematic diagrams from Step 1a with the actual locations or addresses where each parameter and variable was stored.

Program perim-area-1.c computed perimeter and area in two functions, because each function can only return one value. To obtain more than one result from a function, we have to change the nature of the parameters. This is illustrated in perim-area-2.c

Passing Values and Addresses as Parameters

Be sure you have completed the reading on passing values and addresses as parameters before continuing with this lab!

  1. Copy perim-area-2.c, compile and run it, and check that it produces exactly the same output as perim-area.1.c

    To understand how perim-area-2.c works, several print statements have been added to yield program perim-area-2a.c. Compile and run this program.

    When the program was run on one machine, the program generated the following output:

    working with a rectangle of width 7.000000 and length 5.000000
    compute:  addresses, values, and pointer references
                 side1:  address: 640370600, value: 5.000000
                 side2:  address: 640370592, value: 7.000000
       lengthPlusWidth:  address: 640370616, value: 12.000000
       pPerimeter:       address: 640370584, value: 640370664, *perimiter: 24.000000
       pArea:            address: 640370576, value: 640370656, *area: 35.000000
    the rectangle's perimeter is 24.000000
    the rectangle's area is 35.000000
    main:  variable addresses and values
       length:      address: 640370680, value: 5.000000
       width:       address: 640370672, value: 7.000000
       perimeter:   address: 640370664, value: 24.000000
       area:        address: 640370656, value: 35.000000

    This information gives rise to the following schematic for main memory that would have been encountered immediately before the compute procedure finished.


    main

    As we shall discover later in the course, each double requires 8 units (technically called bytes) of memory, so many of the locations given are 8 numbers apart.

    1. Explain why the values stored in main memory for side1 and side2 duplicate the numbers stored in main memory for length and width, respectively.
    2. The printf statement involving pPerimeter in compute indicates
      • the address of perimeter (i.e., &pPerimeter) is 640370584; that is the variable pPerimeter is stored at location 640370584
      • the value stored for pPerimeter is 640370664; note that this is the location of the perim variable in main
      • the value referenced by the location stored in pPerimeter (i.e., the value stored in perimeter) is 24.00000.
      Write similar statements about what is printed regarding the parameter area.
  2. In the previous lab, you wrote two functions that computed the circumference and the area of a circle. Write a new version of your solution, so that the program has just one procedure compute_circle_geometry that has three parameters, the radius of a circle, the circumference, and the area. compute_circle_geometry has a void return type, but takes the radius as input and returns the circumference and area as changed parameters. (You will need to pass in the addresses of the circumference and area variables from your main procedure.)
  3. Copy the program pointers-1.c to your account.
    1. Examine the program to gain an initial understanding of what you expect it to produce.
    2. Compile and run this program. Explain each value printed.
    3. Draw a schematic memory diagram, showing variables and their values just before pointersFunctionOne finishes and returns.
  4. Copy the program pointers-2.c to your account.
    1. Examine the program to gain an initial understanding of what you expect it to produce.
    2. Compile and run the program. Explain each value printed.
    3. Draw a schematic memory diagram, showing variables and their values just before pointersFunctionTwo finishes and returns.
    4. Add the declaration int w = 100; as the first statement in the main procedure (before the declaration int x = 3;). Recompile and rerun your program. Does the output change? Explain. Does the result depend upon the value assigned to w? Why or why not?
    5. Add the declaration int z = 25; immediately after the declaration of y in main. Recompile and rerun. Again, does the output change? Why or why not?
  5. Copy the program pointers-3.c to your account.
    1. Examine the program to gain an initial understanding of what you expect it to produce.
    2. Compile and run this program. Explain each value printed.
    3. Draw a schematic memory diagram, showing variables and their values just before pointersFunctionThreeInner finishes and returns.

For those with extra time

Setting a Max

Write the function

void set_max(int n, int m, int* p_max);

that sets the variable pointed to by p_max to the larger of n and m.

Dividing the time

Write the function

void split_time(unsigned long total_seconds, unsigned int* p_hours, 
                unsigned int* p_minutes, unsigned int* p_seconds);

where total_seconds is a time represented as the number of seconds since midnight. The other paramters are pointers to variables in which the function will store the equivalent time in hours (0-23), minutes (0-59) and seconds (0-59), respectively.