C Syntax Review and Exercises


Comments

Let's take a look at a simple C program, test.c without any real code:

#include <stdio.h>

int main ()
{
}
  

NOTE:

Next, let us add some comments:

// Comment 1 

int main ()  // Comment 2
{
  // Comment 3
  
}
// Comment 4

NOTE:

Next, let's play around with the program to highlight a few syntax issues:

In-Class Exercise 0.1 The following program will not compile. Why? And what kind of error is identified by the compiler?

// Comment 1 

int main ()  // Comment 2
{
  // 
     Comment 3
  
}
// Comment 4
 

In-Class Exercise 0.2 Is a comment allowed between parameter brackets?

// Comment 1 

int main (  // Comment 2
         )  
{
  // Comment 3
  
}
// Comment 4
 

C programs are case-sensitive. The following program will not compile:

Int main ()  
{
}
This is because the C reserved word int is mis-spelt as Int.

Notice that the error produced above by the (gcc)compiler is simply:

test.c:3: parse error before 'main'
Thus, the compiler does not know you mis-typed.

In-Class Exercise 0.3 What is the error produced by compiling this program?

int Main ()  
{
}
 

In-Class Exercise 0.4 What is the error produced by compiling this program?

int main ()
{
  Printf ("Hello World!\n");
}
 

HelloWorld

Consider the classic helloworld program in C:

int main ()
{ 
  printf ("Hello World!\n");
}
 

The main syntactic elements are:

  • C's only reserved word in this program: int.
  • Function names: main, printf.
  • Delimiters for the function main.
  • An end-of-statement symbol, the semicolon.
  • Parentheses for enclosing method parameters (arguments).
  • A string literal, Hello World!.
  • Braces that delimit the body of main.

Next, let us get accustomed to errors produced by the compiler when the syntax is incorrect.

In-Class Exercise 0.5 What errors are reported by the compiler with this program?

int main (  // Forgot the matching right parenthesis
{
  printf ("Hello World!\n");
}
 

In-Class Exercise 0.7 What errors are reported by the compiler with this program?

int main ()
{
  printf ("Hello World!\n);   // Forgot the matching right quote (")
}
 

In-Class Exercise 0.8 What errors are reported by the compiler with this program?

int main ()
{
  printf ("Hello World!\n")  // Forgot the semi-colon.
}
 

In-Class Exercise 0.9 What errors are reported the compiler with this program?

int main ()
{
  printf ("Hello World!\n");
// Missing brace 
 

In-Class Exercise 0.10 Try to compile and run this program.

main ()
{
  printf ("Hello World!\n");
}
 

Data types and Identifiers

Let us examine some code with only int's to get started:

int main ()
{
  // Declare an integer variable called "i". 
  int i;

  // Assign it a value. Note the assignment operator "=" 
  i = 5;

  // Print out its value to the screen. 
  printf ("%d\n", i);
}
  

Next, let's play around with the syntax and observe what the compiler reports.

In-Class Exercise 0.11 Try to compile and run this program.

int main ()
{
  // Didn't declare "i"

  // Assign it a value. Note the assignment operator "=" 
  i = 5;

  // Print out its value to the screen. 
  printf ("%d\n", i);
}
 

In-Class Exercise 0.12 Try to compile and run this program.

int main ()
{
  // Declare an integer variable called "i". 
  int i;

  // Wrong assignment operator
  i := 5;

  // Print out its value to the screen. 
  printf ("%d\n", i);
}
 
NOTE:

  • Good programming style requires that variable names be chosen for readability.

  • Variable names like i are usually only appropriate for loop (control) variables.

  • What kinds of variable names are allowed?
    The rules that apply to variable names also apply to method and parameter names, the so-called identifiers.

About identifiers:

  • An identifier must begin with a letter or underscore

  • An identifiers can contain any number of letters, digits, or underscores.

  • Case (upper or lower) is significant.

  • No C reserved word can be used as an identifier.

  • Examples of legal identifiers:
    i
    really_important_integer_for_counting_lines_in_a_text_file (bad style)
    num_lines_in_file (acceptable, old C style)
    numLinesInFile (recommended, new C style)

More about variable declaration syntax:

  • Variables can be assigned values in a declaration:
    int main ()
    {
      // Declare an integer variable called "i" and assign it a value.
      int i = 5;
    
      // Print out its value to the screen. 
      printf ("%d\n", i);
    }
      
  • Declarations can occur anywhere in a program body in C99 but not in earlier versions.
  • Multiple variables (of the same type) can be declared in a single statement:
    int main ()
    {
      // Declare multiple variables of the same type. 
      int i = 5, j = 6, k;
      
      k = 7;
    
      printf ("i=%d  j=%d  k=%d\n", i, j, k);
    }
      

    The preferred style is either:

    int main ()
    {
      int i = 5;  // i is the variable that .... 
      int j = 6;  // j ... 
      int k = 7;  // k ... 
    
      printf ("i=%d  j=%d  k=%d\n", i, j, k);
    }
      
    or
    int main ()
    {
      int 
        i = 5,  // i is the variable that .... 
        j = 6,  // j ... 
        k = 7;  // k ... 
    
      printf ("i=%d  j=%d  k=%d\n", i, j, k);
    }
      

More Data Types

While there are seven additional data types, we will first focus on a few:

  • double
    • Use double to store floating point numbers, as in:
      int main ()
      {
        double 
          pi = 3.14159,      // The constant Pi 
          radius = 2.0E03,   // Circle radius in exponent format. 
          area = 0;          // Area, not yet computed. 
      
        area = pi * radius * radius;
      
        printf ("Area of circle with radius %lf is %lf\n", radius, area);
      }
       
    • double constants are decimal values (3.14159), or in exponent notation (2.0E03).

  • char
    • A char variable holds a single character, e.g.,
      int main ()
      {
        char 
         initial1 = 'J',
         initial2 = 'F',
         initial3 = 'K';
      
         printf ("Initials: %c %c %c\n", initial1, initial2, initial3);
      }
       
    • "Backslash" combinations are used to represent special characters:
      int main ()
      {
        char initial1 = 'J';
        char initial2 = 'F';
        char initial3 = 'K';
        char newline = '\n';
        char tab = '\t';
      
        printf ("%c Initials: %c \" %c %c %c \" %c", newline, tab, initial1, initial2, initial3, newline);
      }
       
    • Notice the double quote character inside the string "Initials: %c \".

  • Strings
    • Strings in C are really char-arrays, pointed to by a variable of type char *
    • Example:
      int main ()
      {
        char *str1 = "Hello";
        char *str2 = "World!";
      
        // String constants can be concatenated by whitepace:
        char *str3 = "Hello" " again";
      
        printf ("%s %s \n %s \n", str1, str2, str3);
      }
      
       

Casting

Casting is the term used to convert a value of one data type to a value of another data type. For example:

int main ()
{
  int i = 5, j = 6;
  double x = 2.718,  y = 3.141;

  // Implicit cast: 
  x = i;
  printf ("x = %lf\n", x);   // Prints 5.0 
    
  // Explicit cast: 
  j = (int) y;
  printf ("j = %d\n", j);   // Prints 3 
}
 

In-Class Exercise 0.13 What does the following program print out?

int main ()
{
  printf ("%lf\n", ( (double) (int) 3.141 ) );
}
 

Expressions

Arithmetic expressions:

  • Many arithmetic expressions in C are common to most programming languages:, e.g.,
       x = ( (a / b) * (c - d) ) + e;
      

  • It's considered good style to delineate arithmetic expressions with parentheses, where appropriate, to help with readability.

  • Java programmers will be familiar with operators like post-increment and "assignment with operator", e.g.,
       i = 0; 
       i += 1;         // Same as i = i + 1; 
       A[++i] = 0;     // A[2] = 0 because i is first incremented and then used 
      

  • Other arithmetic operators include:
    / Integer division
    % Integer remainder

    Note: bitwise arithmetic operators include the shift operators:
    >> Right shift
    << Left shift

    This is not a complete list - consult a C reference for more operators.

In-Class Exercise 0.14 What does the following program print out?

int main ()
{
  int k = 13;
  int i;

  for (i=0; i < 8; i++) {
    printf ("%d ", (k % 2));
    k >>= 1;
  }
  printf ("%\n");
}
 

Boolean expressions:

  • Boolean operators include:
    && AND
    || OR
    ! NOT
    & Bitwise AND
    | Bitwise OR
    ^ Bitwise XOR
  • Examples of boolean expressions used in if statements:
        if (i == 10) 
          printf ("i is equal to 10");
        
        if ( !(i == 10) )
          printf ("i is not equal to 10");
        
        if (i < 10) 
          print ("i is less than 10");
        
        if ( (i >= 5) && (i <= 10) )
          print ("i is between 5 and 10");
             
        if ( (i >= 5) && (i != 6) )
          printf ("i larger than 6");
       

Statements

Finally, we will examine some basic Java statements. The following is not meant to be exhaustive, but rather, a quick introduction to the most commonly used statements:

  • Assignment:
    • Assignment statements use the assignment operator =, e.g.,
             x = 5;                 // Simple assignment. 
             y = getInputValue();   // Assign a function's return value. 
             z = (x + y) / y;       // Assign an expression value. 
           
    • Assignment can be combined with many operators, e.g.,
             x += 5;    // Add 5 to x 
           
    • Assignments can be grouped:
             x = y = z = 0;     // All are given the value 0. 
           

  • if-statement:
    • An if-statement is the keyword if followed by a boolean expression in parentheses, followed by a statement.
    • Example:
             if (x < 5) 
               printf ("x is less than 5");
           

  • compound-statement:
    • Compound statements are groups of statements placed in a single block.
    • A block is delineated with braces.
    • Example:
             if (x < 5) {       // Start of block 
               y = 5;
               z += x;
             }                  // End of block 
           
    • Example:
             if (x < 5) {       // Start of outer block 
               y = 5;
               z += x;
               if (z > 10) {      // Start of inner block 
                 z = z - 1;
                 w = z * z;
               }                  // End of inner block 
             }                  // End of outer block 
           

  • if-else and if-else-if statements:
    • Example of if-else
             if (x < 5) {
               printf ("x is less than 5");
             }
             else {
               printf ("x is not less than 5");
             }
           
    • Example of if-else-if
             if (x < 5) {
               printf ("x is less than 5");
             }
             else if (x > 5) {
               printf ("x is greater than 5");
             }
             else if (x == 5) {
               printf ("x is equal to 5");
             }
             else {
               // Logically impossible! 
             }
           

  • while loop:
    • Example:
           printf ("Countdown: ");
           i = 10;
           while (i >= 1) {           // Start of while-body 
             printf ("%d\n", i);
             i--;
           }                          // End of while-body 
           
    • Any boolean expression can be used for the while-test expression (i.e., in place of i >= 1).

  • for loop:
    • Example:
           int i;
           printf ("Countdown: \n");
           for (i=10; i >= 1; i--) {           // Start of for-body 
             printf ("%d\n", i);
           }                                     // End of while-body 
           
    • The loop-header first has a statement (int i = 10) then a boolean expression (i>=1), followed by another statement (i--), each separated by a semi-colon.
    • Note: for consistency with C versions prior to C99, the for-loop variable is defined earlier.
    • Each statement (first, and third parts) can consist of multiple comma-separated statements:
           int i, j;
           printf ("Weird countdown/up: \n");
           for (i=10, j=1; ( (i >= 1) && (j <= 10) ); i--, j++) { 
             printf ("i=%d  j=%d\n", i, j);
           }                                     
           
    • Sometimes, the flexibility offered by the for-loop can be taken too far, making some code examples difficult to read:
           printf ("Really weird countdown/up: \n");
           for (countInitializer (i,10), countInitializer (j,1); 
                checkCountGreaterEqual (i, 1) && checkCountLessEqual (j, 10);
                incrementCount (i, -1), incrementCount (j, 1)) {
             printf ("i=%d j=%d\n", i, j);
           }                                     
          

In-Class Exercise 0.15 What's wrong with the statement below? What happens when you compile?

    if (i = 5)
      printf ("i is equal to 5");
 

In-Class Exercise 0.16 What is the error in the following code?

   int i = 10;
   while (i >= 1)
     printf ("i=%d\n", i);
     i--;
 

Functions

Other languages call them "procedures" or "methods". C calls them functions:

  • A function refers to both a procedure (doesn't return a value) or a function (does return a value).

  • A function that does not return a value returns a void value.

  • A function declaration has a return type, followed by the name, followed by parameter declarations.

  • Example of a simple (static) method declaration:
    void printHello ()
    {
      printf ("Hello World!");
    }
      
    int main ()
    {
      printHello ();
    }
    
    Note:
    • The method printHello() has no parameters.
    • The return type is void.
    • Although main doesn't return anything, it's return type is declared as int, for the esoteric applications in which the int is used.

  • Example with parameters and return values:
    int squareIt (int inputInteger)
    {
      int squareValue = inputInteger * inputInteger;
      return squareValue;
    }
      
    int main ()
    {
      int i = 5;
      int j = squareIt (i);
      printf ("The square of %d is %d\n", i, j);
    }
      
    Note:
    • The method squareIt() takes one int parameter and returns an int.
    • The return-statement is the keyword return followed by an expression whose type is the same as the return type.

  • Let's consider some variations of the previous example to illustrate a few points:
    • The return-expression can be of any type that can be cast into the return type, e.g,
      int squareIt (int inputInteger)
      {
        double squareValue = inputInteger * inputInteger;
        return (int) squareValue;                          // Cast to return type 
      }
        
      int main ()
      {
        int i = 5;
        int j = squareIt (i);
        printf ("The square of %d is %d\n", i, j);
      }
        
    • We can "tighten" the code in two ways:
      int squareIt (int inputInteger)
      {
        return (inputInteger * inputInteger);
      
      }
        
      int main ()
      {
        int i = 5;
        printf ("The square of %d is %d\n", i, squareIt (i));
      }
        

In-Class Exercise 0.17 What happens if the function squareIt follows main?

int main ()
{
  int i = 5;
  printf ("The square of %d is %d\n", i, squareIt (i));
}

int squareIt (int inputInteger)
{
  return (inputInteger * inputInteger);

}
 

In-Class Exercise 0.18 Is it possible for a function to return a value, but that the value not be used?

int squareIt (int inputInteger)
{
  return (inputInteger * inputInteger);
}
  
int main ()
{
  int i = 5;
  squareIt (i);    // Return value not used.
}