Escolar Documentos
Profissional Documentos
Cultura Documentos
SE2B2
by
Dr Virginie F. Ruiz
Department of Cybernetics
room 184,
E-mail: V.F.Ruiz@reading.ac.uk
VFR October 03 SE2B2 Further Computer Systems
Notes on C programming 1
VFR October 03 SE2B2 Further Computer Systems
The C programming language was developed in the early 1970s at the Bell
Introduction Laboratories. It became the primary language for the UNIX operating system. It
This course will cover an introduction to programming in C. The programming spread in popularity and is now available on most computers, not just those using
environment used is MS Visual C++. If you develop your programs using another UNIX. There is an ANSI (American National Standards Institute) standard for the
environment please make sure that you can run it under Visual C++ version that is C programming language, which is used to ensure that C code, is portable between
available in the School. computers.
The programming language C++ was originally developed in the 1980s to support
Assessed Work the development of large software projects, including those using object oriented
methods. The name signifies the evolution from C; the increment operator "++"
There will be an assignment. The source listing, testing and written report will need signifies that the new language is the old one with additions; indeed C++ is a
to be handed in, early in term. superset of C (there are a few exceptions). There is now an ANSI standard for C++.
There are many compilers and environments available for turning C and C++
Topics programs into executable programs. These range from the simplistic to the
The following topics will be covered during the course of lectures: supportive. The most simple systems require the programmer to use a text editor to
enter all the code, the code is written to an appropriately name file, compiled, then
• Overview of a program linked to necessary libraries and execution of the code can then follow. The user
• Input and output corrects mistakes returning to the editor. More supportive environments tend to be
• Types and operators integrated, with some automatic generation of code; the available libraries may be
• Selection very extensive.
• Iteration
Comparing the above description with Delphi is a useful exercise. The base level of
• Functions
Delphi is Pascal. C and Pascal share common roots on the Algol family of
• Arrays languages, these will become obvious as C is studied in more detail. Object Pascal
• Strings is Borland's extensions to Pascal that allow object-oriented programming. In much
• Pointers the same way C++ is an extension to C. The Delphi IDE (Interactive Development
• Files Environment) is the usual way in which Delphi programmers develop both Pascal
• Structures and Object Pascal programs. There are many environments available to the C and
Programming is best learnt by writing programs, so it is suggested that you try to C++ programmer to develop their programs. As C and C++ are used in a variety of
create simple programs that exercise the constructs that are discussed. environments the examples presented here will not rely on a particular
environment, instead they will focus on the code.
The C programming language is very powerful. It provides ready access to program
Acknowledgements memory. This is both a strength and a weakness. Delphi programmers are used to
Thanks to Shirley Williams who kindly gave me some her material to help me with the compiler catching silly errors, often made as a result of mistyping, the danger
this course. with C is that these errors will be syntactically correct but will cause a run time
error. Therefore, the Delphi programmer must be careful to remember that C is a
weakly typed language and does not provide the compile time checking that is a
feature of the more strongly typed Pascal.
Notes on C programming 2
VFR October 03 SE2B2 Further Computer Systems
program PDelf1;
{ A Delphi program illustrating comments, simple IO, Delimiters
constants, libraries } Pascal programs must begin with the key word program and end with a full stop.
uses WinCrt; There is no direct equivalent in C, however, all programs must have a function
const MyChoice=7; main.
var MyNumber, YourNumber: Integer;
In Pascal compound statements, as well as, bodies of procedures are delimited
begin
using begin and end; the equivalent in C is that an open curly brace { marks the
WriteLn('Hello');
start and is matched at the end by a }.
MyNumber:=MyChoice;
WriteLn(MyNumber,' is my lucky number'); Strings in Pascal are delimited by single quotes. While in C they are marked by
Write ('What is yours? '); double quotes.
Read(YourNumber);
Write(YourNumber,' is your lucky number');
end.
Main
All C programs consist of one or more functions. There must always be a function
The equivalent in C is: called main. The name main is not a reserved word, but it can cause confusion for
the compiler if it is declared.
/* A C program illustrating comments, simple IO,
constants, libraries */ If compiling with full type checking with a compiler such as gcc, there will be
#include <stdio.h>
errors unless the programmer specifically indicates that main takes no parameters
and does not return anything. This is done using void as in the example.
#define MYCHOICE 7
Programmers and books don’t always do this and the line:
void main(void)
{ void main(void)
int MyNumber,YourNumber;
printf("Hello\n"); could be replaced by
MyNumber = MYCHOICE;
main( )
printf("%5d is my lucky number\n",MyNumber);
printf("What's yours?\n");
Functions will be discussed in more detail later.
scanf("%d",&YourNumber);
printf("%5d is your lucky number\n", YourNumber);
} Libraries
In Delphi programs, libraries are included by listing them in a uses statement. A
These two programs will be used to highlight the similarities and differences similar effect is obtained in C by the use of #include.
between C and Pascal.
The Delphi example includes the line:
Notes on C programming 3
VFR October 03 SE2B2 Further Computer Systems
which tells the environment to generate a console window. Later versions of Delphi Pascal dictates that declarations occur outside the block. So the definitions of both
do not use the library, instead they have a compiler directive: variables and constants occur before the begin of a program or procedure block.
With C, the declaration of variables and constants take place inside the block. The
{$AppType Console} whole program can be considered to be a block, as well as individual conditionals
and loops. The format is also different.
that brings up the console window.
The line:
The C version does not need to specify the use of a console, as the default with C
programs is that they run in a console-like window. #define MYCHOICE 7
The WriteLn procedure is in the Delphi library unit System. Delphi programmers
is not a definition of a constant, it is in fact a macro definition. At compile time,
do not need to include System in a uses statement as it is always available. Other
all occurrences of MYCHOICE will be replaced by the number 7. A constant
libraries such as SysUtils and Forms do need to be specifically included and are
definition equivalent in C would be:
often seen in Delphi units:
const int MyChoice = 7;
uses SysUtils, Forms;
This could occur anywhere that a variable declaration could occur.
The C routines used in the example for reading and writing are scanf and printf,
these are from the stdio library which is included in the program by the statement:
#include <stdio.h>
Assignment
In Pascal, the assignment statement uses the := operator. In C assignment is an
The call to printf is more complicated than the Pascal Write. Consider the line: expression that returns a value. So the line:
printf("%5d is my lucky number\n",MyNumber);
MyNumber = MYCHOICE;
The %5d is a format specifier: it dictates that the value of the first parameter after
this string should be printed using up to 5 digits as an integer number. Leading copies the value of MYCHOICE into MyNumber and returns true to indicate that
blanks will be printed if the number is smaller. The d indicates decimal. The the assignment has successfully occurred. A common mistake made by Pascal
number is printed in the string at the position where the format specifier is. programmers when first using C is to use the assignment operator = when they
mean to use the equivalence operator ==, this is syntactically correct but rarely
The back slash is used with another character to represent a control character. The does what is required - so take care.
combination \n represents the newline character. So the string will be displayed
followed by a newline.
The line: Semicolons
The use of semicolons looks the same in both languages. However, Pascal uses a
scanf("%d",&YourNumber); semicolon to terminate declarations and to separate statements. Whereas C uses
semicolons to mark the end of an expression, so that, the expression becomes a
cause a value to be read. The format specifier %d indicates an integer is to be read. statement.
The & indicates that this is a reference to the variable YourNumber, indicating the
location where the value read must be stored. The & operator is necessary because
C does not have variable parameters, and this can be overcome by passing a Case Sensitive
reference to a variable rather than the variable itself, this issue will be addressed in Pascal is not case sensitive. A variable such as MYNUMBER can be written as
more detail later on. MyNumber, mynumber or in any mixture of upper and lower case.
C is case sensitive. The variable MyNumber is not the same as MYNUMBER.
Definitions When the compiler throws up a warning that a variable is not declared it is always
Notes on C programming 4
VFR October 03 SE2B2 Further Computer Systems
wise to check that there is not a mismatch between the case used in the declaration A declaration associates a group of identifiers with a specific data type. All
and that used in an expression. variables must be declared before they can be used. Unlike Pascal, there is no
special place in which variables need to be declared.
Consider this declaration:
TYPES AND OPERATORS int MyNumber=7,YourNumber;
Notes on C programming 5
VFR October 03 SE2B2 Further Computer Systems
When a compound operation is used, there must not be any space between the < Less than <
operators. > Greater than >
<= Less than or equal to <=
>= Greater than or equal to >=
Arithmetic Operators
There are five arithmetic operators in C. Unary Operators
Operator Description Example A unary operator acts upon a single operand to produce a new value.
+ add 2 + 3 same as Pascal
- subtract Number - 1 same as Pascal
* multiply density_1*2.5 same as Pascal Unary Minus
/ division density_1/density_2 same as Pascal The most well known unary operator is minus, where a minus sign precedes a
% remainder after Number % 2 same as mod in constant, variable or expression.
integer division Pascal
In Pascal, constants can be negative. In C, all numeric constants are positive.
Therefore, in C, a negative number is actually a positive constant preceded by a
The weak typing of C supports the mixing of operands of differing types. Operands unary minus, for example:
may undergo type conversion before an expression takes on its final value. The
general rule is that the final result will be in the highest precision possible given the -3
data types of the operands. The logical not operator is also frequently used. It is written as an explanation mark
! and is the same as NOT in Pascal. C also offers a bitwise not operator,
When an arithmetic expression is assigned to a variable, there are two expressions exchanging 0s and 1s in the binary representation. This operator is represented by
an arithmetic expression and an assignment. Consider:
the tilde symbol ~.
X = Y + Z;
First Y and Z are added, the result will be in the same precision as the highest Increment and Decrement
precision of Y and Z. This result will be then cast (converted) into the precision of C has unary operators for both increment and decrement. They work in the same
X and the assignment will occur. The assignment will return a result of 1 to manner as the Inc and Dec procedures in Pascal.
indicate success, but this is rarely used. The expression becomes a statement
because it is terminated with a semicolon. Operator Description Example Pascal equivalent
++ increment x++; inc(x);
++y; inc(y)
Logical and Equality Operators -- decrement x--; dec(x);
--y; dec(y)
There are two logical operators in C. These both in the same way as the equivalent
in Pascal. They are:
These operators can also be used within expressions, most commonly they are seen
&& AND in the control of loops. If the increment operator appears first it means increment
|| OR the value and then use it in the expression. If the operand appears first it means, use
the current value in the expression and then increment the value.
There are six equality operators, all working in the same way as the Pascal
equivalent.
Unary Pointer Operators
C Operator Description Pascal equivalent There are two unary operators used with pointers, these are similar to their
== Equal to = equivalents in Object Pascal, there is no equivalent to the address of operator in
!= Not equal to <> standard Pascal.
Notes on C programming 6
VFR October 03 SE2B2 Further Computer Systems
int *CIndex; There must not be a space between the minus and the greater than symbols.
Notes on C programming 7
VFR October 03 SE2B2 Further Computer Systems
This will loop until the user types something other than a 7. if statement
If the final expression is replaced by: The general format of an if statement in C is:
(n=7) if (test)
statement;
Regardless what the user types n will be set to 7. The expression returns true each
time it executes and so the program will loop infinitely. The statement (or compound statement) can be followed by an else clause.
Notes on C programming 8
VFR October 03 SE2B2 Further Computer Systems
Notes on C programming 9
VFR October 03 SE2B2 Further Computer Systems
Notes on C programming 10
VFR October 03 SE2B2 Further Computer Systems
completion, fopen returns a pointer to the newly opened stream. In the event of
error, it returns NULL. It is wise always to check this before attempting to use the In C strings are delimited by double quotes, while individual characters use single
file. The programmer should always close files that could be open, when they are quotes.
finished with.
There is a standard C library <string.h> that contains a number of useful string
operations. For example the string compare function, can be considered to have the
Generating a Pointer to an Array prototype:
A pointer to the first element of an array is generated by specifying the array name, int strcmp(s1, s2);
without any index.
So given the definition: This returns a negative number if s1<s2, 0 if they are equal and a positive number if
s1>s2.
int *PtrToSquare;
it is possible to assign in this manner; The programmer should be careful in using this function in conditional statements
such as:
PtrToSquare = square;
Following this assignment, the following statements all read values into the first
if strcmp(s1,s2)
element of square:
{
scanf("%d",PtrToSquare); dosomething()
scanf("%d",&square[0]); }
scanf("%d",square); else
{
More on pointers and arrays later. somethingelse()
}
Strings If s1 and s2 are equal, strcmp returns 0, which will be interpreted as false and
Arrays of characters are used to hold strings. Consider the declaration: somethingelse will be executed.
char AStr[11]; Other frequently used string functions are described in the table below:
this can hold a 10-character string, the eleventh character (AStr[10]) holds null (the strcat(s1,s2 ) concatenates the second string to the first
character written as: \0). int strcmpi(s1,s2) compares two strings, without case sensitivity
strcpy(s1,s2) copy a string to the target string
Strings can be initialised when they are declared: strstr(s1,s2) scan a string for the first occurrence of a substring
char BStr[11] = "Hello"; int strlen(s1) returns the length of a string
It is unnecessary for the programmer to enter the null character, as C adds it The prototypes are not strictly correct, but give an indication of the parameters.
automatically, in this example as character BStr[5]. The string can be subsequently
changed, it can hold a maximum of 10 characters.
Multidimensional Arrays
When a string is initialised and its value is unlikely to change, the programmer
A two dimensional array for storing the hours of sunshine can be declared as:
need not explicitly calculate the number of characters, as in the following example:
int suns [12][31];
char CStr[ ] = "Hello this is an example of a string.";
Notes on C programming 11
VFR October 03 SE2B2 Further Computer Systems
Notes on C programming 12
VFR October 03 SE2B2 Further Computer Systems
Dynamic memory allocation when numbers is pointing beyond the space that was requested will result in an
The above pointers have used static memory and pointer manipulation on access violation.
previously declared arrays. Pointers are often used in association with dynamic
memory allocation. The use is similar to that in Pascal.
There are a number of functions associated with the allocation and freeing of
dynamic memory. These are found in the library stdlib.h. Most commonly used are FUNCTIONS
malloc and free, which can be closely matched to new and dispose in Pascal.
1: int *numbers; In C, functions are sections of code, separate from the main program that performs
2: printf("How many?\n"); a well-defined action. C uses functions where Pascal uses procedures and functions.
3: scanf("%d",&n);
4: /* allocate memory for string */ Syntax of a Function
5: if ((numbers=(int *) malloc(n*sizeof(int)))==NULL) The declaration of a C function is in two parts.
6: {
7: printf("Not enough memory to allocate buffer\n");
Firstly, there is a prototype declaration of the function, giving: the function name,
return type and parameter types.
8: /* terminate program if out of memory */
9: } For example:
10: else
int Calc(int Mine,int Yours);
11: {
12: /* copy values into numbers */
is a function called Calc that returns an integer. The function takes two parameters,
13: for (i=0;i<n;i++,numbers++)
Notes on C programming 13
VFR October 03 SE2B2 Further Computer Systems
both of which are integers, the programmer can include the names of the return Mine+Temp;
parameters and it is often helpful to do so. The prototypes are usually placed just }
before the main function of the program.
The implementation of a function comes after the main function. The name and If this is run in C++ Builder, it will be necessary to add code to the main to stop the
types must match the prototype. The body of a function is enclosed in curly console window closing before the output is seen.
brackets. This may include declarations as well as statements. A return statement The parameters Mine and Yours work in the same way as value parameters in
in a function can be followed by an optional value, which causes the function to Pascal. However, the return is different. In Pascal setting the result of a function
return to where it was called from. Subsequent statements in the function are not does not cause the function to terminate, the function is executed until its logical
executed - this is different to setting Result in Pascal. If there isn't a return, the last statement, whereas in C executing the return causes the function to terminate.
function returns when it reaches it end.
int Calc(int Mine,int Yours) Early Versions of C
/* function to calculate Mine plus twice Yours */
Earlier versions of C declared functions in a slightly different manner that does not
{
work with current compilers. The function header did not include types. This
int Temp;
information was provided by a declaration before the curly brackets.
Temp = Yours * 2;
return Mine+Temp;
} Void
Recall that in Pascal there is no return value associated with a procedure. The type
A whole program using this function is given below: void is used in C to indicate a function that does not return a value, that is, it acts
#include <stdio.h> like a Pascal procedure. For example in the following C prototype:
#define MYCHOICE 7 void CommentOnValue(int number);
int Calc(int Mine,int Yours) the function does not return a value. It can be called by the following code:
/* function to calculate Mine plus twice Yours */ CommentOnValue(MyNumber);
{
int Temp; where MyNumber is a suitably declared variable.
Temp = Yours * 2;
Notes on C programming 14
VFR October 03 SE2B2 Further Computer Systems
Many compilers allow programmers to omit voids, however with checking turned code, this is stored as ASCII text in a file, the source file. The compiler takes the
on missing a void will usually be flagged as an error. source code, parses it and produces machine code that the computer can execute,
the object file. With C Builder, the source code is stored in a file ending in .cpp and
The variable MyNumber is an actual value parameter to the function
object code in a file ending in .obj.
CommentOnvalue, while number is a formal value parameter. In C, the word
argument is sometimes used in preference to parameter. C uses pointers to provide In earlier examples the #include statement was used to tell the compiler to include
the functionality of Pascal variable parameters and these will be discussed later. the header for library functions. For example:
#include <stdio.h>
Scope
means that the header file for the standard input and output is included in with the
In C, each function has a discrete block of code, enclosed in curly brackets. It is not
source code. The file containing the header is in the C Builder directory called
possible to use a goto statement from some other part of a program into a function
Include. The options of the environment ensure the compiler knows to look in this
nor is it possible to access variables defined locally within a function from
directory for files. Looking at the 500 lines of definitions shows that this contains a
anywhere other than within that function.
number of include statements, which will bring in other files.
C does not allow a function to be defined within another function: all functions are
Programmers can put their own definitions into separate header files and use
at the same level of scope. This is different to Pascal, which does allow nesting.
#include statements to bring the definitions into the source code. With short
The scope of a declaration is from the end of the declaration until the end of the programs, this is not always necessary but with longer programs, it can be helpful.
block containing the declaration. The same header can be included with different source code files allowing
consistent definitions to be maintained in all places.
For example, consider the function Calc.
A header file can be created to go with a source file, when the file is saved it should
1: int Calc(int Mine,int Yours) be given a .h extension. With other versions use a text editor - or investigate the
2: /* function to calculate Mine plus twice Yours */ help files.
3: {
4: int Temp; A simple example would be to create a file MyHeader.h containing the following
5: Temp = Yours * 2; two lines:
6: return Mine+Temp; void CommentOnValue(int number);
7: } int dummy;
The variable Temp comes into scope when it is defined on line 4 of the code and and a C source file containing:
goes out of scope with the closing brace. The formal parameters Mine and Yours
come into scope on the first line of the function and remain in scope until the end of 1: #pragma hdrstop
the function. The function is not enclosed in a block. It comes into scope when its 2: #include <condefs.h>
prototype is declared and remains in scope for the whole of the current file, so the 3:
scope is file wide. 4:
5: //----------------------------------
In C, declarations must precede the code of a block. However declarations can
appear at the start of any block, for example at the start of the code associated with 6: #include <stdio.h>
the else condition of an if statement. This is not always a good idea, take care with 7: #include "MyHeader.h"
such declarations. 8: void main()
9: {
10: printf ("Enter a number: ");
Header Files 11: scanf("%d",&dummy);
The statements that make up a program are sometimes referred to as the source 12: CommentOnValue(dummy);
Notes on C programming 15
VFR October 03 SE2B2 Further Computer Systems
Notes on C programming 16
VFR October 03 SE2B2 Further Computer Systems
determining the size of the array inside the function, so the information must be types based on bit patterns.
explicitly available.
This code initialises all elements of an array to 1: Casting
void init_array(int AnArray[],int n) A cast tells the compiler to temporarily treat one data type as though it was
{ another. Given the weak typing of C this can be useful to ensure that variables are
while (n>0) correctly treated. For example the following:
AnArray[--n]=1; (float) 10
}
casts the number 10 as a floating-point number.
The array is iterated through from the back. The loop could be written so element 0
is initialised first. The analogy that is best to use when considering the term cast, is that of casting a
metal (that is changing the shape).
It can be called like this:
The general format of a cast is:
int MyArray[XDIM];
init_array(MyArray,XDIM); (type name) expression
where XDIM is previously defined. The cast has a high precedence and will be only applied to the first operand of an
expression, unless the whole expression is bracketed. Any type name can be used in
A useful trick for finding the size of an array is to calculate the size of an element the cast. If a cast is applied to a longer type then bits will be lost. A cast is
in bytes by using the sizeof function. For example: equivalent to assigning the expression to a variable of the type and then using that
sizeof(MyArray[0]) variable in place of the whole construction.
The maths library <math.h> contains a routine sqrt. This expects an argument of
will return the number of bytes for the first element (say 4). While: the type double. In some versions, if it is inadvertently passed a variable of a
sizeof(MyArray)
different type it will return rubbish. To avoid this problem casting can be used. For
example to obtain the square root of an integer, the following can be used:
returns the number of bytes for the whole array. sqrt((double)AInt)
Dividing one by the other gives the number of elements, so the initialising routine or
can be called as: sqrt((double)4))
or
init_array(MyArray,sizeof(MyArray)/sizeof(MyArray[0])); sqrt((double)(AInt+4))
This does not work inside the function init_array. A properly declared prototype will avoid this problem.
Enumerated Types
FURTHER TYPES An enumerated type is made up of an ordered list of names, which are symbolic
constants. For example:
C offers the programmer the ability to use standard types and to develop enum Seasons {Spring, Summer, Autumn, Winter};
personalised types. Existing types can be cast to be used as though they were
different types. Structured types can be constructed; these include the type arrays Variables of the type are declared like this:
and heterogeneous record type. Programmers can also create enumerations and
Notes on C programming 17
VFR October 03 SE2B2 Further Computer Systems
The names must be distinct even in different enumerations. will initialise an enumeration representing Roman numerals, as the first value is
forced to 1, then all the other values will take successive values without the need to
The values are in fact stored as integers. The values used would be 0 for Spring, 1
enter them.
for Summer, etc. Different values can be associated with particular enumerations,
for example:
enum White_Space {TAB='\t',NEWLINE='\n',SPACE=' '};
Structures
A structure is a collection of related data items, not necessarily all of the same type.
However most compilers will allow any value to be assigned to a variable of an It is similar to a record in Pascal.
enumerated type, and would allow a programmer to sensibly assign 1 to This_Year A structure can be defined as follows:
but also to assign the meaningless 67. Some debuggers retains the information on
the enumeration constant and will display it. typedef struct {
int x;
Although the enumeration constants have numeric values, compilers will give
int y;
warning errors if the programmer attempts to use them in arithmetic expressions.
For example: } gridtype;
This_Year=(Seasons)((int)This_Year+1); The individual members of the structure can be accessed using the dot operator.
Where: a.x=25;a.y=-50;
If this operation was to be performed a number of times the programmer would gridtype *ptrb;
design a function to do the casting.
and this can be associated with an existing variable like this:
ptrb = &b;
Definition
As an alternative to enumerations, the programmer can use #define to associate To obtain the x member of *ptrb we do either:
constant values with names. For example:
(*ptrb).x
#define TAB '\'
#define NEWLINE '\n' or use the specially provided operator ->
#define SPACE ' '
ptrb->x
could replace the enumeration White_Space. Both are acceptable approaches.
Note *ptrb.x does not work because the precedence of dot is higher than *, and
If it is required to initialise several constants to consecutive values, this can be done this is the reason for the existence of the -> operator. This is used a lot with the
more easily with an enumeration. For example: objects of C++.
Notes on C programming 18
VFR October 03 SE2B2 Further Computer Systems
Notes on C programming 19
VFR October 03 SE2B2 Further Computer Systems
10: } uvar; into a single word. C++ uses bitfields to emulate the working of sets (C does not
11: } VARIABLE; have sets and Delphi/Builder uses them extensively in the VCL).
12: VARIABLE AVar; A bitfield is declared in the same way as a structure, except its members are fields
of one or more bits. For example:
Line 1 declares an enumerated type matching possible values of the union. Care
must be exercised in choosing appropriate names that do not conflict with reserved 1: typedef struct
words or the like. 2: {
Lines 2 to 11 define the record type VARIABLE. 3: signed i : 2;
Line 4 sets a tag field sort to the enumeration from line 1. 4: unsigned j : 5;
Line 5 to 10 is the union (declared using an anonymous type). 5: signed : 4;
Line 12 declares a variable of the record type. 6: signed k : 1;
In the code, the tag field can be set to indicate what member of the union is set, for 7: unsigned m : 4;
example: 8: } TBIT;
9: TBIT a,b;
AVar.sort=TINTEGER;
AVar.uvar.ival=2; Lines 1 to 8 define a structure that contains 4 used fields (i, j, k and m).
All bitfield members must be int, signed or unsigned. It is best practice to
When accessing the union the programmer should always check the tag before explicitly state signed or unsigned integers, as int maybe stored as signed or
assuming it has a particular form. unsigned depending on the implementation.
The declaration at line 3 reserves 2 bits for a field called i. This will stored as a
signed integer.
Linked Lists The declaration at line 4 reserves 5 bits for a field called j. This is stored as an
Linked lists can be set up and traversed in the same manner as Pascal. The unsigned integer.
following defines and declares a suitable structure: The declaration at line 5 is padding, these bits are not used. The most likely reason
for this is so that a variable of this type can be used in a bitwise operation that does
typedef struct cell
use these locations.
{
Line 9 declares two variables of the type TBIT.
double value;
The declaration creates a 16-bit structure, which will fit within a word on most
struct cell * next; computers. In most compiler, it will be stored like this:
}cellt;
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
cellt * head, * ptr; X X X X X X X X X X X X X X X X
m k unused j i
This could be traversed, and values printed out using the following code:
The integer fields are stored in two's-complement form, with the leftmost bit being
for (ptr = head;ptr != NULL;)
the MSB (most significant bit). With signed integers the MSB is interpreted as a
{ sign bit. A bit field of width 2 holding binary 11, therefore, would be interpreted as
printf("%f\n",ptr -> value); 3 if unsigned, but as -1 if int. Always check the format relative to the compiler.
ptr = ptr -> next;
} Fields can be set using the selector operators, for example:
a.i= -1;
Bitfields
When trying to economise on space a programmer may wish to pack several things Would put the bit pattern 1 1 in bits 1 and 0.
Notes on C programming 20
VFR October 03 SE2B2 Further Computer Systems
a&=b;
Macro Substitution
will do a bitwise and between a and b putting the result in a. A definition has the form
The & operator is context sensitive and so the compiler differentiates between its #define name replacement text
use as a bitwise operator and the address operator (the same is true for the *
operator). Care is needed with addresses as bitfields may not be on byte boundaries, This causes a simple macro substitution, each occurrence of name is replaced by
so the expression &a.i is illegal as i is a bit field identifier, because there is no replacement text.
guarantee that a.i lies at a byte address.
For example:
#define XDIM 10
Notes on C programming 21
VFR October 03 SE2B2 Further Computer Systems
The substitution does not have to be limited to constants, for example if the int j=100;
programmer wished to use notuntil instead of the C while, the following would i= 2+j;
create a correct program
The programmer must realise that the replacement text is used exactly. So:
#define notuntil while
5* TWO_PLUS_J
do /* this is now correct */
{ will after pre-processing be:
i++; /* though not necessarily */
5* 2+j
} notuntil (i<2); /* not a very good idea */
which might not be what the programmer expected?
It is debatable whether this is good programming practice, as the meaning of the
notuntil is the converse of usual until.
Where the replacement text spreads over more than one line a forward slash is Macros
used to indicate continuation. A macro allows parameters to be used in substitution text. In C the syntax of a
macro definition is:
For example:
#define name(parameters) code
#define WHERE_AM_I printf("In file %s at line %d", \
__FILE__,__LINE__)
The bracket of the parameter list must be next to the name, otherwise it will be part
of the code substituted.
This code will replace all occurrences of WHERE_AM_I.
For example:
Several statements can be combined. For example:
#define SQUARE(x) x*x
#define WHERE_AM_I printf("In file %s at line %d", \
__FILE__,__LINE__) ; \
In the text an occurrence of SQUARE(5) will be replaced by:
printf("\non the %s",__DATE__)
5*5
Note the \n still gives a newline in the output when used inside the quotes of a
print. The single forward slash at the end of the line of a #define is a continuation. So a program containing the following:
For both these examples to work it is necessary that earlier in the code the stdio x= SQUARE(5);
library has been included. y= SQUARE(x);
z= SQUARE(2.5);
It is possible to use variables in replacement text, for example:
#define TWO_PLUS_J 2+j will after pre-processing be:
Such substitutions should be undertaken with care as there may be more than one j x= 5*5;
y= x*x;
in scope. If the following were to appear in the program:
z= 2.5*2.5;
int j=100;
i= TWO_PLUS_J; However, an occurrence of
Notes on C programming 22
VFR October 03 SE2B2 Further Computer Systems
If expr1 is true then the result of expr2 is returned otherwise, the result of expr3 is After pre-processing, this will be:
returned. This means that the statement:
scanf("%d",&dummy);
if (a>0) b=0; else b=1;
a= 5>dummy ? 5 : dummy;
can be written in a shorter form as:
This is the code that will be compiled and then executed. If there is an error in the
b= (a>0) ? 0 : 1; definition, it will be highlighted as an error at the point that MAX is used. This can
be disconcerting for the programmer.
The brackets round the condition are not strictly necessary, but they do aid A function could be written that performed in a similar manner. For example:
readability.
int FMax(int a, int b)
{
Comma Operator return (a>b ? a : b);
The comma operator was used earlier with: }
for(i = 0;i < 5;ptr++, i++)
This is not exactly the same. The arguments have had to be given a type and so
Notes on C programming 23
VFR October 03 SE2B2 Further Computer Systems
different functions would have to be used for different types. The function would version, the economy version or is trying a cover disc sample. A single set of code
be called at run time, this would normally involve more code than the in-line can exist for all versions. Where there is functionality, that is available, differs
version generated from the macro. between versions then the code can be delimited within a conditional inclusion:
This can be achieved using this enumeration and definition:
With a larger function, the use of a macro would be a distinct disadvantage. As
each call would be replaced by the copy of the code, significantly increasing the enum VERSION {FULL, ECONOMY, SAMPLE};
size of the executable. #define VERSION FULL
then at compile time, all the debugging print statements will be included in the This is necessary as it is not possible to define the same symbol twice. An
object code produced. Whereas if the definition is: alternative would be to undefine the symbol and then redefine it, for example:
Notes on C programming 24
VFR October 03 SE2B2 Further Computer Systems
in a Delphi unit.
Notes on C programming 25