C LANGUAGE KEYWORDS
The following names are reserved by the C language. Their meaning is already defined, and they cannot be re-defined to mean anything else.
do double else enum extern float
for goto if int long register
return short sizeof static struct switch
typedef union unsigned void while void
const volatile
Other than these names, you can choose any names of reasonable length for variables, functions etc. The names must begin with a letter or underscore (letters are better), and then can contain letters, numbers and underscores.
DATA TYPES
C has the following simple data types:
On UNIX systems all ints are long ints unless specified as short int explicitly.
NOTE:
There is NO Boolean type in C -- you should use char, int or (better) unsigned char.
Unsigned can be used with all char and int types.
FURTHER DATA TYPES
STRUCTURES
Structures in C are similar to records in Pascal.For example:
STRUCT GUN
{
CHAR NAME[50];
INT MAGAZINE SIZE;
FLOAT CALIBER;
};
STRUCT GUN ARNIES;
defines a new structure gun and makes arnies an instance of it.
NOTE:
That gun is a tag for the structure that serves as shorthand for future declarations. We now only need to say struct gun and the body of the structure is implied as we do to make the arnies variable. The tag is optional.
Variables can also be declared between the } and ; of a struct declaration, i.e.:
struct gun
{
char name[50];
int magazinesize;
float calibre;
} arnies;
struct's can be pre-initialised at declaration:
struct gun arnies={"Uzi",30,7};
which gives arnie a 7mm. Uzi with 30 rounds of ammunition.
To access a member (or field) of a struct, C provides the . operator. For example, to give arnie more rounds of ammunition:
arnies.magazineSize=100;
DEFINING A STRUCTURE
A structure type is usually defined near to the start of a file using a typedef statement.
typedef defines and names a new type, allowing its use throughout the program.
typedefs usually occur just after the #define and #include statements in a file.
Here is an example structure definition.
TYPEDEF STRUCT {
CHAR NAME[64 ];
CHAR COURSE[128];
INT AGE;
INT YEAR;
} STUDENT;
This defines a new type student variables of type student can be declared as follows.
STUDENT ST_REC;
Notice how similar this is to declaring an int or float.
The variable name is st_rec, it has members called name, course.
DEFINING NEW DATA TYPES
typedef can also be used with structures. The following creates a new type agun which is of type struct gun and can be initialised as usual:
typedef struct gun
{
char name[50];
int magazinesize;
float calibre;
} agun;
agun arnies={"Uzi",30,7};
Here gun still acts as a tag to the struct and is optional. Indeed since we have defined a new data type it is not really of much use,
agun is the new data type. arnies is a variable of type agun which is a structure.
C also allows arrays of structures:
TYPEDEF STRUCT GUN
{
CHAR NAME[50];
INT MAGAZINESIZE;
FLOAT CALIBRE;
} AGUN;
AGUN ARNIESGUNS[1000];
This gives arniesguns a 1000 guns. This may be used in the following way:
ARNIESGUNS[50].CALIBRE=100;
gives Arnie's gun number 50 a calibre of 100mm, and:
ITSCALIBRE=ARNIESGUNS[0].CALIBRE;
assigns the calibre of Arnie's first gun to itscalibre.
UNIONS
A union is a variable which may hold (at different times) objects of different sizes and types. C uses the union statement to create unions, for example:
union number
{
short shortnumber;
long longnumber;
double floatnumber;
} anumber
defines a union called number and an instance of it called anumber. number is a union tag and acts in the same way as a tag for a structure.
Members can be accessed in the following way:
PRINTF("%LD?N",ANUMBER.LONGNUMBER);
This clearly displays the value of longnumber.
When the C compiler is allocating memory for unions it will always reserve enough room for the largest member (in the above example this is 8 bytes for the double).
In order that the program can keep track of the type of union variable being used at a given time it is common to have a structure (with union embedded in it) and a variable which flags the union type:
An example is:
TYPEDEF STRUCT
{ INT MAXPASSENGERS;
} JET;
TYPEDEF STRUCT
{ INT LIFTCAPACITY;
} HELICOPTER;
TYPEDEF STRUCT
{ INT MAXPAYLOAD;
} CARGOPLANE;
TYPEDEF UNION
{ JET JETU;
HELICOPTER HELICOPTERU;
CARGOPLANE CARGOPLANEU;
} AIRCRAFT;
TYPEDEF STRUCT
{ AIRCRAFTTYPE KIND;
INT SPEED;
AIRCRAFT DESCRIPTION;
} AN_AIRCRAFT;
This example defines a base union aircraft which may either be jet, helicopter, or
cargoplane.
In the an_aircraft structure there is a kind member which indicates which structure is being held at the time.
ENUMERATED TYPES
Enumerated types contain a list of constants that can be addressed in integer values.
We can declare types and variables as follows.
ENUM DAYS {MON, TUES, ..., SUN} WEEK;
ENUM DAYS WEEK1, WEEK2;
NOTE:
As with arrays first enumerated name has index value 0. So mon has value 0, tues 1, and so on.
WEEK1 AND WEEK2 ARE VARIABLES.
We can define other values:
ENUM ESCAPES { BELL = `?A',
BACKSPACE = `?B', TAB = `?T',
NEWLINE = `?N', VTAB = `?V',
RETURN = `?R'};
We can also override the 0 start value:
ENUM MONTHS {JAN = 1, FEB, MAR, ......, DEC};
Here it is implied that feb = 2 etc.
VARIABLES
In C, a variable must be declared before it can be used. Variables can be declared at the start of any block of code, but most are found at the start of each function.
Most local variables are created when the function is called, and are destroyed on return from that function.
To declare a variable in C, do:
VAR_TYPE LIST VARIABLES;
E.G.
INT I,J,K;
FLOAT X,Y,Z;
CHAR CH;
INT HIGH, LOW, RESULTS[20];
Declarations can be spread out, allowing space for an explanatory comment. Variables can also be initialised when they are declared, this is done by adding an equals sign and the required value after the declaration.
INT HIGH = 250; /* MAXIMUM TEMPERATURE */
INT LOW = -40; /* MINIMUM TEMPERATURE */
INT RESULTS[20]; /* SERIES OF TEMPERATURE READINGS */
C provides a wide range of types. The most common are
?
There are also several variants on these types.
?
All of the integer types plus the char are called the integral types. float and double are called the real types.
DEFINING GLOBAL VARIABLES
Global variables are defined above main() in the following way:-
SHORT NUMBER,SUM;
INT BIGNUMBER,BIGSUM;
CHAR LETTER;
MAIN()
{
}
It is also possible to pre-initialise global variables using the = operator for assignment.
NOTE:
The = operator is the same as := is Pascal.
For example:-
FLOAT SUM=0.0;
INT BIGSUM=0;
CHAR LETTER=`A';
MAIN()
{
}
This is the same as:-
FLOAT SUM;
INT BIGSUM;
CHAR LETTER;
MAIN()
{
SUM=0.0;
BIGSUM=0;
LETTER=`A';
}
...but is more efficient.
C also allows multiple assignment statements using =,
for example:
A=B=C=D=3;
...which is the same as, but more efficient than:
A=3;
B=3;
C=3;
D=3;
This kind of assignment is only possible if all the variable types in the statement are the same.
You can define your own types use typedef. This will have greater relevance later in the course when we learn how to create more complex data structures.
As an example of a simple use let us consider how we may define two new types real and letter. These new types can then be used in the same way as the pre-defined C types:
TYPEDEF REAL FLOAT;
TYPEDEF LETTER CHAR;
VARIABLES DECLARED:
REAL SUM=0.0;
LETTER NEXTLETTER;
PRINTING OUT AND INPUTTING VARIABLES
C uses formatted output. The printf function has a special formatting character (%) -- a character following this defines a certain format for a variable:
%C -- CHARACTERS
%D -- INTEGERS
%F -- FLOATS
E.G.
PRINTF(``%C %D %F'',CH,I,X);
NOTE:
FORMAT STATEMENT ENCLOSED IN ``...'', VARIABLES FOLLOW AFTER. MAKE SURE ORDER OF FORMAT AND VARIABLE DATA TYPES MATCH UP.
scanf() is the function for inputting values to a data structure: Its format is similar to printf:
I.E. SCANF(``%C %D %F'',&CH,&I,&X);
STATIC VARIABLES
A static variable is local to particular function. However, it is only initialised once (on the first call to function).
Also the value of the variable on leaving the function remains intact. On the next call to the function the the static variable has the same value as on leaving.
To define a static variable simply prefix the variable declaration with the static keyword.
For example:
VOID STAT(); /* PROTOTYPE FN */
MAIN()
{ INT I;
FOR (I=0;I<5 auto_var="" int="" printf="" stat="" static="%D" static_var="" u="">5>
Output is:
AUTO_VAR = 0, STATIC_VAR= 0
AUTO_VAR = 0, STATIC_VAR = 1
AUTO_VAR = 0, STATIC_VAR = 2
AUTO_VAR = 0, STATIC_VAR = 3
AUTO_VAR = 0, STATIC_VAR = 4
Clearly the auto_var variable is created each time. The static_var is created once and remembers its value.
CONSTANTS
ANSI C allows you to declare constants. When you declare a constant it is a bit like a variable declaration except the value cannot be changed.
The const keyword is to declare a constant, as shown below:
INT CONST A = 1;
CONST INT A =2;
Note:
You can declare the const before or after the type. Choose one an stick to it.
It is usual to initialise a const with a value as it cannot get a value any other way.
The preprocessor #define is another more flexible (see Preprocessor Chapters) method to define constants in a program.
You frequently see const declaration in function parameters.
This says simply that the function is not going to change the value of the parameter.
The following function definition used concepts we have not met (see chapters on functions, strings, pointers, and standard libraries) but for completenes of this section it is is included here:
VOID STRCPY(CHAR *BUFFER, CHAR CONST *STRING)
The second argiment string is a C string that will not be altered by the string copying standard library function.
SPECIAL CHARACTERS
The following special patterns are used to represent a single character in C programs. The leading backslash in the single quotes indicates that more information is to follow.
?
DYNAMIC MEMORY ALLOCATION AND DYNAMIC STRUCTURES
Dynamic allocation is a pretty unique feature to C (amongst high level languages).
It enables us to create data types and structures of any size and length to suit our programs need within the program.
We will look at two common applications of this:
dynamic arrays
dynamic data structure e.g. linked lists
MALLOC, SIZEOF, AND FREE
MALLOC
The Function malloc is most commonly used to attempt to ``grab'' a continuous portion of memory. It is defined by:
VOID *MALLOC(SIZE_T NUMBER_OF_BYTES)
That is to say it returns a pointer of type void * that is the start in memory of the reserved portion of size number_of_bytes. If memory cannot be allocated a NULL pointer is returned.
Since a void * is returned the C standard states that this pointer can be converted to any type. The size_t argument type is defined in stdlib.h and is an unsigned type.
So:
CHAR *CP;
CP = MALLOC(100);
attempts to get 100 bytes and assigns the start address to cp.
Also it is usual to use the sizeof() function to specify the number of bytes:
INT *IP;
IP = (INT *) MALLOC(100*SIZEOF(INT));
Some C compilers may require to cast the type of conversion. The (int *) means coercion to an integer pointer.
Coercion to the correct pointer type is very important to ensure pointer arithmetic is performed correctly.
It is good practice to use sizeof() even if you know the actual size you want -- it makes for device independent (portable) code.
SIZEOF
It can be used to find the size of any data type, variable or structure. Simply supply one of these as an argument to the function.
SO:
INT I;
STRUCT COORD {FLOAT X,Y,Z};
TYPEDEF STRUCT COORD PT;
SIZEOF(INT), SIZEOF(I),
SIZEOF(STRUCT COORD) AND
SIZEOF(PT) ARE ALL ACCEPTABLE
In the above we can use the link between pointers and arrays to treat the reserved memory like an array. i.e we can do things like:
IP[0] = 100;
Or
FOR(I=0;I<100 b="" scanf="">100>
FREE
When you have finished using a portion of memory you should always free() it. This allows the memory freed to be available again, possibly for further malloc() calls
The function free() takes a pointer as an argument and frees the memory to which the pointer refers.
CALLOC AND REALLOC
There are two additional memory allocation functions, Calloc() and Realloc(). Their prototypes are given below:
VOID *CALLOC(SIZE_T NUM_ELEMENTS, SIZE_T ELEMENT_SIZE};
VOID *REALLOC( VOID *PTR, SIZE_T NEW_SIZE);
Malloc does not initialise memory (to zero) in any way. If you wish to initialise memory then use calloc. Calloc there is slightly more computationally expensive but, occasionally, more convenient than malloc.
Also note the different syntax between calloc and malloc in that calloc takes the number of desired elements, num_elements, and element_size, element_size, as two individual arguments.
Thus to assign 100 integer elements that are all initially zero you would do:
INT *IP;
IP = (INT *) CALLOC(100, SIZEOF(INT));
Realloc is a function which attempts to change the size of a previous allocated block of memory. The new size can be larger or smaller.
If the block is made larger then the old contents remain unchanged and memory is added to the end of the block. If the size is made smaller then the remaining contents are unchanged.
If the original block size cannot be resized then realloc will attempt to assign a new block of memory and will copy the old block contents.
Note
A new pointer (of different value) will consequently be returned. You must use this new value. If new memory cannot be reallocated then realloc returns NULL.
Thus to change the size of memory allocated to the *ip pointer above to an array block of 50 integers instead of 100, simply do:
IP = (INT *) CALLOC( IP, 50);
COMMAND LINE ARGUMENTS
ACCEPTING COMMAND LINE ARGUMENTS IN C USING ARGC AND ARGV
Command-line arguments are given after the name of a program in command-line operating systems like DOS or Linux, and are passed in to the program from the operating system.
To use command line arguments in your program, you must first understand the full declaration of the main function, which previously has accepted no arguments.
In fact, main can actually accept two arguments: one argument is number of command line arguments, and the other argument is a full list of all of the command line arguments.
The full declaration of main looks like this:
INT MAIN ( INT ARGC, CHAR *ARGV[] )
The integer, argc is the argument count. It is the number of arguments passed into the program from the command line, including the name of the program.
The array of character pointers is the listing of all the arguments. argv[0] is the name of the program, or an empty string if the name is not available.
After that, every element number less than argc is a command line argument. You can use each argv element just like a string, or use argv as a two dimensional array. argv[argc] is a null pointer.
How could this be used? Almost any program that wants its parameters to be set when it is executed would use this.
One common use is to write a function that takes the name of a file and outputs the entire text of it onto the screen.
#INCLUDE
INT MAIN ( INT ARGC, CHAR *ARGV[] )
{
IF ( ARGC != 2 ) /* ARGC SHOULD BE 2 FOR CORRECT EXECUTION */
{
/* WE PRINT ARGV[0] ASSUMING IT IS THE PROGRAM NAME */
PRINTF( "USAGE: %S FILENAME", ARGV[0] );
}
ELSE
{
// WE ASSUME ARGV[1] IS A FILENAME TO OPEN
FILE *FILE = FOPEN( ARGV[1], "R" );
/* FOPEN RETURNS 0, THE NULL POINTER, ON FAILURE */
IF ( FILE == 0 )
{
PRINTF( "COULD NOT OPEN FILE\N" );
}
ELSE
{
INT X;
/* READ ONE CHARACTER AT A TIME FROM FILE, STOPPING AT EOF, WHICH
INDICATES THE END OF THE FILE. NOTE THAT THE IDIOM OF "ASSIGN
TO A VARIABLE, CHECK THE VALUE" USED BELOW WORKS BECAUSE
THE ASSIGNMENT STATEMENT EVALUATES TO THE VALUE ASSIGNED. */
WHILE ( ( X = FGETC( FILE ) ) != EOF )
{
PRINTF( "%C", X );
}
FCLOSE( FILE );
}
}
}
This program is fairly short, but it incorporates the full version of main and even performs a useful function.
It first checks to ensure the user added the second argument, theoretically a file name.
The program then checks to see if the file is valid by trying to open it.
This is a standard operation, and if it results in the file being opened, then the return value of fopen will be a valid FILE*; otherwise, it will be 0, the NULL pointer.
After that, we just execute a loop to print out one character at a time from the file.
TYPE CONVERSION
You can mix the types of values in your arithmetic expressions. char types will be treated as int.
Otherwise where types of different size are involved, the result will usually be of the larger size, so a float and a double would produce a double result. Where integer and real types meet, the result will be a double.
There is usually no trouble in assigning a value to a variable of different type. The value will be preserved as expected except where;
The variable is too small to hold the value. In this case it will be corrupted (this is bad).
The variable is an integer type and is being assigned a real value. The value is rounded down. This is often done deliberately by the programmer.
Values passed as function arguments must be of the correct type. The function has no way of determining the type passed to it, so automatic conversion cannot take place.
This can lead to corrupt results. The solution is to use a method called casting which temporarily disguises a value as a different type.
eg. The function sqrt finds the square root of a double.
INT I = 256;
INT ROOT
ROOT = SQRT( (DOUBLE) I);
The cast is made by putting the bracketed name of the required type just before the value. (double) in this example.
The result of sqrt( (double) i); is also a double, but this is automatically converted to an int on assignment to root.
COERCION OR TYPE-CASTING
C is one of the few languages to allow coercion, that is forcing one variable of one type to be another type. C allows this using the cast operator (). So:
INT INTEGERNUMBER;
FLOAT FLOATNUMBER=9.87;
INTEGERNUMBER=(INT)FLOATNUMBER;
assigns 9 (the fractional part is thrown away) to integernumber.
And:
INT INTEGERNUMBER=10;
FLOAT FLOATNUMBER;
FLOATNUMBER=(FLOAT)INTEGERNUMBER;
assigns 10.0 to floatnumber.
Coercion can be used with any of the simple data types including char, so:
INT INTEGERNUMBER;
CHAR LETTER='A';
INTEGERNUMBER=(INT)LETTER;
assigns 65 (the ASCII code for `A') to integernumber.
Some typecasting is done automatically -- this is mainly with integer compatibility.
A good rule to follow is: If in doubt cast.
Another use is the make sure division behaves as requested: If we have two integers internumber and anotherint and we want the answer to be a float then :
e.g.
FLOATNUMBER =
(FLOAT) INTERNUMBER / (FLOAT) ANOTHERINT;
ensures floating point division.
BASIC I/O
There are a couple of function that provide basic I/O facilities.
probably the most common are: getchar() and putchar(). They are defined and
used as follows:
int getchar(void) -- reads a char from stdin
int putchar(char ch) -- writes a char to stdout, returns character written.
INT CH;
CH = GETCHAR();
(VOID) PUTCHAR((CHAR) CH);
Related Functions:
INT GETC(FILE *STREAM);
INT PUTC(CHAR CH,FILE *STREAM);
FORMATTED I/O
We have seen examples of how C uses formatted I/O already. Let's look at this
in more detail.
The following format strings can be used to specify data to be printed or read
using the printf or scanf functions, or any of their variants; fprintf,
sprintf, fscanf or sscanf .
Note that though all can be used with the printf variants, some are not
available for scanf.
?
PRINTF
The function is defined as follows:
INT PRINTF(CHAR *FORMAT, ARG LIST ...) --
prints to stdout the list of arguments according specified format string.
Returns number of characters printed.
The format string has 2 types of object:
Ordinary characters -- these are copied to output.
conversion specifications -- denoted by % and listed in Table.
Between % and format char we can put: - (minus sign) -- left justify.
integer number -- field width.
m.d -- m = field width, d = precision of number of digits after decimal point
or number of chars from a string.
So:
PRINTF("%-2.3F?N",17.23478);
The output on the screen is:
17.235
and:
PRINTF("VAT=17.5%%?N");
...outputs:
VAT=17.5%
SCANF
This function is defined as follows:
int scanf(char *format, args....) -- reads from stdin and puts input in
address of variables specified in
args list.
Returns number of chars read.
Format control string similar to printf
Note:
The ADDRESS of variable or a pointer to one is required by scanf.
SCANF(``%D'',&I);
We can just give the name of an array or string to scanf since this
corresponds to the start address of the array/string.
CHAR STRING[80];
SCANF(``%S'',STRING);

No comments:
Post a Comment