c programming lecture notes 2008-09

Upload: mm010a

Post on 06-Apr-2018

286 views

Category:

Documents


1 download

TRANSCRIPT

  • 8/3/2019 C Programming Lecture Notes 2008-09

    1/173

    1

    1. A Gentle Introduction to C 2

    2. Variables, Operators & Expressions 9

    3. Statements & Flow Control 20

    4. Functions 36

    5. The Preprocessor 50

    6. Arrays 56

    7. Program Structure 62

    8. Pointers 77

    9. Strings 103

    10. Structures 113

    11. Dynamic Memory 122

    12. Input & Output 135

    Appendix A: Some Example Programs 151

    Appendix B: Problem Sheets

    Appendix C: Past Exam Papers

    Appendix D: Data Structure Example

  • 8/3/2019 C Programming Lecture Notes 2008-09

    2/173

    2

    1. A Gentle Introduction to C

    1.1 Basic Hardware concepts

    A computer is made up of three main components:

    1. The micro-processor (mp) which is only able of

    performing very basic

    instructions

    2. The memory which stores the data manipulated by the

    micro-processor.

    3. The bus which links the mp to the memory and allow

    communication.

    1.1.1 Memory - the concept of address

    The memory of a computer is made of a large number of electronic components

    which are designed to store the value of a set of eight binary values, a byte.

    Each of these components is identified by a integer (usually given in

    hexadecimal notation) called the address.

    In other words, an address is nothing more than a location in the memory where

    a byte can be stored.

    Example: the 6501, a very simple mp, can manage up to 64 Kb of memory.

    There are therefore 65,536 addresses available to store bytes of information.

    The addresses start at 0000 and finish at 0xFFFF (which is 65,535 in

    hexadecimal notation).

    When the mp requires data, it has to determine its address. This is the only way

    it can access it.

    Every object that the computer manipulates has to be represented as one or a

    sequence of several continuous bytes.

    The address of an object in memory is the address of the first byte used to store

    it.

  • 8/3/2019 C Programming Lecture Notes 2008-09

    3/173

    3

    1.1.2The Micro-Processor - The Concept of Machine Instruction

    The micro-processor is a electronic component which is able to perform only a

    fairly limited number of basic operations:

    1. store a bit pattern in memory

    2. get a bit pattern from memory

    3. perform basic arithmetic or boolean operations on a bit pattern

    4. jump to "somewhere'' in a program. Actually, the mp jumps to the

    address where the next instruction to be executed is stored in memory.

    These basic operations are the machine instructions.

    Basic tasks such as the multiplication of two real numbers have to be

    decomposed in a large sequence of machine instructions.

    A computer program at the lowest level is nothing more than a sequence of

    machine instructions operating on the memory.

    1.2 The Role of High-Level Languages

    The first people to use computers had to write their program directly with the

    machine instructions and addresses needed.

    This is both very impractical and error-prone.

    High level languages are designed to allow easier communication between the

    user and the machine.

    While executable code is made of machine instructions and addresses, a high

    level language is made of statements describing the operations to be done and

    variables which store the data being processed.

    Once a program is written in the language, it is transformed into an executable

    code in two main stages:

    1. the compiler translates the high level instructions into machine

    instructions

    2. the linker associates an address with every variable used. A variable is

    nothing more than a symbolic name for an address in the computer

    memory.

  • 8/3/2019 C Programming Lecture Notes 2008-09

    4/173

    4

    1.3 A First C program

    A C program is collection of functions which operate on variables.

    A function in C is a sequence of computing operations which are executed in

    sequence.

    A function has:

    1. a name

    2. a number of arguments which provide data for the function (the

    function may need no argument).

    3. a body i.e. a sequence of statements that describe the job to be carried

    out by the function.

    4. a result which is returned (the function may also return no result).

    Example of a complete C program:

    #include

    int main()

    {

    printf("Hello world\n");

    return 0;

    }

    After compilation and linkage, this program will display the message Hello

    worldon the screen.

  • 8/3/2019 C Programming Lecture Notes 2008-09

    5/173

    5

    Analysis of the program

    It consists of a function called main which takes no arguments and returns no

    value. main is the C equivalent of the main program in Pascal or FORTRAN.

    A C program starts at the beginning ofmain. Consequently every C program

    has to have a main function somewhere.

    The work done by main is enclosed between the braces {}.

    Usually, main will call other functions to perform its task.

    In this case, main only uses one other function, called printf with a single

    argument: "hello World". It is printf which is responsible for outputting the

    message.

    In C a function is called by stating its name followed by a possibly empty list of

    arguments enclosed in brackets:

    Function_Name(list_of_arguments);

    printf is very commonly used in C programs. It is the basic output routine.

    After execution ofprintf, the end of main is reached and control is returned

    to the calling program. In the case of main, the calling program is always theoperating system.

    Note that printf is not defined in the program. The reason is that printf is

    a function which is part of the C standard itself.

    A C program can therefore make use of function that are either written by the

    program or provided to him by the language standard.

    C comes in with different collections of such standard functions called libraries.

    Commonly used library of functions include:

    1. input/output operations

    2. mathematic functions

    3. processing of strings of characters.

    The line #include indicates to the compiler that the

    input/output library is going to be used in the program.

  • 8/3/2019 C Programming Lecture Notes 2008-09

    6/173

    6

    1.4 Variables in C

    Variables are defined by specifying:

    a) a name

    b) the type of data they are to contain

    C can handle variables containing integer numbers, floating point numbers and

    a single characters.

    For example:

    #include

    int main()

    {

    int sum;

    sum=10+15;

    printf("sum of 10+15:%d\n",sum);

    return 0;

    }

    This program makes use of a variable named sum of type integer (this is a

    short-cut for the full length definition: sum is a variable which can hold the

    value of an integer).

    The line int sum; is a variable definition. As well as giving information to

    the compiler about the name of the variable and its type, the compiler also

    allocates the memory corresponding to the variable.

    In C, a variable definition follows the pattern: type_of_data Variable_Name;

    The line sum=10+15; is a assignment statement. According to intuition, the

    value computed from the expression at the right of the sign = is stored in sum.

    = is called the assignment operatorin C

    The line printf("the sum of 10+15 is %d\n",sum); calls

    printf for the purpose of outputting information. Here, there are two

    arguments:

  • 8/3/2019 C Programming Lecture Notes 2008-09

    7/173

    7

    The first argument is the string of characters to be printed. The % indicates

    where the second argument is to be substituted, and in what form it is to be

    printed.

    Here %d means that the second argument is to be printed as an integer (d

    standing for digit).

    The second argument, sum, gives the value to be printed. When printf is

    called, the value stored in sum will be passed the function.

    This is an example of variable reference. Whenever a variable is encountered in

    an expression, the value it contains at that time is substituted in the expression.

    1.5 Basic Input/Output Operations in C

    Basic output is performed by printf. It is a general purpose function to print

    characters

    to the screen.

    Unlike most other functions, it has a variable number of arguments; a call to

    printf takes in general the following form:

    printf(format,val1,...,valn);

    format is a string of characters which is to be printed. It is composed of i)

    ordinary characters which are output directly to the screen and ii) conversion

    specifications.

    Each conversion specification begins with % and controls the way in which one

    of the subsequent arguments is converted into printable characters.

    val1 to valn are the arguments to be converted. There must be as many

    arguments as there are conversion specifications in the format string.

    Examples:

    printf("A string\n") output the message A string and starts a

    new line.

    printf("%d\n",sum) prints the value of the variable sum

    interpreted as an integer.

    printf("%d %f\n",a,b) prints the values of integer variable a

    and floating point variable b, separated by a space and followed by a

    new line. A more detailed description ofprintf is given later.

  • 8/3/2019 C Programming Lecture Notes 2008-09

    8/173

    8

    1.6 Example of a User Defined Function

    The following programme illustrates how a user-defined function can be written

    and employed in the C language.

    This program computes a generalisation of the square root:

    /* pre-processor directivenecessary when using the math library */

    #include

    double gen_sqrt(double); /* function prototype */

    /* main function */

    int main()

    {

    double val,sqroot; /* variables */

    /* ask the user to enter a real number */printf("Enter a floating point value > 0");

    /* get the value from the user */scanf("%lf",&val);

    /* call the function to compute the generalised square root */sqroot=gen_sqrt(val);

    /* print out the result */printf("The generalised square root of %lf is %lf\n",val,sqroot);

    return 0;

    }

    /* -- user-defined function gen_sqrt --*/

    double gen_sqrt(double x)

    {

    double result;

    if(x

  • 8/3/2019 C Programming Lecture Notes 2008-09

    9/173

    9

    2. Variables, Operators and Expressions

    2.1 Variable Types

    A variable is a symbolic name which the compiler associates with an area in

    memory where a value can be stored.

    The fundamental characteristic of a variable is the type of data which they hold.

    This is important because (i) different data types need different amounts of

    storage space and (ii) different data types are represented differently in binary

    form.

    A variable declaration specifies to the compiler: (i) the name of the variable, (ii)

    its type. In addition, the compiler allocates the necessary memory.

    Strictly speaking, this is really a variable definition. A variable declaration does

    not cause the compiler to allocate memory. However, in the common usage,

    declaration is used in both cases.

    A C declaration follows the pattern

    data_type variable name;

    C can handle variables of the following data types:

    characters (which are stored as integer values according to a code - for

    example the ASCII code):

    char c; declares a variable c of type character. A variable of type

    character only hold one character.

  • 8/3/2019 C Programming Lecture Notes 2008-09

    10/173

    10

    2.2 Variable Names

    One can also speak of a variable identifier

    Names are made of letters and digits. The first character must be a letter.

    The underscore _ is a letter so that names such as the_sum, _value, flag_

    are valid.

    It is best to avoid names starting with an underscore because these patterns are

    often used for library

    functions.

    Upper and lower cases are different and can be mixed. SUM, Sum and sum

    are all different names.

    Traditional C usage is that variables are in lower cases and constants in

    uppercases.

    Internal names are significant up to 31 characters.

    External names are guaranteed significant up to 6 characters by the standard

    and are single case.

    (This is due to the fact that external names have to be manipulated by linkers,

    assemblers and loaders over which the language has no control).

    In practice, external names can often have more than 6 significant characters.

    There is a list of reserved keywords which cannot be used as variable names:

    auto double int struct

    break else long switch

    case enum register typedef

    char extern return union

    const float short unsigned

    continue for signed void

    default goto sizeof volatile

    do if static while

  • 8/3/2019 C Programming Lecture Notes 2008-09

    11/173

    11

    2.3 More on Fundamental Data Types

    Important properties of a data type are:

    1. its size i.e. the number of bits that are used to

    store a value of this type

    2. its range i.e. the interval in which values can be

    represented by a variable of this type.

    C provides a range of fundamental data types (with different sizes and

    range) in order to suit the needs of the programmers.

    According to the basic type of data, types belong to one of three

    categories:

    1. Integral Types

    2. Character Integral Types

    3. Floating Point Types

    A character integral type can either be unsigned or signed.

    If a character variable is stored using 8 bits, as is usually the case, then

    if we have unsigned char x; can hold values

    between 0 and 255.

    if we have signed char x; can hold values

    between -128 and 127.

    The declaration char x; is in practice equivalent to signed char

    x;

    A integral type can also be either unsigned or signed, the default being

    signed.

    For integral types, There are also three different sizes available (that is

    the number of bits used to store the number):

    1) short int

    2) int

  • 8/3/2019 C Programming Lecture Notes 2008-09

    12/173

    12

    Examples :

    unsigned short int i;

    signed long int j;

    int can be omitted when used with either short, long, signed or unsigned.

    Thus:

    long i;

    is equivalent to

    signed long int i;

    Finally, there are two floating point types:

    1. float

    2. double for double precision numbers

    The C standard does not specify that a double is twice as precise as a

    float.

    The only guarantee is that the latter types in the list are at least as

    precise as those which precede.

    The actual size of these types is not specified by the standard. The

    following table shows the size for different platforms:

    Type PCDec MIPS

    (ULTRIX)

    Dec Alpha

    (OSF/1)

    Dec Alpha (OPEN VMS)

    char 1 1 1 1

    short int 2 2 2 2

    int 2 4 4 4

    long int 4 4 8 4

    float 4 4 8 4

    double 8 8 8 8

  • 8/3/2019 C Programming Lecture Notes 2008-09

    13/173

    13

    2.4 Constants

    There are four categories of constants in C:

    1. Integer Constants (such as 63, 0 and 42L)

    2. Floating-Point Constants (such as 1.2, 0.00,

    and 77E2+)

    3. Alpha-Numeric Constants (such as 'A' or

    "Hello!")

    4. Enumeration constants

    2.4.1 Floating-point constants

    The default type of a floating-point constant is double.

    An F or f is appended to the value, which specifies the float type for the

    floating point constant.

    Examples:

    Notation Value Type

    .0 0.000000 double

    0. 0.000000 double

    2. 2.000000 double

    2.5 2.500000 double

    2e1 20.00000 double2E1 20.00000 double

    2.E+1 20.00000 double

    2e+1 20.00000 double

    2e-1 0.200000 double

    2.5e4 25000.00 double

    2.5E+4 25000.00 double

    2.5F 2.500000 float

  • 8/3/2019 C Programming Lecture Notes 2008-09

    14/173

    14

    2.4.2 Alpha-Numerical Constants

    A character constant is any character from the character set enclosed in

    apostrophes.

    Note that characters are stored by the machine as (unsigned) integernumbers. The value associated with the character is machine dependent.

    Very often the ASCII code is used.

    The following piece of code is valid:

    char c;

    c='A';

    On a machine using the ASCII code, the value 65 (which is the ASCII

    code for A), is stored in c.

    Computers use not only printable characters (letters, digits, punctuation,

    etc.) but also non-printable characters such as the new-line character, the

    horizontal tab and the bell.

    These characters can be entered as escape sequences (which begin with

    a backslash '\')

    Non printable characters are:

    Character Escape sequence

    Alert (Bell) \a

    Backspace \b

    Form feed \f

    Newline \n

    Carriage Return \r

    Horizontal tab \t

    Vertical tab \v

    In addition, some printable characters have to be entered as escape

    sequences because they have a special meaning in the C syntax.

  • 8/3/2019 C Programming Lecture Notes 2008-09

    15/173

    15

    Example: char c='\n';

    A string constant or string literal is a sequence of characters enclosed by

    double quotes (").

    Escape sequences can be included in the string.

    Example of valid string constants are:

    "Hello world"

    "Hello world\n"

    "Ready ? \n Steady \n\t Go!\a\n"

    Unlike the FORTRAN read, C does not add a new-line character after a

    call to printf. The new line has to be given explicitly. Hence:

    printf("Hello ");

    printf("World");

    will produce the output

    Hello World

    But

    printf("Hello\n");

    printf("World");

    will produce the output

    Hello

    World

    and

    printf("Ready ? \n Steady \n\t Go!\a\n");

  • 8/3/2019 C Programming Lecture Notes 2008-09

    16/173

    16

    2.4.3 The const type modifier

    Some variables are meant to store constants. This is particularly true in

    the case of functions parameters.

    C provides a keyword, const, which informs the compiler that the

    value stored in a variable is constant and that any attempt by theprogrammer to modify this value is illegal.

    For example:

    const double pi=3.14159;

    2.5 Operators and Expressions

    An expression is a sequence of computing operations, to which aresulting value can be associated.

    C has a wider range of expressions than the usual mathematical and

    boolean expressions. For instance, a variable assignation such as:

    x=1.0;

    is an expression.

    The value associated with an assignation expression is the value storedin the variable, in this case, 1.0.

    An operator is "something'' which given some arguments (the operands)

    will produce a result.

    C has a very wide set of operators.

    C has unary operators which take only one argument, binary operators

    which take two arguments and even a ternary operator which need three

    arguments!

    2.5.1 Arithmetic operators

    The usual unary arithmetic operators are:

    - which gives the negative of the operand

    + which gives the value of the operand itself (not

    very useful)

  • 8/3/2019 C Programming Lecture Notes 2008-09

    17/173

    17

    2.5.2 Relational and Logical Operators

    The relational operators are >, >=,

  • 8/3/2019 C Programming Lecture Notes 2008-09

    18/173

    18

    2.5.3 Increment and Decrement Operators

    The increment operator ++ adds 1 to its operand.

    The decrement operator -- subtracts 1 from its operand.

    For example:

    int main()

    {

    int i=0;

    i++;

    printf("i: %d\n",i);

    return 0;

    }

    will produce the output: i : 1

    i++; is therefore equivalent to i=i+1;

    Similarly, i--; is equivalent to i=i-1;

    Both ++ and -- can either be prefix or postfix operators.

    In other words, i++, ++i, i-- and --i are all valid C expressions.

    However ++i is not equivalent to i++ although they both increment the

    value of i.

    With ++i, the value of the expression is the value of i after theincrementation is carried out.

    With i++, the value of the expression is the value of i before the

    incrementation is carried.

  • 8/3/2019 C Programming Lecture Notes 2008-09

    19/173

    19

    Consider the code:

    int main()

    {

    int i=0;

    printf("i: %d\n",++i);

    return 0;

    }

    It will produce the output i: 1 as in the last example because printf

    outputs the value of the expression ++i, which is the value ofi after

    incrementation.

    By contrast,

    int main()

    {

    int i=0;

    printf("i: %d\n",i++);return 0;

    }

    will produce the output i: 0 because the value ofi++ is the

    value ofi before incrementation.

    Another example:

    int main()

    {

    int i=0,j,k;

    j=++i;

    k=i++;

    printf("i: %d j: %d k: %d\n",i,j,k);

    return 0;

    }

  • 8/3/2019 C Programming Lecture Notes 2008-09

    20/173

    20

    3. Statements and Flow Control in C

    3.1 Concept of Statement in C

    A statement is either

    an expression followed by a semicolon;

    a construct which controls the flow of the program

    the so-called 'null' statement which consists of a single semicolon ;

    This statement provides a null operation in situations where the grammar of C

    requires a statement but the program requires no work to be done.

    A typical use of the null statement is in loops, as the following example shows:

    for(i=0;array[i]!=0;i++)

    This piece of code finds the first non zero element of array

    Most expressions are either assignments or function calls:

    i++;

    y=sqrt(x);

    printf("Hello World\ n");

    Note that i++, y=sqrt(x), printf("Hello World") are

    expressions. They only become statements when they are followed by a semi-

    colon.

    The semicolon in C is a statement terminator rather that a statement separator as

    in Pascal.

    Example of statement which control the flow of the programme are selection

    statements, e.g. the if then else construct, iteration statements, e.g. do

    while construct, or jump statements such as return or goto.

  • 8/3/2019 C Programming Lecture Notes 2008-09

    21/173

    21

    3.2 Compound Statements or Blocks

    A compound statement is a sequence of declarations and statements enclosed in

    braces:

    { }.

    This group of statements can then be treated syntaxically as a single statement.

    For example, the definition of the function gen_sqrt is a compound

    statement:

    double gen_sqrt(double x)

    {

    double result;

    if(x

  • 8/3/2019 C Programming Lecture Notes 2008-09

    22/173

    22

    The statement following the control expression is executed if the value of the

    control expression is true (nonzero).

    An if statement can be written with an optional else clause that is executed if

    the control expression is false (0).

    For example:

    if (i < 1)

    funct(i);

    else

    {

    i = x++;

    funct(i);

    }

    Here, if the value of i is less than 1, then the statement funct(i); is

    executed and the (compound) statement following the keyword else is not

    executed.

    If the value of i is not less than 1, then only the (compound) statement

    following the keyword else is executed.

    The syntax of the C language requires that the if and then clause be single

    statements. This is why a block has to be used when several statements are to be

    executed.

    The control expression in a selection statement is usually a logical expression,

    but it can be any expression of scalar type.

    Note: the statement

    if (expression)

    statement-1

    else

    statement-2

    is equivalent to

  • 8/3/2019 C Programming Lecture Notes 2008-09

    23/173

    23

    if (expression!=0)

    statement-1

    else

    statement-2

    When if statements are nested, an else clause matches the most recent if

    statement that does not have an else clause, and is in the same block.

    For example,

    if (i < 1)

    {

    if (j < 1)

    funct(j);

    if (k < 1) /*This if statement is associated*/funct(k);

    else /* with this else clause */

    funct(j + k);

    }

    Braces can be used to force the proper association:

    if (b < 3)

    {

    if (a > 3) b += 1;

    } else {

    b - = 1 ;

    }

    A common use of the if then else statement deals with multi-way decisions. The

    following construction is used:

    if (expression)

    statement

    else if (expression)

    statement

    [ else if (expression) statement ]

    [ else statement ]

  • 8/3/2019 C Programming Lecture Notes 2008-09

    24/173

    24

    The expressions are evaluated in order; if any expression is true, the statement

    associated with the expression is executed and this terminates the whole chain.

    The last else handles the "none of the above'' case. It can be used for error

    handling. It can also be omitted.

    3.3.2 The switch Statement

    The switch statement executes one or more of a series of cases, based on the

    value of a controlling expression.

    The switch statement has the following syntax:

    switch (expression)

    {

    case const-expression: statements

    [ case const-expression: statements ]

    [ default: statements ]

    }

    The switch statement is a multi-way decision statement where a singleexpression is evaluated.

    It the result matches one of a number of constants, a branching is performed to

    the statement associated with the constant.

    The case labelled default is executed if none of the other cases match. It is

    optional.

    case and default clauses can occur in any order.

    The usual arithmetic conversions are performed on the control expression, but

    the result must have an integral type.

    The constant expressions must have an integral type. No two case labels can

    specify the same value. There is no limit on the number of case labels in a

    switch statement.

    The following code is a very simple example showing how to use the switch

    statement for interfacing purposes.

    Depending on the value of a, functions action1 and action2 can be called

    or appropriate messages be displayed.

  • 8/3/2019 C Programming Lecture Notes 2008-09

    25/173

    25

    The break statement causes the programme to exit from the switch statement

    Without the break statements, each case would drop through to the next.

    It is possible to have several cases resulting in the same sequence of statements

    being executed:

    switch(a)

    {

    case 1: action1();

    break;

    case 2:

    case 3: action2();

    break;

    case 4: printf("Exit...\n");

    break;

    default: printf("Incorrect choice\n");

    break;

    }

  • 8/3/2019 C Programming Lecture Notes 2008-09

    26/173

    26

    The following example uses switch to count blanks, tabs, and newlines entered

    from the terminal:

    #include

    int main()

    {

    int number_tabs = 0;

    int number_lines = 0;

    int number_blanks = 0;

    int ch;

    while ((ch = getchar()) != EOF)

    switch (ch)

    {

    case '\t': ++number_tabs;

    break;

    case '\n': ++number_lines;

    break;

    case ' ' : ++number_blanks;

    break;

    default:;

    }

    printf("Blanks %d\n",number_blanks);

    printf("Tabs %d\n",number_tabs);

    printf("Newlines %d\n",number_lines);

    return 0;

    }

    Here a series of case statements is used to increment separate countersdepending on the character encountered.

  • 8/3/2019 C Programming Lecture Notes 2008-09

    27/173

    27

    3.4 Iteration Statements

    An iteration statement, or loop, repeatedly executes a statement, known as the

    loop body, until the controlling expression is false (0). The control expression

    must have scalar type.

    There are three different iteration statements:

    The while statement evaluates the control expression before executing the loop

    body.

    The do statement evaluates the control expression afterexecuting the loop

    body: at least one execution of the loop body is guaranteed.

    The for statement executes the loop body on the evaluation of the second ofthree expressions.

    3.4.1 The while Statement

    The while statement evaluates a control expression before each execution of the

    loop body. If the control expression is true (nonzero), the loop body is executed.

    If the control expression is false (0), the while statement terminates.

    The while statement has the following syntax:

    while (expression)

    statement

    For example:

    n = 0 ;while (n < 10)

    {

    a[n] = n;

    n++;

    }

    This statement tests the value of n; ifn is less than 10, it assigns n to the nth

    element of the array a and then increments n.

  • 8/3/2019 C Programming Lecture Notes 2008-09

    28/173

    28

    The control expression (in parentheses) is then evaluated; if true (nonzero), the

    loop body is executed again; if false (0), the while statement terminates.

    If the statement n++; were missing from the loop body, this while statement

    would not terminate. If the statement n = 0 ; were replaced by the statement n

    = 10;, the control expression is initially false (0), and the loop body is never

    executed.

    Another example is:

    while ( n < 1 000)

    {

    n *= 2;

    j += 1;

    }

    3.4.2 The do Statement

    The do statement evaluates the control expression aftereach execution of the

    loop body

    The do statement has the following syntax:

    do

    statement

    while (expression);

    The loop body is executed at least once.

    The control expression is evaluated after each execution of the loop body.

    If the control expression is true (nonzero), the statement is executed again. If

    the control expression is false (0), the do statement terminates.

  • 8/3/2019 C Programming Lecture Notes 2008-09

    29/173

    29

    For example:

    do

    {

    n * = 2 ;

    j + = 1 ;

    }

    While (n < 1000);

    Example: a typical use of the do statement is checking input data:

    do

    {

    printf("y/n?");

    scanf("%c",&c);

    }

    While((c!='y')&&(c!='n'));

  • 8/3/2019 C Programming Lecture Notes 2008-09

    30/173

    30

    3.4.3 The for Statement

    The for statement evaluates three expressions and executes the loop body until

    the second controlling expression evaluates to false (0).

    The for statement is useful for executing a loop body a specified number of

    times.

    The for statement has the following syntax:

    for ([expression-1];[expression-2];[expression-3])statement

    The for statement is equivalent to the following while loop:

    expression-1;

    while (expression-2){

    statement

    expression-3;

    }

    The for statement executes the loop body zero or more times.

    Semicolons (;) are used to separate the control expressions.

  • 8/3/2019 C Programming Lecture Notes 2008-09

    31/173

    31

    A for statement executes the following steps:

    1. Expression-1 is evaluated once before the first iteration of the

    loop. This expression usually specifies the initial values for variables

    used in the loop.

    2. Expression-2 is any scalar expression that determines whether to

    terminate the loop.

    3. Expression-2 is evaluated before each loop iteration. If the

    expression is true (nonzero), the loop body is executed. If the expression

    is false (0), execution of the for statement terminates.

    4. Expression-3 is evaluated after each iteration.

    The for statement executes until expression-2 is false (0), or until a jump

    statement, such as break or goto, terminates execution of the loop.

    Any of the three expressions in a for loop can be omitted:

    Ifexpression-2 is omitted, the test condition is always true; that is the

    while loop equivalent becomes while(1). This is an infinite loop.

    For example:

    for (i = 0; ;i++)

    statement;

    Infinite loops can be terminated with a break, return, or goto statement within

    the loop body.

    If either expression-1 or expression-3 is omitted from the for

    statement, the omitted expression is evaluated as a void expression and iseffectively dropped from the expansion.

  • 8/3/2019 C Programming Lecture Notes 2008-09

    32/173

    32

    For example:

    n = 1 ;

    for ( ; n < 10; n++)

    func(n);

    Here n is initialised before the for statement is executed.

    Infinite loops are often used in practice.

    For example:

    #include

    void action1();

    void action2();

    int main()

    {

    int a;

    for(;;)

    {printf("Enter a choice\n");

    printf("\t 1. Action 1\n");

    printf("\t 2. Action 2\n");

    printf("\t 3. Exit\n");

    scanf("%d",&a);

    switch(a)

    {

    case 1: action1();break;

    case 2: action2();

    break;

    case 3: printf("Exit...\n");

    return 0;

    default: printf("Incorect choice\n");

    }

    }

    return 0;

    }

  • 8/3/2019 C Programming Lecture Notes 2008-09

    33/173

    33

    /* ------ action routines ------ */

    void action1()

    {

    printf("This is the action1 routine\n");

    }

    void action2()

    {

    printf("This is the action2 routine\n");

    }

    3.5 Jump Statements

    Jump statements cause an unconditional jump to another statement elsewhere in

    the code.

    They tend to be used to interrupt switch statements and loops.

    The jump statements are:

    the goto statement,

    the continue statement,

    the break statement,

    the return statement.

    The break statement terminates execution of the immediately enclosing

    while, do, for or switch statement. Control passes to the statementfollowing the loop or switch body.

    The syntax for the break statement is

    break;

  • 8/3/2019 C Programming Lecture Notes 2008-09

    34/173

    34

    3.5.1 The return Statement

    The return statement terminates execution of a function and returns control

    to the calling function, with or without a return value.

    A function may contain a number of return statements.

    The return statement has the syntax

    return [expression];

    If present, the expression is evaluated and its value returned to the calling

    function.

    Very often, the expression is enclosed in brackets:

    return (0);

    A return statement with an expression cannot appear in a function whose

    return type is void.

    If there is no expression and the function is not defined as void, the return value

    is undefined.

    Reaching the closing brace that terminates a function is equivalent to executing

    a return statement without an expression.

    3.5.2 The continue Statement

    The continue statement passes control to the end of the immediately enclosing

    while, do or for statements. It has the following syntax:

    continue;

    The continue statement can be used only in loops.

    A continue inside a switch statement that is inside a loop causes continued

    execution of the enclosing loop after exiting from the body of the switch

    statement

  • 8/3/2019 C Programming Lecture Notes 2008-09

    35/173

    35

    3.5.3 The goto Statement

    The goto statement causes unconditional transfer of program control to a

    labelled statement.

    The label identifier is in the scope of the function containing the goto

    statement.

    The labelled statement is the next statement executed.

    The goto statement has the syntax

    goto identifier;

    The goto statement is redundant and dangerous.

    It is always possible to write equivalent code which does not use any goto

    statement.

    The equivalent code is often easier to write and usually easier to understand and

    easier to maintain because it is more structured.

    The only circumstances where a goto statement may be acceptable is the case

    of non-trivial error-handling, in a deeply nested code:

    for (...)

    {

    ...

    for (...)

    ...

    if (disaster)

    goto error;

    ...

    ...

    }

    ...

    error:

    /* error handling */

    return;

    In this example, the use of a goto statement enable a clean exit from both

    loops. Here, a break statement would not be sufficient because it would onlyexit from the inner-most loop.

  • 8/3/2019 C Programming Lecture Notes 2008-09

    36/173

    36

    4. Functions in C

    4.1 Basic Principles and Definitions

    A C program is a collection of user-defined and system-defined functions.

    Functions provide a useful way to break large computing tasks down into

    smaller ones which promotes the design of modular programmes that are easier

    to understand and maintain.

    A function contains statements to be executed when it is called, can be passed

    zero or more arguments, and can return a value.

    4.2 Function Calls

    A function call is an expression, usually consisting of a function identifier

    followed by parentheses used to invoke a function.

    The parentheses contain a (possibly empty) comma-separated list of

    expressions that are arguments to the function.

    For example, the following is a call to the function power (defined

    appropriately elsewhere):

    int main()

    {

    ...

    y = power(x,n); /* function call */

    ...

    return 0;

    }

    In this example, the value returned by the function power is assigned to the

    variable y.

    The calling function is also free to ignore the return value of the function.

    For example, printf is a function which returns an integer, (the number of

    character displayed). This return value is usually ignored as in

    int main()

    {

    printf("Ignored returned value\n");

    return 0;

    }

  • 8/3/2019 C Programming Lecture Notes 2008-09

    37/173

    37

    4.3 Function Types

    A function has the derived type function returning type.

    The type can be any data type except array types or function types, althoughpointers to arrays and functions can be returned.

    If the function returns no value, its type is function returning void', sometimes

    called a void function.

    A void function in C is equivalent to a procedure in Pascal, or a subroutine in

    FORTRAN.

    A non-void function in C is equivalent to a function in these other languages.

    It is very important for the compiler to know the type returned by any function

    the program uses.

    This information can be passed to the compiler through a function prototype.

    The simplest form of function prototype deals with the case when there is no

    argument.

    For example: we want to write a C function my_pi which returns the value of

    pi using the formula

    atan(1.0) = pi/4.

    A simple but complete C program defining and using my_pi is:

  • 8/3/2019 C Programming Lecture Notes 2008-09

    38/173

    38

    #include

    #include

    double my_pi();

    int main()

    {

    printf("Value of PI: %18.14f\n",my_pi());

    return 0;

    }

    double my_pi()

    {

    return (4.0*atan(1.0));

    }

    Execution gives the following output:

    Value of PI: 3.14159265358979

    The line: double my_pi();

    is the prototype for the function my_pi. It tells the compiler, before the

    function is used, that it is a function returning a double and taking no argument.

    The purpose of the line #include is to provide the compiler

    with the prototype for the function printf.

    The effect of this line is to include the file stdio.h in the source code

    processed by the compiler. stdio.h is a header file where the prototypes for

    the standard input/output functions are given.

    Similarly, the purpose of the line #include is to provide the

    compiler with the prototype for the function atan.

  • 8/3/2019 C Programming Lecture Notes 2008-09

    39/173

    39

    Example: declaration of a void function.

    #include

    void message();

    int main()

    {

    message();

    return 0;

    }

    void message()

    {

    printf("Hello World\n");

    }

    4.4 Parameters and Arguments

    C functions exchange information by means of parameters and arguments.

    The term parameter refers to any declaration within the parentheses following

    the function name in a function declaration or definition.

    The term argument refers to any expression within the parentheses of a function

    call.

    A synonym for argument is actual arguments

    A synonym for parameter is formal arguments

    Arguments are passed by value; that is, when a function is called, the parameter

    receives a copy of the corresponding argument's value, not its address as in

    other languages such as FORTRAN.

    This is a very important point. Its main consequence is that modifying a

    parameter does not modify the corresponding argument passed by the function

    call.

    Consider the FORTRAN program:

  • 8/3/2019 C Programming Lecture Notes 2008-09

    40/173

    40

    program VALUE

    integer i

    i=0

    call routine(i)

    write(*,'(A,I3)')'value of i in programme:',i

    end

    subroutine routine(i)

    integer i

    i=i+1

    write(*,'(A,I3)')'value of i in subroutine:',i

    return

    end

    This produces the following output:

    value of i in subroutine: 1

    value of i in program: 1

    Consider now the seemingly equivalent C program:

    #include

    void routine(int);

    int main()

    {

    int i;

    routine(i);

    printf("value of i in programme: %3d\n",i);

    return 0;

    }

    void routine(int i)

    {

    i=i+1;

    printf("value of i in subroutine: %3d\n",i);

    return;

    }

    This produces a different output:

  • 8/3/2019 C Programming Lecture Notes 2008-09

    41/173

    41

    value of i in routine: 1

    value of i in program: 0

    In the FORTRAN program, the modifications to the parameters are mirrored inthe arguments.

    In C, these modifications have no effect on the arguments.

    C nevertheless provides a mechanism whereby a function can modify a variable

    in a calling routine. This necessitates the use of pointers

    4.5 Function Definitions

    A function definition includes the code for the function.

    Function definitions can appear in any order, and in one source file or several.

    A function definition has the following syntax:

    return-type function-name(parameter declarations, if any){

    declarations

    statements

    }

    The type-specifier is the data type of the value returned by the function.

    If no return value is specified, the function is declared to return a value of type

    int.

    A function can return a value of any type except array of type' or function

    returning type'. Pointers to arrays and functions can be returned.

  • 8/3/2019 C Programming Lecture Notes 2008-09

    42/173

    42

    Consider the following definition of the function power

    int power(int base, int exp)

    {

    int n=1;

    if (exp < 0)

    {

    printf ("Error: negative exponent\n");

    return -1;

    }

    for ( ; exp; exp--) n = base * n;

    return n;

    }

    This function takes two integer parameters and returns an integer value

    The sequence power(int base, int exp) is called a function

    declarator.

    It specifies the name of the function as well as the name and type of the

    parameters.

    A function definition with no parameters is defined with an empty parameter

    list.

    An empty parameter list can be specified in two ways:

    1. Using the keyword void, if the prototype style is used. For example,

    char msg(void)

    {

    return 'a';

    }

    2. Using empty parentheses. For example:

    Char msg()

    {

    return 'a';

    }

  • 8/3/2019 C Programming Lecture Notes 2008-09

    43/173

    43

    4.6 Function Prototypes

    A function prototype is a function declaration that specifies the data types of

    the function parameters in the parameter list, as well as the return type of the

    function.

    The compiler uses the information in a function prototype to ensure that:

    1. the corresponding function definition and all corresponding function

    declarations and calls (within the scope of the prototype) contain the

    correct number of arguments or parameters,and that each argument or

    parameter is of the correct data type.

    2. the return value is consistent for all corresponding declarations as well

    as the definition.

    The function declaration used is the prototype style

    Prototype Style:

    Functions are declared explicitly with a prototype before they are called.

    Multiple declarations must be compatible; parameter types must agree

    exactly.

    Arguments to functions are converted to the declared types of theparameters.

    The number and type of arguments are checked against the prototype and

    must agree with or be convertible to the declared types.

    Empty parameter lists are designated using the void keyword.

    Ellipses ... are used in the parameter list of a prototype to indicate that a

    variable number of parameters are expected.

    Consider the following definition:

    char func(int lower, int *upper, char (*func)(), double y )

    {}

    The corresponding prototype declaration for this function is:

    char func(int lower, int *upper, char (*func)(), double y);

  • 8/3/2019 C Programming Lecture Notes 2008-09

    44/173

    44

    A prototype is identical to the header of its corresponding function definition

    specified in the prototype style, with the addition of a terminating semicolon (;) or

    comma (,) at the end, as appropriate (depending on whether the prototype is

    declared alone or in a multiple declaration).

    Function prototypes need not use the same parameter identifiers as in thecorresponding function definition because identifiers in a prototype only have

    scope within the identifier list.

    For example, the following prototype declarations are equivalent:

    char func(int lower, int *upper, char (*func)(), double y);

    char func(int a, int *b, char (*c)(), double d );

    char func(int, int *, char (*)(), double );

    The last example shows that identifiers themselves need not be specified in the

    prototype declaration

    4.7 Argument Conversion

    If a prototype is in scope, arguments are converted to the type of the

    corresponding parameters.

    If no prototype is in scope, integral types are converted to int, and floating

    point types are converted to double.

  • 8/3/2019 C Programming Lecture Notes 2008-09

    45/173

    45

    4.8 Recursive Functions

    A recursive function is a function is a function that is defined in terms of itself.

    It is also called a self-referential function.

    A recursive function in C is a function whose definition contains a call to the

    function itself.

    Perhaps the simplest example of a recursive function is that given by the

    factorial function:

    n! =

    1 if n>0

    n(n-1)! otherwise

    Here n! is defined in terms of (n-1)!. Note that when the function refers to itself,

    it uses an argument smaller than the one it was given.

    In addition the value of the function for the smallest argument is defined

    without self-reference, so that the function terminates.

    Recursive functions can be implemented directly in C. For example, the

    factorial function can be written as:

    if (n == 0)

    return 1;

    else

    return n * factorial(n-1);

    This is often called tail recursion, because the last statement contains a single

    recursive call.

    The important point is that sometimes the recursive divide and conquer

    approach provides a neater and more efficient solution to a problem than the

    iterative approach.

    Note that recursive functions have iterative equivalents; for the factorial

    function this is:

  • 8/3/2019 C Programming Lecture Notes 2008-09

    46/173

    46

    int factorial(int n)

    {

    if (n == 0)

    return 1;

    else

    {

    int i, fact = 1;

    for (i = 2; i

  • 8/3/2019 C Programming Lecture Notes 2008-09

    47/173

    47

    The idea behind recursive algorithms is to divide the original problem up into

    problems of smaller size.

    In general, recursive functions may divide the problem up into many sub-

    problems and make several recursive calls in the process of recombining the

    sub-problems, before generating the solution.

    This approach is often called divide and conquerand usually leads to much

    simpler solution of the problem than that taken by an iterative approach.

    A good example where a recursive approach is also more efficient is provided

    by the problem of simultaneously finding the maximum and minimum of an

    array of integers.

    The iterative solution can be written as follows:

    void minmax(int a[], int n, int *p_max, int *p_min)

    {

    int i;

    *p_max = *p_min = a[0];

    for (i = 1; i < n; i++)

    {if (a[i] > *p_max)

    *p_max = a[i];

    if (a[i] < *p_min)

    *p_min = a[i];

    }

    }

    The comparison count for this function is 2(n-1):

    since at each of the n-1 iterations of the loop, 2 comparisons are made.

  • 8/3/2019 C Programming Lecture Notes 2008-09

    48/173

    48

    The recursive approach can be summarised as follows:

    ifn =1

    min = max = a[0];

    ifn = 2 compare a[0] and a[1] and assign min the smallerand max the larger

    else

    divide the array in two, and recursively find

    the min and max of each half; assign min the

    smaller of the two min's, and max the larger

    of the two max's.

    The C implementation is:

    void minmax(int numberlist, int n, int *p_min, int *p_max){

    int min2, max2;

    if (n == 1)

    *p_min = *p_max = numberlist[0];

    else if (n == 2)

    {

    if (numberlist[0] < numberlist[1])

    {

    *p_min = numberlist[0];*p_min = numberlist[1];

    }

    else

    {

    *p_min = numberlist[1];

    *p_max = numberlist[0];

    }

    }

    else

    {minmax(numberlist, n/2, p_min, p_max);

    minmax(numberlist + n/2, n - (n/2), &min2, &max2);

    if (min2 < *p_min)

    *p_min = min2;

    if (max2 > *p_max)

    *p_max = max2;

    }

    }

    Although not obvious, this algorithm makes slightly less comparisons.

  • 8/3/2019 C Programming Lecture Notes 2008-09

    49/173

    49

    The Tower of Hanoi problem is another problem that can be solved recursively.

    In C, the solution is given by the following program:

    int main()

    {

    int n;

    printf("Input the number of disks: ");

    scanf("%d", &n);

    if (n

  • 8/3/2019 C Programming Lecture Notes 2008-09

    50/173

    50

    5. The C Preprocessor

    5.1 Concept of Preprocessor

    Preprocessing is the first step in the compilation process. It is optional.

    According to directives, the pre-processor modifies the source code before it is

    passed to the compiler proper.

    The C preprocessor provides the ability to perform macro substitution,

    conditional compilation, and the inclusion of named files.

    Preprocessor directives are lines beginning with #.

    5.2 Macro Definition (#define)

    The #define directive specifies a macro identifier and a replacement list, and

    terminates with a newline character.

    The replacement list, a sequence of preprocessing tokens, is substituted for

    every subsequent occurrence of that macro identifier in the program text, unless

    the identifier occurs inside a character constant, a comment, or a literal string.

    #define is often used to define constants or array sizes.

    For example:

    #define PI 3.14159

    #define TRUE 1

    #define FALSE 0

    #define NMAX 100

    int main()

    {

    double a[NMAX];

    ...

    return 0;

    }

  • 8/3/2019 C Programming Lecture Notes 2008-09

    51/173

    51

    The #undef directive is used to cancel a definition for a macro.

    A macro definition is independent of block structure, and is valid from the

    #define directive that defines it until either a corresponding #undef

    directive or the end of the compilation unit is encountered.

    The #define directive has the syntax: #define identifier replacement-list

    new-line

    #define identifier (identifier-list) replacement-list new-line

    The first form of the #define directive is called an object-like macro. The

    second form is called a function-like macro.

    The #undef directive has the following syntax:

    #undef identifier newline

    The replacement list in the macro definition, as well as arguments in a function-

    like macro reference, can contain other macro references.

    The following example shows nested #define directives:

    /* Show multiple substitutions and listing format.

    */

    #define AUTHOR james + LAST

    int main()

    {

    int writer,james,michener,joyce;

    #define LAST michener

    writer = AUTHOR;

    #undef LAST#define LAST joyce

    writer = AUTHOR;

    return 0;

    }

    After this example is compiled with the appropriate options to show

    intermediate macro expansions, the following listing results:

  • 8/3/2019 C Programming Lecture Notes 2008-09

    52/173

    52

    /* Show multiple substitutions and listing format.

    */

    #define AUTHOR james + LAST

    int main()

    {

    1 int writer, james, michener, joyce;

    2 #define LAST michener

    3 writer = AUTHOR;

    4 james + LAST

    5 michener

    6 #undef LAST

    7 #define LAST joyce

    8 writer = AUTHOR;

    9 james + LAST

    10 joyce

    return 0;

    }

    On the first pass, the compiler replaces the identifier AUTHOR with the

    replacement list james + LAST.

    On the second pass, the compiler replaces the identifier LAST with its currently

    defined replacement list value.

    At line 5, the replacement list value for LAST is the identifier michener,

    so michener is substituted at line 6.

    At line 7, the replacement list value for LAST is redefined to be the

    identifier joyce, so joyce is substituted at line 8.

    The #define directive can be continued on to subsequent lines if necessary.To do this, end each line to be continued with a backslash \ immediately

    followed by a newline character.

    The first character in the next line is logically adjacent to the character that

    immediately precedes the backslash.

  • 8/3/2019 C Programming Lecture Notes 2008-09

    53/173

    53

    5.3 Function-Like Form

    The function-like form of macro definition includes a list of parameters.

    References to such macros look like function calls.

    When a function is called, control passes from the program to the function at

    run time; when a macro is referenced, source code is inserted into the program

    at compile time. The parameters are replaced by the corresponding arguments,

    and the text is inserted into the program stream.

    Consequently, for small amount of computing work, macros are more efficient

    than functions because they do not have the overheads of argument passing.

    The library macro _trouper, available on some systems in the ctype.h header

    file, is a good example of macro replacement. The macro is defined as follows:

    #define _trouper(c) ((c) >= 'a' && (c)

  • 8/3/2019 C Programming Lecture Notes 2008-09

    54/173

    54

    Consider the following macro defining the square of an expression:

    #define SQUARE(A) A * A

    This implementation will give in wrong results for some expressions such as:

    y=SQUARE(x+1);

    which after macro expansion is interpreted by the compiler as

    y=x+1*x+1=2*x+1

    instead of:

    y=(x+1)*(x+1)

    The correct implementation of the SQUARE macro is:

    #define SQUARE(A) ((A)*(A))

    Similarly, unwanted side-effects can occur if the increment (++), decrement (--

    ), and assignment operators (such as +=) are used in macro invocation.

    For example:

    j=SQUARE(i++);

    will result in i being incremented twice; j will also be assigned a wrong

    value.

    The solution is obviously:

    i++;

    j=SQUARE(i);

  • 8/3/2019 C Programming Lecture Notes 2008-09

    55/173

  • 8/3/2019 C Programming Lecture Notes 2008-09

    56/173

    56

    6. Arrays

    6.1 Basic Definition and Arrays Declarations

    Arrays are a derived type because they are defined in terms of another type.

    Typically, arrays are used to perform operations on some homogeneous set of

    values.

    The declaration of an array follows the following pattern: completed-type

    identifier[[ const-size ]];

    Example:

    int a[10]; defines (i.e. declares and allocates corresponding storing

    space in memory) an array of 10 consecutive integer, identified by the

    name a

    double x[10],y[10]; defines two arrays, x and y, of 10 doubles

    each.

    In C, arrays of any completed type can be declared. These include:

    1. fundamental types

    2. pointers

    3. structures and union

    4. arrays

    A completed type is a type whose size is known from the compiler. The

    restriction that array have to be defined in term of a completed type arises

    because the compiler needs to know the size of an array element in order toaccess individual elements.

  • 8/3/2019 C Programming Lecture Notes 2008-09

    57/173

    57

    6.2 Referencing an Individual Array Element

    A particular element of an array is referenced using the [ ] notation.

    Given a declaration such as int a[10];, a[i] is an expression which value

    is the ith element of array a

    In C, arrays start at index 0. Given the declaration int a[SIZE];, elements

    a[0], a[1], ..., a[SIZE-1] are correct.

    For example: The following program displays the maximum value of an array

    of floating point values

    #include

    #define SIZE 10

    int main()

    {

    double a[SIZE];

    double max;

    int i,n;

    printf("Enter the number of values >");

    scanf("%d",&n);if ((n >SIZE)||(n

  • 8/3/2019 C Programming Lecture Notes 2008-09

    58/173

    58

    C is a very "lazy'' language. It does not check many things (unlike Pascal).

    There is no mechanism for checking that the index used for referencing an array

    element is within the bounds of the array.

    Given the declaration int a[SIZE];, expressions such as a[-1] or

    a[SIZE+100] are valid. The compiler assumes the programmer knows what

    he/she is doing!

    6.3 Incomplete Array Declarations

    Declarations such as int x[]; can be valid in C.

    Because the size of the array is unknown (at compilation time), this is referred

    to as an incomplete array declaration.

    The size of an array declared in this way must be specified elsewhere in the

    programme.

    This mechanism can be useful in the context of functions which deal with

    arrays.

    For example, if we want to write a function which computes the average of the

    values of an array, the size of the array is nothing more than a parameter which

    is important at run-time, not at compile time.

    The following function definition satisfies this constraint:

    double average(double a[],int n)

    {

    double sum,average;

    int i;

    sum=0.0;

    for(i=0;i

  • 8/3/2019 C Programming Lecture Notes 2008-09

    59/173

    59

    The corresponding main program is the following:

    #include

    #define SIZE 10

    double average(double [],int);

    int main()

    {

    double a[SIZE];

    int i,n;

    printf("Enter the number of values >");

    scanf("%d",&n);

    if ((n >SIZE)||(n

  • 8/3/2019 C Programming Lecture Notes 2008-09

    60/173

    60

    6.4 Multi-Dimensional Arrays

    An array in C has only one dimension.

    Multi-dimensional arrays can be created by declaring arrays of arrays.

    For example, the declaration:

    double a[NROW][NCOL];

    declares an NROW by NCOL matrix of double.

    Internally, because the [ ] operator has left to right associativity, the

    declaration is interpreted as:

    double (a[NCOL])[NROW];

    In other words, a is an one-dimensional array of NROW objects of type "array of

    NCOL doubles''.

    In memory, this result in the array being stored row after row. This is calledrow major order.

    For example: consider the declaration int a[2][3]; the elements are stored

    in memory in the following order:

    a[0][0], a[0][1], a[0][2], a[1][0], a[1][1]

    a[1][2]

    Note: FORTRAN uses the converse convention: the column major orderwhere

    multi-dimensional arrays are stored column by column.

    Given the declaration a[NROW][NCOL]; the expression a[i][j] has the

    value of the array element at the intersection of the ith

    row and the jth

    column.

    The order in which a multi-dimensional array is stored is important if anefficient code is to be written.

    It is common to have nested loop to access all the elements of the array

    successively. The correct looping order in C is

    for(i=0;i

  • 8/3/2019 C Programming Lecture Notes 2008-09

    61/173

    61

    By contrast, but for the same reasons, the correct order in FORTRAN is the

    reverse:

    do 10 j=1,ncol

    do 20 i=1,nrow

    call func(a(i,j))

    20 continue

    10 continue

  • 8/3/2019 C Programming Lecture Notes 2008-09

    62/173

    62

    7. Program Structure in C

    7.1 External Variables

    An internal variable is a variable which is defined within a function. Therefore,

    it cannot be used outside thatparticular function because it has no meaning

    everywhere else in the programme.

    By contrast, an external variable is a variable which is defined outside any

    function.

    Because they are defined outside any function, external variables are available

    to many functions.

    For example:

    double total;

    void add(double x)

    {

    total+=x;

    }

    void subtract(double x)

    {

    total-=x;

    }

    Here, both functions operate on the external variable total.

    External variables are useful when a set of functions operate on the same group

    of data.

    Because data is accessible to all the functions, argument lists are shorter.

    The typical example is the C implementation of a stack.

    External variables are nevertheless to be used with caution because they can

    yield unnecessary data dependencies causing a loss of generality in functions.

  • 8/3/2019 C Programming Lecture Notes 2008-09

    63/173

    63

    For example: functions

    void add2(double x,double *p_total)

    {

    *p_total+=x;

    }

    void subtract2(double x,double *p_total)

    {

    *p_total-=x;

    }

    are much more general than add and subtract because they are not restricted to

    operating on a single variable total.

    7.2 Storage Classes for Variables

    The storage class of a variable determines the lifetime of the variable.

    There are two storage classes:

    1.automatic variables

    2.static variables

    7.2.1 Automatic variables

    All the variable declarations we have been using so far have been automatic

    variables.

    An automatic variable is a variable that comes into existence only when the

    block within which they are declared is executed. They disappear when the

    block is exited.

    Consequently:

    1. an automatic variable can only be declared within a function/block, and

    more precisely, at the beginning of the block.

    2. an automatic variable is private to the function in which it is declared.

    3. an automatic variable does not retain its value from one call to the other.

    4. an automatic variable has to be initialised explicitly at each entry of the

    function (otherwise it will contain garbage).

  • 8/3/2019 C Programming Lecture Notes 2008-09

    64/173

    64

    Automatic variables are often allocated on the stack.

    An automatic variable is declared by using fundamental-type declarator;

    For example:

    int i;

    char char[10];

    Variables with block scope, i.e. variables that are declared at the beginning of a

    block have automatic storage class by default.

    7.2.2 Register Variables

    Registervariables are automatic variables. However, their declaration hint to

    the compiler that these variables will be often used.

    As a result, the compiler may assign them storage in one of the registers of the

    mp for faster access. However, this is not guaranteed.

    A register variable is declared in the following way:

    register fundamental-type declarator;

    It is not possible to apply the unary operator & to a register variable, whether or

    not it is actually stored in a register.

  • 8/3/2019 C Programming Lecture Notes 2008-09

    65/173

    65

    7.2.3 Static Variables

    Static variables are in existence throughout the duration of the programme.

    A static object can be declared anywhere a declaration may appear in the

    programme:

    1. inside a block, at the beginning of the block.

    2. anywhere outside of a block

    Static variables are declared using the static keyword:

    static fundamental-type declarator;

    static variables are initialised only once at the beginning of the programme. The

    initialisation expression must be a constant.

    If a static variable is not explicitly initialised, every arithmetic member of that

    object is initialised to 0 and every pointer member is initialised as a NULL

    pointer constant.

    By default, variables declared outside any block have the static storage class.

    Example : Consider the program: because a is auto while b is static:

    #include void func(int);

    int main()

    {

    int n=3;

    int i;

    for(i=1;i

  • 8/3/2019 C Programming Lecture Notes 2008-09

    66/173

  • 8/3/2019 C Programming Lecture Notes 2008-09

    67/173

    67

    7.3.1 Block Scope

    An identifier appearing within a block or in a parameter list of a function

    definition has block scope and is visible within the block, unless hidden by an

    inner block declaration.

    Block scope begins at the identifier declaration and ends at the closing brace }

    completing the block.

    Note: variables used in a block must be declared at the beginning of the block.

    Example:

    int func(void)

    {

    int i;

    double func2(void);

    ...

    }

    Both variable i and the prototype for function func2 have block scope.

    Example:

    int main()

    {

    int i=0;

    i++;

    if(1) /* always true */

    {

    int i=2;

    i++;

    printf("i at end of block 2: %d\n",i);

    }

    printf("i at end of block 1: %d\n",i);

    return 0;

    }

    This program will produce the output: i at end of block 2: 3i at end of block 1: 1

  • 8/3/2019 C Programming Lecture Notes 2008-09

    68/173

    68

    7.3.2 File Scope

    An identifier whose declaration is located outside any block or function

    parameter list has file scope.

    An identifier with file scope is visible from the declaration of the identifier tothe end of the compilation unit (i.e. the file being compiled), unless hidden by

    an inner block declaration.

    In the example below, the identifier off has file scope:

    int off = 5; /* Defines the integer identifier off. */int f(void); /* prototype for function f */int main ()

    {

    int on; /* Declares the integer identifier on. */

    o n = o f f + 1 ;

    /* Uses off, declared outside the function block

    of main. This point of the program is still

    within the active scope of off. */

    on=f();/* call to f is checked by the compiler becausethe prototype is in scope */

    if (on

  • 8/3/2019 C Programming Lecture Notes 2008-09

    69/173

    69

    7.3.3 Function Scope

    Only statement labels have function scope.

    An identifier with function scope is unique throughout the function in which it

    is declared.

    Labelled statements are used as targets for goto statements. They should

    therefore only very seldom used!

    Labelled statements are declared implicitly by their syntax: label : statement

    For example:

    int func1(int x,int y,int z)

    {

    label: x+=(x+y);

    if(x >1) goto label;

    }

    7.3.4 Function Prototype Scope

    An identifier that appears within a function prototype's list of parameter

    declarations has function prototype scope: the scope of this identifier begins at

    the identifier declaration and terminates at the end of the function prototype

    declaration list.

  • 8/3/2019 C Programming Lecture Notes 2008-09

    70/173

    70

    7.4 Linkage

    C was designed so that programs could easily be built by linking together

    groups of functions that had been compiled separately.

    Technically, a C programme is said to consist of one or several compilation

    units.

    A compilation unit is a file containing C source code that can be independently

    processed by the compiler.

    If we consider again the example of the generalised square root program and

    write the gen_sqrt function in a file gen_sqrt.c and the main function in

    a file tgen_sqrt.c, our program is made of two compilation units which can

    be compiled separately (for example, by typing the commands

    cc -c gen_sqrt.c

    cc -c tgen_sqrt.c

    on a UNIX system) and then linked together to build the executable file (forexample, by typing:

    cc -o tgen_sqrt tgen_sqrt.o gen_sqrt.o -lm

    on a UNIX system - note that -lm includes the math library; this has to be done

    explicitly on a UNIX system. However, it is done implicitly on most othersystems)

    The fact that a program can be made of several compilation units means that

    there is a need for the compiler to distinguish between internal and external

    objects: this is called the linkage of the object.

    The linkage is a property of both static variables and functions.

  • 8/3/2019 C Programming Lecture Notes 2008-09

    71/173

    71

    7.4.1 Linkage for variables

    Linkage properties only make sense for static variables. Since automatic

    variables are private to a function, linkage issues do not arise.

    A static variable with external linkage can be referenced by other compilationunits (provided it is in scope).

    A variable with internal linkage can only be referenced within the compilation

    unit (provided it is in scope).

    external variables, i.e. variables defined outside any function, have external

    linkage by default.

    A static variable can be given internal linkage by using the keyword static:

    static type identifier;

    Example: total has external linkage and can be referenced by other compilation

    units:

    double total;

    void add(double x)

    {

    total+=x;

    }

    void subtract(double x)

    {

    total-=x;

    }

    Example: total has internal linkage and cannot be referenced by other

    compilation units:

    static double total;

    void add(double x)

    {

    total+=x;

    }

    void subtract(double x)

    {

    total-=x;}

  • 8/3/2019 C Programming Lecture Notes 2008-09

    72/173

    72

    Internal linkage provides added data security. In a self-contained application

    such as a stack, it ensures that other routines are not allowed to tamper with the

    data manipulated by the group of functions in the compilation unit.

    7.5 Variable Declaration and Variable Definition

    A variable cannot be referenced within a compilation unit unless it is in scope,

    i.e. it has to be declared.

    The declaration of variables with external linkage raises some issues. Consider

    for example the following code split into two compilation units:

    /* compilation unit 1 */

    double var;

    void func1()

    {

    ...

    var=...;...

    }

    and

    /* compilation unit 2 */

    double var;

    void func2()

    {

    ...

    func3(var);

    ...

    }

  • 8/3/2019 C Programming Lecture Notes 2008-09

    73/173

    73

    These functions are intended to manipulate the same variable var. In fact, this is

    a wrong implementation. var will be associated with a different address in

    memory in each compilation unit because it is defined twice.

    When a variable is defined, it is not only in scope so that it can be referenced

    but it is also allocated storing space.

    Consider the correct implementation:

    /* compilation unit 1 */

    double var;

    void func1()

    {

    ...

    var=...;

    ...

    }

    and

    /* compilation unit 2 */

    extern double var;

    void func2()

    {

    ...

    func3(var);

    ...

    }

    Here, func1 and func2 correctly manipulate the same variable var.

    This is because we have:

    1. a variable definition in the first compilation unit (line double

    var;)

    2. a variable declaration in the second compilation unit (line extern

    double var;)

  • 8/3/2019 C Programming Lecture Notes 2008-09

    74/173

    74

    A variable declaration puts the variable in scope but does not allocate storing

    space for it.

    The keyword extern informs the compiler that the variable declared is defined

    elsewhere. Its syntax is: extern type list-of-declarators;

    Because storing space is not allocated, incomplete type are allowed in variable

    declarations.

    For example:

    /* compilation unit 1 */

    double a[10]; /* definition */

    void func1()

    {

    ...

    var=...;

    ...

    }

    and

    /* compilation unit 2 */

    extern a[]; /* declaration */

    void func2()

    {

    ...func3(var);

    ...

    }

    Every variable with external linkage must be defined only once and declared in

    all other units.

  • 8/3/2019 C Programming Lecture Notes 2008-09

    75/173

    75

    7.5 Linkage of Functions

    Like static variables, functions have external linkage by default: they can be

    called within any compilation unit which makes the program.

    A function can be given internal linkage, i.e. it can only be called within thecompilation unit by using the keyword static:

    The syntax for the definition of an function with internal scope is:

    static type function-designator function-body;

    It should also be prototyped in the following way: static type function-

    designator;

    Functions with internal linkage are useful to protect internal functions (i.e. lowlevel functions used by higher level functions within the compilation unit) from

    outside functions.

    Note that the distinction between definition and declaration exists also for

    function. A prototype is a function declaration.

    This is why the extern keyword can be used with function prototypes to inform

    the compiler that the function is defined in another compilation unit.

    For example: consider the two compilation units:

    /* compilation unit 1 */

    double func1(void)

    {

    ...

    }

    and

    /* compilation unit 2 */

    extern double func1(void);

    int main()

    {

    ...

    }

    extern is, however, optional for function declarations.

  • 8/3/2019 C Programming Lecture Notes 2008-09

    76/173

    76

    7.6 Header Files

    A header file is a file which contains information that has to be shared by

    several source files.

    Header files typically contains:

    1. function prototypes

    2. constants (macro) definitions

    3. type definitions

    4. global variables

    They are included into the compilation stream by the pre-processor directive#include

    The C has the following standard header files:

    locale.h>

    It is good programming practice to create header files because they are a

    convenient and safe way to insure uniform declarations of global objects for all

    the files which make up a particular applications.

  • 8/3/2019 C Programming Lecture Notes 2008-09

    77/173

    77

    8. Pointers

    8.1 Concept of Pointers: Pointers and Addresses

    A pointer is a variable which contains the address of another variable (it points'

    to another variable).

    Note that a pointer is a variable. In other words, it is a portion of memory

    where the address of another memory cell can be stored.

    For example: the 6501 mp can manage up to 64K-bytes of memory. Addresses

    are integer numbers between 0 and 0xFFFF (in hexadecimal notation). An

    address needs two bytes to be stored. On a 6501-based machine, a pointer

    variable will be a group of two continuous bytes in which any address can be

    stored.

    In the following example, p is a pointer variable that points' to the variable

    letter (which contains the character 'A').

    On a typical PC, a char is stored in 1 byte and a pointer needs 2 bytes.

    This example is expressed in C in the following way

    char letter='A';

    char *p;

    p = &letter;

    Line 1 contains a variable declaration: letter is a variable of type char

    Line 2 is also a variable declaration: it declares p as a pointer to a char.

    Finally, in line 3, p is assigned with the address of letter

    If we suppose that on a particular machine, with a particular compiler, the

    variable letter is associated with the address 0xFF0, the pointer p will contain

    the value 0xFFF0

  • 8/3/2019 C Programming Lecture Notes 2008-09

    78/173

    78

    8.2 Declaration of Pointer Variables

    The pointer type is a derived type. A pointer variable points to variable of a

    particular type.

    For reasons that will become clear later, it is important that the compiler knowsthe size of the object pointed to by a pointer.

    However, whatever the object it points to, a pointer is always the same size

    because it always contains the

    same thing: an address.

    Pointer declarations follow the pattern: type *variable-name;

    8.3 The & Operator

    The address of letter is determined by using the & operator. This returns a

    pointer value that can be assigned to a pointer variable or used as a parameter.

    A good example is the library function scanf:

    scanf("%d, &x);

    Here scanf is given the address ofx as its second argument, so that it can

    place the value it reads at that address.

    Using the & argument with scanf is an example of how pointers can be used tohave function calls by reference in a C programme instead of function calls by

    value which is the default.

    8.4 The * Operator

    To access the memory location to which a pointer variable "points'', the * prefix

    operator is used on the pointer. For example:

    *p = 'B';

    This C statement stores the code for character 'B' at the address given by the

    pointer p, i.e. at the memory location pointed to by p.

    The * operator is also called the dereferencing or indirection operator.

    One way of defining the * operator is to interpret it as the instruction follow the

    arrow'. Then *p' can be thought of as follow the arrow stored in p'.

  • 8/3/2019 C Programming Lecture Notes 2008-09

    79/173

    79

    If, before the statement *p='B'; there is a statement such as

    p=&letter;

    *p and letter then refer to the same contents of the same memory

    location.

    Hence, the statement *p='B'; is rigorously equivalent to letter='B';.

    *p and letter are not merely equal, but refer to the same physical object in the

    computer's memory.

    Hence, changing the value of*p alters the value of letter as the following

    example shows:

    #include

    int main()

    {

    char letter, *p;

    letter='A';

    printf("letter before: %c\n",letter);

    p=&letter

    *p='B';

    printf("letter after: %c\n",letter);

    return 0;

    }

    The output of the programme is the following:

    letter before: Aletter after: B

    This is one reason why it is necessary to declare pointer variables as pointers to

    a particular type. When a reference to *p is made, the computer then knows

    what kind of data to expect.

  • 8/3/2019 C Programming Lecture Notes 2008-09

    80/173

    80

    Another example:

    int main()

    {

    char letter, *p;

    char character;

    p = &letter

    letter = 'A';

    printf("letter=%c,*p=%c\n",letter,*p);

    *p = 'B';

    printf("letter=%c,*p=%c\n",letter,*p);

    p = &character

    *p = 'Z';

    printf("letter=%c,*p=%c,character=%c\n",letter,

    *p,character);

    return 0;

    }

    The output of the program is

    letter=A,*p=Aletter=B,*p=B

    letter=B,*p=Z,character=Z

    8.5 Pointers to Pointers and Pointer Casting

    Because pointers are "normal'' variables, it is possible to have pointers to

    pointers.

    For instance: double **a; declares a as a pointer to a pointer to a double.

    This construction is very useful in C and will be used later.

    It is also possible to cast a pointer of a certain type into a pointer to another

    type.

    For example:

    char *charpt;

    int *intpt;

    intpt=(int *)charpt;

  • 8/3/2019 C Programming Lecture Notes 2008-09

    81/173

    81

    8.6 Pointers and Function Arguments: Difficulties with calls by value

    When a function is called, memory space for the declared parameters is

    allocated, and the values of the arguments are copied into that space.

    This form of parameter passing is known as call by value.

    Memory space is then allocated for the local variables used in the function, and

    execution begins.

    The fact that the values of the arguments are copied into the space used by the

    parameters means that a function cannot alter the argument values used in the

    calling routine.

    When a function finishes execution, all its parameters are destroyed and their

    memory space returned to the available memory pool.

    For example, the following swap program does not work as intended:

    #include

    void swap(int,int);

    int main()

    {int x, y;

    x = 0 ;

    y = 1 ;

    printf("in main before swap: x = %d, y=%d\n", x, y);

    swap(x, y);

    printf("in main after swap: x = %d, y=%d\n", x, y);

    return 0;

    }

    void swap(int x,int y)

    {

    int temp;

    printf("in swap at start, x = %d and y = %d\n", x, y);

    temp = x;

    x = y ;

    y = temp;

    printf("in swap at end, x = %d and y = %d\n", x, y);

    }

  • 8/3/2019 C Programming Lecture Notes 2008-09

    82/173

    82

    Values are swapped in the function but not in the main program:

    in main before swap: x = 0, y=1

    in swap at start, x = 0 and y = 1

    i n s w a p a t e n d , x = 1 a n d y = 0

    in main after swap: x = 0, y=1

    This is because parameter and arguments refer to different variables; swap only

    swaps copies of the arguments.

    8.7 Use of Pointers to Implement Call by Reference

    It is possible for a function to modify a variable if a pointer to that variable is

    passed to it.

    It is thus possible to write a new swap2 of the swapping subroutine that will

    work properly:

    #include

    void swap2(int *,int *);

    int main()

    {

    int x, y;

    x = 0 ;

    y = 1 ;printf("in main before swap: x = %d, y=%d\n", x, y);

    swap2(&x, &y);

    printf("in main after swap: x = %d, y=%d\n", x, y);

    return 0;

    }

    void swap2(int *p_x, int *p_y)

    {int temp;

    printf("in swap at start,x=%d and y=%d\n",*p_x,*p_y);

    temp = *p_x;

    *p_x = *p_y;

    *p_y = temp;

    printf("in swap at end, x=%d and y=%d\n",*p_x,*p_y);

    }

  • 8/3/2019 C Programming Lecture Notes 2008-09

    83/173

    83

    Instead of passing x and y, the addresses ofx and y are passed. These are

    copied into the pointerparameters p_x and p_y used by swap2.

    As a result, p_x and p_y will point to x and y.

    The situation at the start of swap2 can be represented in the following way:

    Within the function swap2, the expressions *p_x and *p_y refer the function

    arguments themselves, not copies.

    This is why the lines:

    *p_x = *p_y;

    *p_y = temp;

    are modifying the arguments x and y themselves.

    The results, this time, are correct:

    in main before swap: x = 0, y=1

    in swap at start, x = 0 and y = 1

    in swap at end, x = 1 and y = 0

    in main after swap: x = 1, y=0

    8.8 Using Pointers for "Returning'' Function Results

    Since the return statement can only return one value, pointers can be used as

    parameters when a function computes two or more values, which it needs to

    communicate to the calling function.

    When a pointer is used, the function does not, strictly speaking, return a value:rather it is abl