Você está na página 1de 26

Department of Cybernetics The University of Reading

SE2B2

FURTHER COMPUTER SYSTEMS

LECTURE NOTES ON C PROGRAMMING

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

CALL BY REFERENCE .................................................................................................................................. 16


AN INTRODUCTION TO C FOR DELPHI PROGRAMMERS .........................................................2 ARRAYS AS ARGUMENTS ............................................................................................................................ 16
INTRODUCTION ..............................................................................................................................................2
ASSESSED WORK ...........................................................................................................................................2 FURTHER TYPES................................................................................................................................... 17
TOPICS ...........................................................................................................................................................2 CASTING ...................................................................................................................................................... 17
ACKNOWLEDGEMENTS ..................................................................................................................................2 ENUMERATED TYPES .................................................................................................................................. 17
DEFINITION ................................................................................................................................................. 18
C AND C++ FOR DELPHI PROGRAMMERS - AN INTRODUCTION ...........................................2 STRUCTURES ............................................................................................................................................... 18
A SIMPLE PROGRAM .............................................................................................................................3 POINTERS TO STRUCTURES ......................................................................................................................... 18
COMMENTS ....................................................................................................................................................3 A FUNCTION RETURNING A STRUCTURE ..................................................................................................... 19
DELIMITERS ...................................................................................................................................................3 UNION ......................................................................................................................................................... 19
MAIN ..............................................................................................................................................................3 LINKED LISTS .............................................................................................................................................. 20
LIBRARIES ......................................................................................................................................................3 BITFIELDS.................................................................................................................................................... 20
DEFINITIONS ..................................................................................................................................................4 THE PRE-PROCESSOR......................................................................................................................... 21
ASSIGNMENT .................................................................................................................................................4 PREDEFINED SYMBOLS ............................................................................................................................... 21
SEMICOLONS ..................................................................................................................................................4 MACRO SUBSTITUTION ............................................................................................................................... 21
CASE SENSITIVE ............................................................................................................................................4 MACROS ...................................................................................................................................................... 22
TYPES AND OPERATORS ......................................................................................................................5 CONDITIONAL OPERATOR ........................................................................................................................... 23
TYPES.............................................................................................................................................................5 COMMA OPERATOR..................................................................................................................................... 23
ASSIGNMENT OPERATORS .............................................................................................................................5 MACROS VS FUNCTIONS ............................................................................................................................. 23
ARITHMETIC OPERATORS ..............................................................................................................................6 CONDITIONAL COMPILATION ..................................................................................................................... 24
LOGICAL AND EQUALITY OPERATORS ..........................................................................................................6 CONDITIONAL DEFINITIONS ........................................................................................................................ 24
UNARY OPERATORS ......................................................................................................................................6 PRAGMA ...................................................................................................................................................... 24
Unary Minus.............................................................................................................................................6
Increment and Decrement........................................................................................................................6
Unary Pointer Operators .........................................................................................................................6
STRUCTURE OPERATORS ...............................................................................................................................7
PRECEDENCE OF OPERATORS ........................................................................................................................7
WHILE STATEMENT .......................................................................................................................................7
DO…WHILE STATEMENT ...............................................................................................................................8
FOR STATEMENT ............................................................................................................................................8
IF STATEMENT ................................................................................................................................................8
GOTO ..............................................................................................................................................................9
CONTINUE AND BREAK ..................................................................................................................................9
continue ....................................................................................................................................................9
break.........................................................................................................................................................9
SWITCH STATEMENT ......................................................................................................................................9

ARRAYS, POINTERS AND STRINGS .................................................................................................10


ONE DIMENSIONAL ARRAYS .......................................................................................................................10
READING INTO AN ARRAY ...........................................................................................................................10
GENERATING A POINTER TO AN ARRAY .....................................................................................................11
STRINGS .......................................................................................................................................................11
MULTIDIMENSIONAL ARRAYS.....................................................................................................................11
POINTERS .....................................................................................................................................................12
Pointers and one dimensional arrays ....................................................................................................12
Pointers and multidimensional arrays...................................................................................................12
DYNAMIC MEMORY ALLOCATION ...............................................................................................................13
FUNCTIONS .............................................................................................................................................13
SYNTAX OF A FUNCTION .............................................................................................................................13
EARLY VERSIONS OF C................................................................................................................................14
VOID ............................................................................................................................................................14
SCOPE ..........................................................................................................................................................15
HEADER FILES .............................................................................................................................................15

Notes on C programming 1
VFR October 03 SE2B2 Further Computer Systems

C AND C++ FOR DELPHI PROGRAMMERS - AN


AN INTRODUCTION TO C FOR DELPHI PROGRAMMERS INTRODUCTION

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

In Delphi curly brackets { and } are used to delimit comments. While in C /* is


used to mark the start of a comment and it terminates with */. Neither language
A SIMPLE PROGRAM supports nesting of comments. Later versions of Delphi allowed single line
comments that begin with // and end with the end of line. The same single line
Below is a simple Delphi 1 console program that handles numbers: comments are allowed in C++ but are not a feature of C.

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:

Comments uses WinCrt;

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;

Two variables are declared, both of type int. MyNumber is initialised to 7.


The C programming language, like Pascal, supports several different data types. YourNumber is not initialised and so its value is undefined and could contain
Variables are declared to be of a type. Operations can be performed on variables anything. It should not be used before a value is assigned to it.
and constants.
Other examples of declarations are:
Variable names in C are made up of uppercase and lowercase letters, numbers and
the underscore character. Variable names can begin with either a letter or an int Number;
underscore, names beginning with underscore often have special meanings and so char Letter1, Letter2='b';
are best avoided. It should be remembered that C is case sensitive so it is important float e,E,f,F; /*permitted but difficult to understand*/
always to use the same mix of uppercase and lowercase letters in a particular name. double density_1;
As with Pascal it is wise not to use variable names that match reserved words. double density_2;

The maximum allowable length of variable names varies from compiler to


Types compiler. The general rule is to use names that are meaningful within the context of
The memory requirements of each type will vary on different computers, and the program. It is wise to avoid using the same name in different case of letters,
indeed can vary with different compilers on the same processor. Table 1 indicates unless the meaning is very clear.
the names of some of the most commonly used data types and their possible range
of values and size in bytes on a 32-bit machine.
Assignment Operators
The use of the standard headers <limits.h> and <float.h> can help in fixing sizes
when trying to write portable programs. Pascal has a single assignment operator := which is equivalent to the = operator in
C. The C language offers a number of compound operators, including assignment
Data Type Size in Bytes possible range of values operators that combine other operations, as summarised in Table 2.
char 1 -128 to 127
unsigned char 1 0 to 255 Operator Description Example
int 4 -2147483648 to 2147483647 = Assignment Number = 6;
unsigned int 4 0 to 4294967295 += Sum and assign Number += 10; adds 10 to Number
short int 2 -32768 to 32767 -= Subtract and Number -= 5; subtract 5 from Number
long 4 same as int assign
*= Multiply and density_1 *= same as density_1=
float 4 3.4 *10-38 to 1.7* 1038
assign Number; density_1*Number;
double 8 1.7*10-308 to 3.4 ^ 10308
/= Divide and assign density_1/=4; divides density_1 by 4
&= bitwise AND and Letter1&=Letter2 ands the bits of Letter1
Table 1
assign with Letter2
The meaning of these types will vary between compilers, for example on some |= bitwise OR and Letter1|=Letter2 ors the bits of Letter1
machines int and short int will represent the same range. Programmers should be assign with Letter2
aware that porting a program between compilers may result in the introduction of Table 2
overflow errors.
More details of the other operations will be given in the following sections.

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

C Operator Description Object Pascal equivalent


& Address of @ The C equivalent needs brackets to control what the indirection operator is applied
* Indirection ^ to:
(*CThisItem).Next
The way in which they are written is subtly different.
Consider declaring a pointer: Alternatively, the C indirection operator can be used:

• in C a pointer to an integer is declared like this: CThisItem->Next

int *CIndex; There must not be a space between the minus and the greater than symbols.

• in Pascal a pointer to an integer is declared like this:


Precedence of Operators
var PIndex:^Integer;
The precedence of C operators dictates the order of calculation within an
Assigning a previously declared integer to the address these points and then setting expression. The precedence of the operators introduced here is summarised in the
both to the value 5 is done in similar manners. table below. The highest precedence operators are given first.

• in C a pointer to an integer is used like this:


Operators Associativity
CIndex=&CInteger;
*CIndex=5;
() -> . left to right
! ~ + - ++ -- & * right to left
* / % left to right
• in Pascal:
+ - left to right
PIndex:=@PInteger; < <= > >= left to right
PIndex^:=5; == != left to right
& left to right
Note in statements in C the indirection operator goes in front, whereas in Pascal it | left to right
goes behind. && left to right
|| right to left
= *= /= %= += -= right to left
Structure Operators
C has a heterogeneous data structure like Pascal records. In C, these are called Where the same operator appears twice (for example *) the first one is the unary
structures or struct as will be explained later. version.
The dot operator is used in both C and Pascal to indicate a member. For example At the heart of most programs are pieces of code that are executed many times,
given a structure variable Employee with a field Salary both languages refer to this with some choices between the paths through the code. C offers counted and
field as: conditional loops. Selection is offered by an if statement on a multi-way switch.
Employee.Salary
While Statement
Data structures such as linked lists mix records and pointers. In Pascal a list is The syntax of a while statement is:
traversed using expressions such as:
while (expression)
PThisItem^.Next
statement;

Notes on C programming 7
VFR October 03 SE2B2 Further Computer Systems

The general format is:


The expression is usually a relational expression. The statement is either a
for (initial; test; adjust )
compound statement enclosed in curly brackets or single statement. For example:
statement;
n = 1;
while (n <= 10) Where initial is a statement that initialises values prior to the execution of the loop.
{ The expression test must hold true for an iteration of the loop to start. The adjust
printf("%3d", n); statement is executed for each iteration, after the iteration has completed.
n++;
for (n=1; n<=10; n++)
}
{
printf("%3d", n);
this will print out the numbers 1 to 10.
}
The positioning of the curly brackets and the indentation are according to the
programmers preference. It is wise to keep with the same sort of lay out that you This will print out the numbers 1 to 10. The curly brackets are not necessary as
would have used in Pascal. there is only a single statement.
It is not always necessary to have all parts of the for statement, parts can be left
do…while statement empty. The following code has the same functionality as the above.
The syntax of a do...while statement is: n=0;
for (; ++n<=10; )
do
{
statement
printf("%3d", n);
while (expression);
}
it is similar to the Pascal repeat, in that the statement or compound statement is
always executed at least once. In this case, the initialisation is outside the loop. The incrementing of n occurs as
part of the final test. As the operator is first the incrementing happens before the
do comparison. If the test were replaced by:
{
n++<=10
printf("Enter a number that is not 7");
scanf("%d",&n);
The loop would be executed 11 times.
} while (n==7);

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.

for statement if (test)


The C for statement offers much more than the equivalent counted loop in Pascal. statement;

Notes on C programming 8
VFR October 03 SE2B2 Further Computer Systems

else continue and break


statement; C offers two structured alternatives to goto. Both of these cause the remainder of a
compound statement to be ignored.
Note that the semicolon is needed before the else. Below is an example of an if
statement. It executes in the same manner as the Pascal equivalent.
continue
if (number > 0)
printf("Number positive\n"); The continue is used inside a loop, it causes the remainder of the current iteration
else to be skipped and the next iteration to be started.
{
printf("Number negative \n"); break
printf("or zero\n");
The break is used inside a loop or conditional statement. It causes the remainder of
}
the statement to be skipped and execution to proceed to the next statement. With a
loop, this means that no further iterations are executed.
As with Pascal statements can be nested, as shown in the following example.
if (number > 100)
printf("Large\n");
switch statement
else if (number > 0) The C switch statement is similar to the Pascal case. The general format is:
printf ("Not large but positive\n"); switch expression
else if (number == 0)
{
printf("or zero\n"); case value1: statements1;
else case value2: statements2;
printf("Negative \n");
/* more cases */
default: defaultstatements; }
Care is needed to match the else clause with the correct if.
Semantically this is different to the Pascal case. If the expression is equal to value1,
goto then statements1 is executed, followed by statements2, then all other statements
including defaultstatements. If the expression is equal to value2, then statements2
Pascal programmers rarely use the goto statement and its use in object oriented is executed, followed by all other statements including defaultstatements. To get
languages, including C++, is considered unnecessary. Some C programs do use the the same effect as Pascal it is necessary to put a break after every set of statements,
instruction and so it is described here. to prevent execution of all subsequent statements in the switch. The following
The syntax of a goto statement is: fragment of code illustrates the use of break.
goto label ; /* assume char op; */
scanf("%c", &op);
Where label is a local label, terminated by a colon. switch(op) {
case '+' : printf("%d", x + y); break;
For example:
case '-' : printf("%d", x - y); break;
again: case '*' : printf("%d", x * y); break;
/* code*/; case '/' : printf("%d", x / y); break;
goto again; default: break;
}

Notes on C programming 9
VFR October 03 SE2B2 Further Computer Systems

Reading into an Array


ARRAYS, POINTERS AND STRINGS The following program fragment reads from the standard input (that is the
keyboard) into an array - it stops at a sentinel. There is plenty of opportunity for
this program to give rise to errors - so it should incorporate error checking on the
An array is a bounded collection of elements of the same type. Each element of an size of the array before it is used.
array is accessed via an index. In C, all arrays are stored in contiguous memory
locations. The lowest address corresponds to the first element and the highest /* reads numbers from standard input -
address to the last element. As in Pascal arrays can be, single dimensional or that is the keyboard - into array
multidimensional. until sentinel is encountered
NB overflow check needed*/
In C arrays and pointers are closely related, so programmers can use pointers to
int i,Temp;
traverse arrays.
int square[5];
One of the most common uses of one-dimensional arrays is to represent strings. fscanf(stdin,"%d", &Temp);
These are stored as an array of characters, terminated by a null. In Delphi, we refer for (i=0; Temp != SENT; i++)
to these as C-strings. {
square[i] = Temp;
One Dimensional Arrays fscanf(stdin,"%d", &Temp);
}
Consider this fragment of program:
1: int square[5]; Alternatively the numbers can be read from a file and written to another:
2: int i; FILE *fin, *fout;
3: for(i = 0;i < 5; i++) if (((fin =fopen("Numbers.txt","r")) == NULL)
4: square[i] = (i+1)*(i+1); ||
((fout=fopen("Copy.txt","w")) == NULL))
Line 1 defines an array with 5 elements, each element is an integer. The first {
element of an array has the index 0. So this declaration gives 5 elements: fprintf(stdout,"Can't open file\n");
square[0] }
square[1] else
square[2] {
square[3] fscanf(fin,"%d", &Temp);
square[4] for (i=0; Temp != SENT; i++)
{
The last element has an index that is one less than the size of the array. fprintf(fout,"%d ",Temp);
fscanf(fin,"%d", &Temp);
Line 2 defines a control variable for the loop that starts at line 3 and iterates round
}
the statement at line 4.
}
Line 4 in turn assigns to each element the square of its position (that is one more fclose(fin); fclose(fout);
than its index).
The variable fin is a pointer to a file, hence the declaration.
An array can be initialised as it is declared, as in this example:
All files can be opened using fopen. The second parameter indicates how it is to be
int squared[5] = {0,1,4,9,16}; used, "r" indicates reading, "w" indicates writing and if the file already exists, it
will be overwritten. It is also possible to use "a" to indicate append. On successful

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

A pointer is an address of a location (of a particular type), for example:


To record 6 hours of sunshine for the 1st April, the following assignment could be
float * RealPtr;
done:
suns [3][0] = 6; is a pointer to a location that can contain a real number. NULL is equivalent to nil
in Pascal.
The right most subscript varies most rapidly. This is important to remember when
In C, it is possible to have a pointer to a general type, for example:
initialising arrays. It will also be significant if pointers are used to access elements
of an array. Consider: void * genptr;

int values[3][4]={1,2,3,4,5,6,7,8, 9,10,11,12};


Pointers and one dimensional arrays
Then values[0][0] contains 1, values[0][1] contains 2 and values[1][0] contains 5. In C pointers are often used to access existing structures, such as arrays. The
following code shows three ways in which an array can be accessed:
It is possible to initialise parts of each row:
1: int square[5];
int values[3][4] ={
2: int *ptr = &square[0];
{1,2},
3: /* assigns square of number to element */
{5,6},
4: for (i = 0; i < 5; i++) square[i] = (i+1)*(i+1);
{9,10}
5: /* and so does this */
};
6: for (i = 0; i < 5; i++) ptr[i] = (i+1)*(i+1);
7: /*and this - note comma*/
Which will initialise columns 0 and 1. The other elements will not be initialised,
8: for(i = 0;i < 5;ptr++, i++)
and may contain anything - so this is not often advisable.
9: *ptr = (i+1)*(i+1);
When a number of arrays are to be declared using the same dimensions, it is good
practice to use #define to set the bound. For example: Line 1 declares an array and line 2 declares a pointer to the first element of the
array. With a single dimension array, it is possible to put just:
#define XDIM 10
#define YDIM 20 int *ptr = square;
#define ZDIM 30
However, this doesn't work with multidimensional arrays.
these can then be used in the program: Line 4 loops round setting each element of the array.
Line 6 uses the pointer as a means of accessing the array. Note the indirection
int testarray [XDIM][YDIM][ZDIM]; operator * is not used.
int i,j,k; The loop on lines, 8 and 9, is more subtle. Note at line 8 there are two increments
for (i=0;i<XDIM;i++) (separated by commas). On the first iteration, ptr is pointing to the first element in
for (j=0;j<YDIM;j++) the array, when it is incremented for the next iteration it will point to the second
for (k=0;k<ZDIM;k++) element of the array. When the loop is completed ptr will be pointing beyond the
testarray[i][j][k]=i*YDIM*ZDIM+j*ZDIM+k; end of the array and if used would access garbage. The value ptr was pointing to
could be seen by using a printf statement:
Then if the program needs to cope with larger arrays it is only necessary to change
the definitions (and probably allow a longer run time and plenty of memory). printf("%d",*ptr);

Pointers and multidimensional arrays


Pointers Pointers can also be used to access multidimensional arrays, care is needed in two

Notes on C programming 12
VFR October 03 SE2B2 Further Computer Systems

respects: 14: *numbers=i;


15: /* display numbers */
• ensuring that the array is accessed matching the appropriate subscripts
16: for (i=n;i>0;i--)
• de-referencing correctly to get to the initial point.
17: printf("Numbers are %3d\n", *(numbers-i));
Consider the following code: 18: /* free memory */
19: free(numbers-n);
1: int values[3][4];
20: }
2: int *ptr;
3: ptr=&values[0][0];
In this code memory is allocated at line 5, within a conditional, if the allocation
4: for (i=0;i<3*4;i++,ptr++)
fails a suitable error message is displayed.
5: *ptr=i; The casting using (int *) in front of malloc ensures that result is treated as though
it is a pointer to int, it is not strictly necessary.
This uses ptr to set the elements of values. When the loop is complete, ptr will The for at line 13 increments both i and numbers, so the body of the loop (at line
point beyond the end of the loop. 14) puts successive values of i into successive locations of numbers.
Printing out the contents of values will verify the elements are correctly set: The loop at line 16 counts backward. Since numbers will now be pointing just
for (i=0;i<3;i++) beyond the space allocated, care has to be taken to print out the contents of
{ locations that have been set!.
for(j=0;j<4;j++) Likewise at line 19 the space allocated originally to numbers is released, the
printf("%3d",values[i][j]); decrement is because numbers is pointing beyond the allocated locations. This
printf("\n");
needs to be carefully handled as attempts to:
} free(numbers)

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); and in the corresponding function:

main() void CommentOnValue(int number)


{ {
int MyNumber,YourNumber; if (number > 100)
MyNumber = MYCHOICE; printf("Large\n");
else if (number > 0)
printf("%5d is my number\n",MyNumber); printf ("Not large but positive\n");
printf("What's yours?\n"); else if (number == 0)
scanf("%d",&YourNumber); printf("or zero\n");
printf("Mine plus twice yours is: %5d", else
Calc(MyNumber,YourNumber)); printf("Negative \n");
} }

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

13: scanf("%d",&dummy); *y=temp;


14: } }
15:
16: void CommentOnValue(int number) and called like this:
17: {
int a=3,b=5;
18: if (number > 100)
19: printf("Large\n");
swap(&a,&b);
20: else if (number > 0)
21: printf ("Not large but positive\n"); The & in front of a and b indicates that the address of these variable is passed.
22: else if (number == 0) Within the function x and y are pointers and the values used, are those they point
23: printf("or zero\n"); to. It is possible to do this in Pascal, but programmers normally use variable
24: else parameters (which hide the use of pointers).
25: printf("Negative \n");
26: } If you find it confusing using pointers inside functions, you could on entry to the
function, copy the pointers into local variable. However, you must then remember
The first 5 lines above the comment are automatically generated, by C++ Builder. to copy them back at the end of the function, this may need to be done several
These may not be necessary in other versions of C. times if you have multiple returns. It does make a lot more code…

The line: void swap2 (int *rptr, int *sptr)


{
#include <stdio.h> int temp;
int r,s;
includes the definitions for the input and output.
The line: r=*rptr;
s=*sptr;
#include "MyHeader.h"
temp=r;
includes the definition from the header file just created. The quotes indicates that
r=s;
this file should be found where the source file is, if it is not found there, searching
s=temp;
follows the rules set within the environment.
*rptr=r;
Call by reference *sptr=s;
All arguments in C are passed by value. To get the effect of Pascal variable }
parameters it is necessary to pass a pointer. Within the function the pointer can be
de-referenced, that value can be changed, so what the pointer points to changes but The call is the same as before:
the pointer remains unaltered. For example, a function, which swaps the values swap2(&a,&b);
held in two integer variables, could be written like this:
void swap (int *x, int *y) Arrays as Arguments
{ When an array is passed as an argument, it is in fact the address of the first
int temp; element that is passed. Therefore, it is possible to change the elements of the array
temp=*x; because the argument is the address. It is not necessary to specify the size of an
*x=*y; array when declaring it as an argument. Unfortunately, there is no way of

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

enum Seasons This_Year, Next_Year; enum Roman {I=1,II,III,IV,V,VI,VII,VIII,IX,X};

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++; /*will give a warning*/ Variables of this type can be declared:

The correct form is: gridtype a, b;

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;

1. This_Year is cast as an integer Pointers to Structures


2. 1 is added
3. The result is then cast back as Seasons. A pointer to a structure can be declared like this:

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

If we have: gridtype *makeplace (int xx, int yy)


{
typedef struct {
gridtype *temp;
int x;
temp =malloc(sizeof(gridtype));
int y;
if (temp == NULL)
} gridtype;
exit (1); /* error */
gridtype a, *aptr=&a;
temp -> x = xx;
then the following are equivalent: temp -> y = yy;
return temp;
a.x }
aptr->x
(*aptr).x The programmer will need to free the space allocated to this gridtype when it is no
longer needed.
The priorities indicate that:
++ aptr->x Union
increments the x member. If it was required to increment a ptr, brackets should be
A union is somewhat like a variant record in Pascal. It can hold (at different times)
used.
things of different types and sizes. The compiler keeping track of size and
alignment necessary, the space allocated will be sufficient for the largest member
A function returning a structure of the union. For example:
Function to return structure typedef union
{
gridtype makeplace (int xx, int yy)
int ival;/* or */
{
float fval;/* or */
gridtype temp;
char *sval;
temp.x = xx;
} utype;
temp.y = yy;
utype uvar;
return temp;
}
Syntactically members are accessed in the same way as members of a record, but
the programmer is responsible for keeping track of what is stored in the union. The
The scoping of C means it is acceptable to use x and y in place of xx and yy: normal approach is to put the union into a record and add a tag field (this is
gridtype makeplace (int x, int y) automatically available in Pascal). In C this is more difficult but can be achieved
{ using code such as this:
gridtype temp;
1: enum TSORT{TINTEGER,TFLOAT,TSTRING} ;
temp.x = x;
2: typedef struct
temp.y = y;
3: {
return temp;
4: enum TSORT sort;
}
5: union
6: {
This will be more readable to some programmers.
7: int ival;/* or */
To return a pointer to a gridtype will require memory to be allocated, as in the 8: float fval;/* or */
following: 9: char *sval;

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

However, there is no warning of overflows so the assignment:


a.i = 6; THE PRE-PROCESSOR
would leave binary 10 = -2 in a.i with no warning.
There are many steps involved in turning a C program into an executable program.
The signed field k of width 1 can hold only the values -1 and 0, because the bit The first step is called pre-processing. The pre-processor performs textual
pattern 1 is interpreted as -1. manipulation on the source code before it is compiled. There are a number of major
parts to this:
In other machines the coding may be the other way round (right most bit most
significant). Bitfields may be aligned to word boundaries or they may flow across 1. deleting comments
them. Some machines limit structures containing bitfields to 16 bits. Thus, there are 2. inserting the contents of files mentioned in #include directives
issues that may effect portability. 3. defining and substituting symbols from #define directives
4. deciding which code should be compiled depending on conditional compiler
Bitfields are not arrays and cannot be treated as such. The bitwise operators should
directives
be used:
5. to act on recognised #pragma statements, which are implementation dependent.
Operator What it does
& bitwise AND; compares two bits and generates a 1 result if both bits
are 1, otherwise it returns 0.
Predefined Symbols
| bitwise inclusive OR; compares two bits and generates a 1 result if C provides a number of predefined symbols, the values of which are either string
either or both bits are 1, otherwise it returns 0. literals or decimal constants. These include:
^ bitwise exclusive OR; compares two bits and generates a 1 result if the
Symbol Sample Value Meaning
bits are complementary, otherwise it returns 0.
_ _FILE_ _ " C:\ Unit1.cpp" name of the source file being compiled
~ bitwise complement; inverts each bit. ~ is used to create destructors.
_ _DATE_ _ "May 14 1999" date the current file was compiled
>> bitwise shift right; moves the bits to the right, discards the far right bit
_ _STDC_ _ 1 1 if the compiler conforms to ANSI C,
and if unsigned assigns 0 to the left most bit, otherwise sign extends.
otherwise undefined
<< bitwise shift left; moves the bits to the left, it discards the far left bit
and assigns 0 to the right most bit.
A particular environment may supplement the available symbols. Most predefined
symbols start with two underscores, there must not be a blank between them, and
The combined assignment and operators &= and |= can also be used. For example:
they often look as though they are a single long line ( __ ).

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

causes all occurrences of XDIM to be replaced by the literal 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

After pre-processing, it would be: 10+SQUARE(5)

Notes on C programming 22
VFR October 03 SE2B2 Further Computer Systems

will be replaced by *ptr = (i+1)*(i+1);


10+5*5
which incremented both ptr and i.
this is not a problem here, consider what happens with the following: The syntax of the comma operator is that the sub-expressions are evaluated in order
and the result is the value of the last one.
#define DOUBLE(IT) IT+IT
m= 10*DOUBLE(5); The comma operator is often used with while loops to incorporate fetching of a
value with the test, with the general syntax:
after pre-processing, the assignment will become:
while(get some value, perform calculation on value, and
m= 10* 5+5; test)
{ statements}
It is unlikely the programmer expected this to evaluate to 55. Use of brackets in the
#define or the code will remove this problem. The comma operator is different to the comma used to separate the list of
arguments.
The use of an argument could make the earlier example of UNTIL closer to the
Pascal equivalent.
#define UNTIL(x) WHILE(!(x))
Macros Vs Functions
Macros are sometimes used to perform simple computations, often using the
Note the brackets around the argument will ensure the not operator (that is the ! operators described above. For example, the following macro finds the maximum
symbol) is applied to the whole of the x argument. of two expressions:
#define MAX(a,b) a>b ? a : b
Conditional Operator
In the program code such as the following can be used:
The conditional operator can be used to return a value. It has the following syntax:
scanf("%d",&dummy);
expr1 ? expr2 : expr3
a=MAX(5,dummy);

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

in conjunction with conditional compilations of the following sort:


Conditional Compilation
Conditional compilation provides a way where by code can be selectively included #if (VERSION == FULL)
into the compilation - depending on values available at pre-processing. The syntax statements for full implementation
of conditional compilation statement is: #elif (VERSION == ECONOMY)
statements for economy implementation
#if constant expression #else
statements statements for sample implementation
#endif #endif
The pre-processor evaluates the constant expression if it is zero (false) the
statements are deleted from the code passed to the compiler, if the constant
expression is non-zero (true) the statements are passed to the compiler.
Conditional definitions
The #ifdef command conditionally includes code if a symbol is defined. If the
The constant expression is made up of literals and variables that have been defined symbol is not defined, the code is not included. The opposite command is #ifndef
using a #define. It is illegal to use anything where the value will not be known until which includes code only if the symbol is not defined. For example, if the program
execution time, as the compiler is unable to predict the values. includes a library file that, in some implementations, does not define a symbol
A simple example is to bracket the code used for debugging in the following MAXLINES, then the program may have a fragment like this:
manner:
#if DEBUG 1: #include <somelib.h>
printf("At line %d: a=%d, b=%d\n",__LINE__,a,b); 2: #ifndef MAXLINES
#endif 3: #define MAXLINES 100
4: #endif
Therefore, the listing may contain many instances of this conditional inclusion,
protecting the printing of interesting variables. Line 1 includes the library, which may vary between machines.
If the following is present: Line 2 checks if MAXLINES is already defined. If it isn't defined then line 3
defines it.
#define DEBUG 1 Line 4 is the end of the conditional definition.

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:

#define DEBUG 0 #undef MAXCHARS


#define MAXCHARS 60
none of the debug statements will be included in the object code generated.
Conditional compilation is also useful if developing a software product that has Pragma
different functionality depending on whether the user has purchased the full The #pragma command is a mechanism that supports implementation dependent

Notes on C programming 24
VFR October 03 SE2B2 Further Computer Systems

directives. An environment may provide pragmas to allow special options. Where a


pragma is not recognised, it is ignored. So a program with pragams will run on
different machines, however the actions of the pragma may not be the same across
machines, so the program is not truly portable.
Pragmas are used in a number of ways by C++ Builder. For example when
generating forms, the corresponding unit will contain code like this:
#pragma resource "*.dfm"

This is equivalent to:


{$R *.DFM}

in a Delphi unit.

Notes on C programming 25

Você também pode gostar