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:

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
 
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.

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

int Main ()  
{
}
 

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.

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

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

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

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

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

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

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

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

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.

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);
}
 

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 
}
 

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.

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 C 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);
           }                                     
          

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

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

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));
      }
        

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);

}
 

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.
}
 



© 2003, Rahul Simha (revised 2017)