The Structure of C Programs: #Include #Include #Include #Include
The Structure of C Programs: #Include #Include #Include #Include
Let's looks at the high-level structure of the rot.c program from Lab01 (using ellipsis to omit some statements for now). Of note in this example:
#include #include #include #include <stdio.h> <stdlib.h> <string.h> <ctype.h>
Characters such as a space, tab, or newline, may appear almost anywhere - they are stripped out and ignored by the C compiler. We use such whitespace characters to provide a layout to our programs. While the exact layout is not important, using a consistent layout is very good practice. Keywords, in bold, mean very specific things to the C compiler. Lines commencing with a '#' in blue are processed by a separate program, named the C preprocessor. In practice, our program is provided as input to the preprocessor, and the preprocessor's output is given to the C compiler. Lines in green are comments. They are ignored by the C compiler, and may contain (almost) any characters. C99 provides two types of comments 1. /* block comments */ and 2. // comments to the end of a line
/* Compile this program as: gcc -std=c99 -Wall -Werror -pedantic -o rot rot.c */ #define ROT 13 static char rotate(char c) { ..... return c; } int main(int argc, char *argv[]) { // check the number of arguments if(argc != 2) { .... exit(EXIT_FAILURE); } else { .... exit(EXIT_SUCCESS); } return 0; }
1/12
A variety of brackets are employed, in pairs, to group together items to be considered in the same way. Here: angle brackets enclose a filename in a #include directive, round brackets group items in arithmetic expressions and function calls, square brackets enclose the index when access arrays (vectors and matricies...) of data, and curly brackets group together sequences of one or more statements in C. We term a group of statements a block of statements. Functions in C, may be thought of as a block of statements to which we give a name. In our example, we have two functions - rotate and main. When our programs are run by the operating system, the operating system always starts our program from main. Thus, every complete C program requires a main function. The operating system passes some special information to our main function, command-line arguments, and main needs a special syntax to receive these. When our program finishes its execution, it returns some information to the operating system. Our example here exits by announcing either its failure or success.
/* Compile this program as: gcc -std=c99 -Wall -Werror -pedantic -o rot rot.c */ #define ROT 13 static char rotate(char c) { ..... return c; } int main(int argc, char *argv[]) { // check the number of arguments if(argc != 2) { .... exit(EXIT_FAILURE); } else { .... exit(EXIT_SUCCESS); } return 0; }
2/12
Variables
Variables are locations in a computer's memory. A typical desktop or laptop computer will have 1GB of memory, or one billion addressible memory locations, and C programs will typically use 4 bytes to hold 1 integer value. Any variable can only hold a single value at any time - they do not maintain a history of past values they once had.
and MyLimit
are four different variable names. Older C compilers may limit variable names to, say, 8 unique characters. Thus, for them,
turn_reactor_coolant_on
and
turn_reactor_coolant_off
are the same variable! Keep this in mind when writing portable code. While not required, it's preferred that variable names do not consist entirely of uppercase characters. We'll consistently use uppercase-only names for constants provided by the C preprocessor, or user-defined type names:
MAXLENGTH, AVATAR, BUFSIZ, and ROT
3/12
Basic datatypes
Variables are declared to be of a certain datatype, or just type. We use different types to represent the role permissible values that a program's variable has. For example, if we're using a variable to just count things, we'll use an integer variable to hold the count; if performing trigonometry on angles expressed in radians, we'll use floating-point variables to hold values with both an integral and a fractional part. C provides a number of standard, or base types to hold commonly required values, and later we'll see how we can also define our own user-defined types to meet our needs. Let's look quickly at some of C's base datatypes: typename bool char int float double description, and an example of variable initialization Boolean (truth values), which may only hold the values of either true or false e.g. bool finished = false; character values, to each hold a single values such as an alphabetic character, a digit character, a space, a tab... e.g. char initial = 'C'; integer values, negative, positive, and zero e.g. int year = 2006; floating point values, with a typical precision of 10 decimal digits (on our lab machines) e.g. float inflation = 4.1; "bigger" floating point values, with a typical precision of 17 decimal digits (on our lab machines) e.g. double pi = 3.1415926535897932;
Some textbooks will (too quickly) discuss the actual storage size of these basic types, and discuss the ranges of permissible values. We'll examine these later, but for now we'll focus on using these basic types in their most obvious ways. From where does the bool datatype get its name? - the 19th century mathematician and philosopher, George Boole.
CITS1210 C Programming: Lecture 2, Wednesday 4 August. 4/12
It is defined on line 06, and may be used anywhere from line 06 until the end of the file (until line 26). The variable nfound has block scope. It is defined on line 10, and may be used anywhere from line 10 until the end of the block in which it was defined (until line 26). The variable nerrors has block scope. It is defined on line 14, and may be used anywhere from line 14 until line 18. The variable ntimes has block scope. It is defined on line 20, and may be used anywhere from line 20 until line 24. We could define a different variable named nerrors in the block of lines 20-24 - without problems. We could define a different variable named nfound in the block of lines 20-24 - but this would be a very bad practice!
static int count = 0; int main(int argc, char *argv[]) { int nfound = 0; // check the number of arguments if(argc != 2) { int nerrors = 1; .... exit(EXIT_FAILURE); } else { int ntimes = 100; .... exit(EXIT_SUCCESS); } return 0; }
5/12
Conditional execution
Conditional statements first evaluate a Boolean condition and then, based on whether it's true or false, execute other statements. The most common form is: Sometimes, the else clause is omitted: Often, the else clause itself provides further if statements:
if( condition1) { more statements; ..... } else if(condition2) { more statements; ..... } else { more statements; ..... }
6/12
// here, variable i holds the values 1,2,...10 for(int i = 1 ; i <= 10 ; i = i+1) { // the above introduced a loop-control variable, i ..... printf("loop number %d\n", i); ..... // variable i is available down to here } // but variable i is not available from here
// here, variable ch holds each lowercase value for(char ch = 'a' ; ch <= 'z' ; ch = ch+1) { ..... printf("loop using character '%c'\n", ch); ..... }
Notice that in both cases, above, we have introduced new variables, here i and ch, to specifically control the loop. The variables may be used inside each loop, in the statement block, but then "disappear" once the block is finished (after its bottom curly bracket). It's also possible to use any other variable as the loop control variable, even if defined outside of the for loop. In general, we'll try to avoid this practice - unless the value of the variable is required outside of the loop.
CITS1210 C Programming: Lecture 2, Wednesday 4 August. 7/12
i = 1; n = 0; while(i <= 20) { printf("iteration number %d\n", i); ..... ..... i = some_calculation_setting_i; n = n + 1; } printf("loop was traversed %d times\n", n);
i = 1; n = 0; do { printf("iteration number %d\n", i); ..... ..... i = some_calculation_setting_i; n = n + 1; } while(i <= 20); printf("loop was traversed %d times\n", n);
Notice that in both cases we still use a variable, i, to control the number of iterations of each loop, and that the changing value of the variable is used to determine if the loop should "keep going". However, the statements used to modify the control variable may appear almost anywhere in the loops. The can provide flexibility, but can also be confusing when loops become severals tens or hundreds of lines long. Notice also that while, and do....while loops cannot introduce new variables to control their iterations, and so we have to use "more global" variables.
CITS1210 C Programming: Lecture 2, Wednesday 4 August. 8/12
for(int i = 1 ; i <= 6 ; i = i+1) { for(int j = 1 ; j <= 4 ; j = j+1) { printf("(%d,%d) } printf("\n"); } ", i, j); // print i and j as if "coordinates" // finish printing on this line
Notice that we have two distinct loop-control variables, i and j. Each time that the inner loop (j's loop) starts, j's value is initialized to 1, and advances to 4. As programs become more complex, we will see the need for, and write, all combinations of: for loops within for loops, while loops within while loops, for loops within while loops, and so on....
CITS1210 C Programming: Lecture 2, Wednesday 4 August. 9/12
for(int i = 1 ; i <= 10 ; i = i+1) { // Read an input character from the keyboard ..... if(input_char == 'Q') // Should we quit? break; ..... ..... } // Come here after the 'break'. i is unavailable
for(char ch = 'a' ; ch <= 'z' ; ch = ch+1) { if(ch == 'm') // skip over the character 'm' continue; ..... ..... statements that will never see ch == 'm' ..... ..... }
In the first example, we iterate through the loop at most 10 times, each time reading a line of input from the keyboard. If the user indicates they wish to quit, we break out of the bounded loop. In the second example, we wish to perform some work for all lowercase characters, except 'm'. We use continue to ignore the following statements, and to start the next loop (with ch == 'n').
CITS1210 C Programming: Lecture 2, Wednesday 4 August. 10/12
In both cases, we're expecting expression2 to produce a Boolean value, either true or false, as we need that truth value to determine if our loops should "keep going". You should think about these carefully, perhaps perform some experiments, to determine where control flow really goes when we introduce break and continue statements.
CITS1210 C Programming: Lecture 2, Wednesday 4 August. 11/12
And this loop doesn't even have a loop-control variable, and doesn't test for its termination. This loop will run forever, until we interrupt or terminate the operating system process running the C program. We term these infinite loops :
While we often see and write such loops, we don't usually want them to run forever! We will typically use an enclosed condition and a break statement to terminate the loop, either based on some user input, or the state of some calculation.
CITS1210 C Programming: Lecture 2, Wednesday 4 August. 12/12