CISC105: Reading Notes
Tan and D'Orazio, Chapter 4

by Phill Conrad, Asst. Professor,
CIS Dept, University of Delaware

See reading notes for Chapter 1 for discussion of the purpose of these reading notes.

What to emphasize in Chapter 4

Chapter 4 contains eleven lessons (L4.1 through L4.11) covering if/else, relational expressions, logical expressions and operators, the switch statement, while loops, and for loops.

There are also eight Application Programs (AP4.1 through AP4.8) demonstrating these features in the context of complete working programs that solve real mathematics or engineering problems.

We will cover all of the material in Chapter 4.

Chapter 4, Tan and D'Orazio (1999)

Lesson 4.1: If Control Structure and Relation Expressions (p. 169)

A few things you need to pay special attention to in this section:

A couple of additional points:

  1. Your book indicates that if you forget the difference between = and == that "you will cause serious errors in your programs". This is true, but a bit more explanation may be helpful here.

    For example, consider the following code:
    if (x = 0)
         printf("x is zero\n")
    else
         printf("a / x = %lf", a/x);  
        
  2. What will be the result of this code exactly? First, it is important to understand that there is no compiler error. The result of doing an if test on the expression (x = 0) is the following:

    1. x is assigned the value 0
    2. the value 0 is returned as the result of the expression
    3. Whenever the value 0 when in a place the C language expects a true/false value to appear, zero is interpreted as false
    4. The else part of the statement is executed. Therefore, the program tries to divide a by x, and since x has been assigned zero (regardless of its previous value!) we try to divide by zero, and the program will terminate with a fatal error (we sometimes say "the program will crash".)

    Clearly, the intent of the programmer was to prevent division by zero, but instead, he/she has ensured that division by zero is the only possible result!

  3. As another example, consider the the following:
    if (x = 2)
         printf("x is two; the expression cannot be evaluated\n")
    else
         printf("a / (2 - x) = %lf", a/(2 - x));  
    
    what will be the result exactly in this case? Again, there is no compiler error. if test on the expression (x = 2) is the following:
    1. x is assigned the value 2
    2. the value 2 is returned as the result of the expression
    3. Whenever a non-zero value (any non-zero value, not only the value 1) appears in a place where the C language expects a true/false value to appear, the non-zero value is interpreted as "true".
    4. The "if" part of the statement is executed. Therefore, the program always prints the message "x is two; the expression cannot be evaluated", regardless of the previous value of x. There is no "crash" in this case—just an erroneous result.

    Clearly, the intent of the programmer was to prevent division by zero, and she/he surely accomplished that, but not in they manner he/she intended!

  4. Your book points out the difference between writing the not-equals sign from math not equal to and the C symbol != which is the relational operator for not-equals. Be sure that when you write out programs on exams or quizzes that you always use the != symbol, and never the math symbol. Similarly, even for hand-written C code always use <= and >=, never less than or equal to or greater than or equal to (which are fine for pseudocode, but never for C program code.)
  5. On p. 174, your text suggests that you remember that in order to use "fabs()" in your code, you need to do a "#include <stdlib.h>". Actually, on strauss, the situation is a bit different:

    The following script session illustrates this:

 
> cat fabsTest.c
/* program to test compiling with fabs (floating pt absolute value ) */
/* P. Conrad, for CISC105, Fall 2004 */

#include <stdio.h>

int main (void)
{
  double x = -1.23;

  printf("fabs(x) = %lf\n", fabs(x));

  return 0;
}
> cat fabsTest1.c
/* program to test compiling with fabs (floating pt absolute value ) */
/* P. Conrad, for CISC105, Fall 2004 */

#include <stdio.h>
#include <stdlib.h>

int main (void)
{
  double x = -1.23;

  printf("fabs(x) = %lf\n", fabs(x));

  return 0;
}
> cat fabsTest2.c
/* program to test compiling with fabs (floating pt absolute value ) */
/* P. Conrad, for CISC105, Fall 2004 */

#include <stdio.h>
#include <math.h>

int main (void)
{
  double x = -1.23;

  printf("fabs(x) = %lf\n", fabs(x));

  return 0;
}
> cc fabsTest.c
Undefined                       first referenced
 symbol                             in file
fabs                                fabsTest.o
ld: fatal: Symbol referencing errors. No output written to a.out
> cc fabsTest.c -lm
> ./a.out
fabs(x) = 1.230000
> gcc fabsTest.c
fabsTest.c: In function `main':
fabsTest.c:10: warning: type mismatch in implicit declaration for built-in function `fabs'
> gcc fabsTest1.c
fabsTest1.c: In function `main':
fabsTest1.c:11: warning: type mismatch in implicit declaration for built-in function `fabs'
> gcc fabsTest2.c
> ./a.out
fabs(x) = 1.230000
> 

 

Lesson 4.2 Simple If-Else Control Structures (p. 175)

This section covers if/else, as well as the ternary operator. An important section to read. Just one comment: consider the statement on p. 178: "Note that, for the unevaluated expression [in the ternary operator], no side effects occur".

Let's call this the "no side effects" rule. Can you think of an example where the "no side effects" rule would apply? What do the authors mean by "side effects"? As an example, consider the output of the following program would be when the input is 1, and when the input is 2:

> cat ternarySideEffect.c 
// ternarySideEffect.c   P. Conrad for CISC105, Fall 2004
// A silly program that does nothing useful, but illustrates
// some rules of the C programming language.

#include <stdio.h>

int main(void)
{
  int x;
  int a = 10, b = 20;
  int c; 

  printf("Enter 1 or 2 > ");
  scanf("%d", &x);

  c = (x < 2) ? a++ : b++; 

  printf("a=%d b=%d c=%d\n",a, b, c);
  return 0;
}
> make ternarySideEffect
cc    -o ternarySideEffect ternarySideEffect.c 
> ./ternarySideEffect 
Enter 1 or 2 > 1
a=11 b=20 c=10
> ./ternarySideEffect
Enter 1 or 2 > 2
a=10 b=21 c=20
> 

 

 

Lesson 4.3 Nested If-Else Control Structures (p. 178)

Understanding how to next if/else control structures is important, so read this section carefully.

A comment: this section shows the proper indentation of if/else control structures. This is very important. If you get in the habit of properly indenting your if/else control structures, you will avoid many mistakes.

Lesson 4.4 Logical Expressions (p. 182)

This lesson covers logical expressions. Be sure that you always use && and || to mean and and or, respectively. There is also a single & and single | operator in C, however these mean "bit-wise-and" and "bitwise-or" which are different. They may seem to work the same for many cases, but they do not work the same in all cases.

The not operator (!) can frequently be overlooked by a programmer reading your code, and it is sometimes better to avoid it. DeMorgan's rules can be useful for eliminating the ! operator. In C they are expressed as follows:

For example, the expressions on the left are equal to the ones on the right. But which is easier to read?

!((x == 0) && (y == 0)) (x!=0) || (y!=0)
!((x>0) || (y>0)) (x>=0) && (y>=0)

 

Lesson 4.5 Precedence of Logical Operators (p. 186)

This section covers operator precedence of logical operators, but it also covers treating variables as logical values (e.g. int a=4; ... if (a) printf(...)). Be sure you don't miss this important point!

Lesson 4.6 Switch and If-Else-If Control Structures (p. 191)

This lesson introduces the switch statement as an alternative to the if/else construct.

One thing to be careful of in the switch statement is to be sure that every switch case ends in a break statement (unless you really want to fall through to the next case.) If you do want to fall through to the next case, you should definitely put in a comment indicating that you "meant" to do that.

Lessons 4.7-4.11 While loops and for loops (pp 199-224).

Don't interpret my lack of detailed comments on these sections as a signal that these sections aren't important. On the contrary: they are very important, and very well written. Be sure you read over these sections carefully, and understand each of the forms of while loops and for loops (both simple and nested).

Actually, section 4.11 is the only one where I'm a little disappointed; I would like to have seen some coverage of using nested for loops to produce two dimensional tables such as the one on this web page: http://www.nws.noaa.gov/om/windchill/index.shtml

Here's an example program that produces a multiplication table such as the one that you might find in a 3rd or 4th grade classroom. Perhaps that can give you an idea of how a table like the one on the web site above might be produced using nested for loops:


> cat multTable.c
/* multTable.c   Produce 2D multiplication table using nested loops */ 
/* P. Conrad for CISC105, Fall 2004 */

/* result should look like this: 
 
  +---++---+---+---+---+... 
  | x ||  1|  2|  3|  4| 
  +===++===+===+===+===+...
  |  1||  1|  2|  3|  4|
  +---++---+---+---+---+...
  |  2||  2|  4|  6|  8|
  +---++---+---+---+---+...
  |  3||  3|  6|  9| 12|
  ... etc.                          */
       

 
#define LIMIT 10    /* Limit of how far the table goes up.  
                       Could be changed to 12, for example */ 
  
#include <stdio.h> 
 
void printLineAcross(void)
{
  /* print a line like this one, 
  +---++---+---+---+---+...  
  with limit + 1 columns      */

  int i;

  printf("+---++");
  for (i=1; i<=LIMIT; i++)  
    printf("---+");
  printf("\n");

  return;
}

/* note: we could do better by creating one function printLineAcross,
   and passing in the character to use, either '-' or '='.  Please accept
   this invitation to do that as an exercise */

void printDoubleLineAcross(void)
{
  /* print a line like this one, 
  +===++===+===+===+===+...  
  with limit + 1 columns      */

  int i;

  printf("+===++");
  for (i=1; i<=LIMIT; i++)  
    printf("===+");
  printf("\n");

  return;
}



int main(void) 
{ 
 
  int i,j; /* loop indices */ 
 

  /* print header row */

  printLineAcross();
  printf("| x ||");
  for (i=1; i<=LIMIT; i++)
    printf("%3d|", i);
  printf("\n"); 
  printDoubleLineAcross();

  /* print the main table */

  for (i=1; i<=LIMIT; i++)
    {
      /* print the first cell that labels the row */
      printf("|%3d||", i);

      /* fill in the row with the rest of the entries*/
      for (j=1; j<=LIMIT; j++)  
        {
          printf("%3d|", i * j); /* prints the actual multiplication entry */
        }
      printf("\n"); /* finish off the row */
      printLineAcross();
    }

  /* Done! */

  return 0;
}
> make multTable
cc    -o multTable multTable.c 
> ./multTable 
+---++---+---+---+---+---+---+---+---+---+---+
| x ||  1|  2|  3|  4|  5|  6|  7|  8|  9| 10|
+===++===+===+===+===+===+===+===+===+===+===+
|  1||  1|  2|  3|  4|  5|  6|  7|  8|  9| 10|
+---++---+---+---+---+---+---+---+---+---+---+
|  2||  2|  4|  6|  8| 10| 12| 14| 16| 18| 20|
+---++---+---+---+---+---+---+---+---+---+---+
|  3||  3|  6|  9| 12| 15| 18| 21| 24| 27| 30|
+---++---+---+---+---+---+---+---+---+---+---+
|  4||  4|  8| 12| 16| 20| 24| 28| 32| 36| 40|
+---++---+---+---+---+---+---+---+---+---+---+
|  5||  5| 10| 15| 20| 25| 30| 35| 40| 45| 50|
+---++---+---+---+---+---+---+---+---+---+---+
|  6||  6| 12| 18| 24| 30| 36| 42| 48| 54| 60|
+---++---+---+---+---+---+---+---+---+---+---+
|  7||  7| 14| 21| 28| 35| 42| 49| 56| 63| 70|
+---++---+---+---+---+---+---+---+---+---+---+
|  8||  8| 16| 24| 32| 40| 48| 56| 64| 72| 80|
+---++---+---+---+---+---+---+---+---+---+---+
|  9||  9| 18| 27| 36| 45| 54| 63| 72| 81| 90|
+---++---+---+---+---+---+---+---+---+---+---+
| 10|| 10| 20| 30| 40| 50| 60| 70| 80| 90|100|
+---++---+---+---+---+---+---+---+---+---+---+
> 

You might try changing the #define (constant macro) to make the table be a 12 by 12 table, or changing it so that the limit value is a variable entered by the user.

Application Programs 4.1-4.7

All of these are definitely worth looking over. I particularly want to recommend that you look at exercise 4.7, which solves quadratic equations (for both real and imaginary numbers).

Exercises

The following exercises are definitely recommended, and are certainly fair game for exam questions:

Application Exercises

All of the application exercises are good practice for you. A few of them may show up i your labs/projects. You are advised to look over the others, as they might make an appearance (in simplified form) as exam questions.

(end of reading notes for Chapter 4).

These reading notes are based on C Programming for Engineering and Computer Science, by H. H. Tan and T. B. D'Orazio, Copyright 1999 by WCB McGraw-Hill. The notes themselves are Copyright 2004, by Phillip T. Conrad, All Rights Reserved.

Prof. Conrad takes sole responsibility for any views or opinions expressed in these notes. Such view and opinions do necessarily reflect those of the University of Delaware, its Department of Computer and Information Sciences, or any other organization.