Share this:
VARIATIONS IN DECLARING STRUCTURES
Consider the following,
Consider the following,
struct date {
int month, day, year;
} todays_date, purchase_date;
or another way is,
struct date {
int month, day, year;
} todays_date = { 9,25,1985 };
or, how about an array of structures similar to date,
struct date {
int month, day, year;
} dates[100];
Declaring structures in this way, however, prevents you from using the structure definition later in the program. The structure definition is thus bound to the variable name which follows the right brace of the structures definition.
CLASS EXERCISE C22
Write a program to enter in five dates, Store this information in an array of structures.
Write a program to enter in five dates, Store this information in an array of structures.
CLASS EXERCISE C22
#include
struct date { /* Global definition of date */
int day, month, year;
};
main()
{
struct date dates[5];
int i;
for( i = 0; i < 5; ++i ) {
printf(“Please enter the date (dd:mm:yy)” );
scanf(“%d:%d:%d”, &dates[i].day, &dates[i].month,
&dates[i].year );
}
}
STRUCTURES WHICH CONTAIN STRUCTURES
Structures can also contain structures. Consider where both a date and time structure are combined into a single structure called date_time, eg,
Structures can also contain structures. Consider where both a date and time structure are combined into a single structure called date_time, eg,
struct date {
int month, day, year;
};
struct time {
int hours, mins, secs;
};
struct date_time {
struct date sdate;
struct time stime;
};
This declares a structure whose elements consist of two other previously declared structures. Initialization could be done as follows,
static struct date_time today = { { 2, 11, 1985 }, { 3, 3,33 } };
which sets the sdate element of the structure today to the eleventh of February, 1985. The stime element of the structure is initialized to three hours, three minutes, thirty-three seconds. Each item within the structure can be referenced if desired, eg,
++today.stime.secs;
if( today.stime.secs == 60 ) ++today.stime.mins;
BIT FIELDS
Consider the following data elements defined for a PABX telephone system.
Consider the following data elements defined for a PABX telephone system.
flag = 1 bit
off_hook = 1 bit
status = 2 bits
In C, these can be defined as a structure, and the number of bits each occupy can be specified.
struct packed_struct {
unsigned int flag:1;
unsigned int off_hook:1;
unsigned int status:2;
} packed_struct1;
The :1 following the variable flag indicates that flag occupies a single bit. The C compiler will assign all the above fields into a single word.
Assignment is as follows,
packed_struct1.flag = 0;
packed_struct1.status = 3;
if( packed_struct1.flag )
………….
Practise Exercise 9: Structures
1. Define a structure called record which holds an integer called loop, a character array of 5 elements called word, and a float called sum.
2. Declare a structure variable called sample, defined from a structure of type record.
3. Assign the value 10 to the field loop of the sample structure of type record.
4. Print out (using printf) the value of the word array of the sample structure.
5. Define a new structure called birthdays, whose fields are a structure of type time called btime, and a structure of type date, called bdate.
Practice Exercise 9: Structures( Answers)
1. Define a structure called record which holds an integer called loop, a character array of 5 elements called word, and a float called sum.
struct record {
int loop;
char word[5];
float sum;
};
2. Declare a structure variable called sample, defined from a structure of type struct record.
struct record sample;
3. Assign the value 10 to the field loop of the sample structure of type struct record.
sample.loop = 10;
4. Print out (using printf) the value of the word array of the sample structure.
printf(“%s”, sample.word );
5. Define a new structure called birthdays, whose fields are a structure of type struct time called btime, and a structure of type struct date, called bdate.
struct birthdays {
struct time btime;
struct date bdate;
};
DATA CONVERSION
The following functions convert between data types.
The following functions convert between data types.
atof() converts an ascii character array to a float
atoi() converts an ascii character array to an integer
itoa() converts an integer to a character array
Example
/* convert a string to an integer */
#include
#include
char string[] = “1234”;
main()
{
int sum;
sum = atoi( string );
printf(“Sum = %dn”, sum );
}
/* convert an integer to a string */
#include
#include
main()
{
int sum;
char buff[20];
printf(“Enter in an integer “);
scanf(” %d”, &sum );
printf( “As a string it is %sn”, itoa( sum, buff, 10 ) );
}
Note that itoa() takes three parameters,
- the integer to b converted
- a character buffer into which the resultant string is stored
- a radix value (10=decimal,16=hexadecimal)
In addition, itoa() returns a pointer to the resultant string.
FILE INPUT/OUTPUT
To work with files, the library routines must be included into your programs. This is done by the statement,
To work with files, the library routines must be included into your programs. This is done by the statement,
#include
as the first statement of your program.
- Associate the variable with a file using fopen()
Before using the variable, it is associated with a specific file by using the fopen() function, which accepts the pathname for the file and the access mode (like reading or writing).
in_file = fopen( “myfile.dat”, “r” )
In this example, the file myfile.dat in the current directory is opened for read access.
Process the data in the file
Use the appropriate file routines to process the data
When finished processing the file, close it
Use the fclose() function to close the file.
fclose( in_file );
USING FILES
- Declare a variable of type FILE
To use files in C programs, you must declare a file variable to use. This variable must be of type FILE, and be declared as a pointer type.
FILE is a predefined type. You declare a variable of this type as
FILE *in_file;
This declares infile to be a pointer to a file.
The following illustrates the fopen function, and adds testing to see if the file was opened successfully.
#include
/* declares pointers to an input file, and the fopen function */
FILE *input_file, *fopen ();
/* the pointer of the input file is assigned the value returned from the fopen call. */
/* fopen tries to open a file called datain for read only. Note that */
/* “w” = write, and “a” = append. */
input_file = fopen(“datain”, “r”);
/* The pointer is now checked. If the file was opened, it will point to the first */
/* character of the file. If not, it will contain a NULL or 0. */
if( input_file == NULL ) {
printf(“*** datain could not be opened.n”);
printf(“returning to dos.n”);
exit(1);
}
NOTE: Consider the following statement, which combines the opening of the file and its test to see if it was successfully opened into a single statement.
if(( input_file = fopen (“datain”, “r” )) == NULL ) {
printf(“*** datain could not be opened.n”);
printf(“returning to dos.n”);
exit(1);
}
INPUTTING/OUTPUTTING SINGLE CHARACTERS
Single characters may be read/written with files by use of the two functions, getc(), and putc().
Single characters may be read/written with files by use of the two functions, getc(), and putc().
int ch;
ch = getc( input_file ); /* assigns character to ch */
The getc() also returns the value EOF (end of file), so
while( (ch = getc( input_file )) != EOF )
………………….
NOTE that the putc/getc are similar to getchar/putchar except that arguments are supplied specifying the I/O device.
putc(‘n’, output_file ); /* writes a newline to output file */
CLOSING FILES
When the operations on a file are completed, it is closed before the program terminates. This allows the operating system to cleanup any resources or buffers associated with the file. The fclose() function is used to close the file and flush any buffers associated with the file.
When the operations on a file are completed, it is closed before the program terminates. This allows the operating system to cleanup any resources or buffers associated with the file. The fclose() function is used to close the file and flush any buffers associated with the file.
fclose( input_file );
fclose( output_file );
COPYING A FILE
The following demonstrates copying one file to another using the functions we have just covered.
The following demonstrates copying one file to another using the functions we have just covered.
#include
main() /* FCOPY.C */
{
char in_name[25], out_name[25];
FILE *in_file, *out_file, *fopen ();
int c;
printf(“File to be copied:n”);
scanf(“%24s”, in_name);
printf(“Output filename:n”);
scanf(“%24s”, out_name);
in_file = fopen ( in_name, “r”);
if( in_file == NULL )
printf(“Cannot open %s for reading.n”, in_name);
else {
out_file = fopen (out_name, “w”);
if( out_file == NULL )
printf(“Can’t open %s for writing.n”,out_name);
else {
while( (c = getc( in_file)) != EOF )
putc (c, out_file);
putc (c, out_file); /* copy EOF */
printf(“File has been copied.n”);
fclose (out_file);
}
fclose (in_file);
}
}
TESTING FOR THE End Of File TERMINATOR (feof)
This is a built in function incorporated with the stdio.h routines. It returns 1 if the file pointer is at the end of the file.
This is a built in function incorporated with the stdio.h routines. It returns 1 if the file pointer is at the end of the file.
if( feof ( input_file ))
printf(“Ran out of data.n”);
THE fprintf AND fscanf STATEMENTS
These perform the same function as printf and scanf, but work on files. Consider,
These perform the same function as printf and scanf, but work on files. Consider,
fprintf(output_file, “Now is the time for all..n”);
fscanf(input_file, “%f”, &float_value);
THE fgets AND fputs STATEMENTS
These are useful for reading and writing entire lines of data to/from a file. If buffer is a pointer to a character array and n is the maximum number of characters to be stored, then
These are useful for reading and writing entire lines of data to/from a file. If buffer is a pointer to a character array and n is the maximum number of characters to be stored, then
fgets (buffer, n, input_file);
will read an entire line of text (max chars = n) into buffer until the newline character or n=max, whichever occurs first. The function places a NULL character after the last character in the buffer. The function will be equal to a NULL if no more data exists.
fputs (buffer, output_file);
writes the characters in buffer until a NULL is found. The NULL character is not written to the output_file.
NOTE: fgets does not store the newline into the buffer, fputs will append a newline to the line written to the output file.
Practise Exercise 9A: File Handling
1. Define an input file handle called input_file, which is a pointer to a type FILE.
2. Using input_file, open the file results.dat for read mode as a text file.
3. Write C statements which tests to see if input_file has opened the data file successfully. If not, print an error message and exit the program.
4. Write C code which will read a line of characters (terminated by a n) from input_file into a character array called buffer. NULL terminate the buffer upon reading a n.
5. Close the file associated with input_file.
Practise Exercise 9A: File Handling (Answers)
1. Define an input file handle called input_file, which is a pointer to a type FILE.
FILE *input_file;
2. Using input_file, open the file results.dat for read mode.
input_file = fopen( “results.dat”, “r” );
3. Write C statements which tests to see if input_file has opened the data file successfully. If not, print an error message and exit the program.
if( input_file == NULL ) {
printf(“Unable to open file.n”);
exit(1);
}
4. Write C code which will read a line of characters (terminated by a n) from input_file into a character array called buffer. NULL terminate the buffer upon reading a n.
int ch, loop = 0;
ch = fgetc( input_file );
while( (ch != ‘n’) && (ch != EOF) ) {
buffer[loop] = ch;
loop++;
ch = fgetc( input_file );
}
buffer[loop] = NULL;
5. Close the file associated with input_file.
fclose( input_file );
File handling using open(), read(), write() and close()
The previous examples of file handling deal with File Control Blocks (FCB). Under MSDOS v3.x (or greater) and UNIX systems, file handling is often done using handles, rather than file control blocks.
The previous examples of file handling deal with File Control Blocks (FCB). Under MSDOS v3.x (or greater) and UNIX systems, file handling is often done using handles, rather than file control blocks.
Writing programs using handles ensures portability of source code between different operating systems. Using handles allows the programmer to treat the file as a stream of characters.
open()
#include
int open( char *filename, int access, int permission );
The available access modes are
O_RDONLY O_WRONLY O_RDWR
O_APPEND O_BINARY O_TEXT
The permissions are
S_IWRITE S_IREAD S_IWRITE | S_IREAD
The open() function returns an integer value, which is used to refer to the file. If un- successful, it returns -1, and sets the global variable errno to indicate the error type.
read()
#include
int read( int handle, void *buffer, int nbyte );
The read() function attempts to read nbytes from the file associated with handle, and places the characters read into buffer. If the file is opened using O_TEXT, it removes carriage returns and detects the end of the file.
The function returns the number of bytes read. On end-of-file, 0 is returned, on error it returns -1, setting errno to indicate the type of error that occurred.
write()
#include
int write( int handle, void *buffer, int nbyte );
The write() function attempts to write nbytes from buffer to the file associated with handle. On text files, it expands each LF to a CR/LF.
The function returns the number of bytes written to the file. A return value of -1 indicates an error, with errno set appropriately.
close()
#include
int close( int handle );
The close() function closes the file associated with handle. The function returns 0 if successful, -1 to indicate an error, with errno set appropriately.
File handling example of a goods re-ordering program
The following program handles an ASCII text file which describes a number of products, and reads each product into a structure with the program.
The following program handles an ASCII text file which describes a number of products, and reads each product into a structure with the program.
/* File handling example for PR101 */
/* processing an ASCII file of records */
/* Written by B. Brown, April 1994 */
/* */
/* process a goods file, and print out */
/* all goods where the quantity on */
/* hand is less than or equal to the */
/* re-order level. */
#include
#include
#include
#include
/* definition of a record of type goods */
struct goods {
char name[20]; /* name of product */
float price; /* price of product */
int quantity; /* quantity on hand */
int reorder; /* re-order level */
};
/* function prototypes */
void myexit( int );
void processfile( void );
void printrecord( struct goods );
int getrecord( struct goods * );
/* global data variables */
FILE *fopen(), *input_file; /* input file pointer */
/* provides a tidy means to exit program gracefully */
void myexit( int exitcode )
{
if( input_file != NULL )
fclose( input_file );
exit( exitcode );
}
/* prints a record */
void printrecord( struct goods record )
{
printf(“nProduct namet%sn”, record.name );
printf(“Product pricet%.2fn”, record.price );
printf(“Product quantityt%dn”, record.quantity );
printf(“Product reorder levelt%dn”, record.reorder );
}
/* reads one record from inputfile into ‘record’, returns 1 for success */
int getrecord( struct goods *record )
{
int loop = 0, ch;
char buffer[40];
ch = fgetc( input_file );
/* skip to start of record */
while( (ch == ‘n’) || (ch == ‘ ‘) && (ch != EOF) )
ch = fgetc( input_file );
if( ch == EOF ) return 0;
/* read product name */
while( (ch != ‘n’) && (ch != EOF)) {
buffer[loop++] = ch;
ch = fgetc( input_file );
}
buffer[loop] = 0;
strcpy( record->name, buffer );
if( ch == EOF ) return 0;
/* skip to start of next field */
while( (ch == ‘n’) || (ch == ‘ ‘) && (ch != EOF) )
ch = fgetc( input_file );
if( ch == EOF ) return 0;
/* read product price */
loop = 0;
while( (ch != ‘n’) && (ch != EOF)) {
buffer[loop++] = ch;
ch = fgetc( input_file );
}
buffer[loop] = 0;
record->price = atof( buffer );
if( ch == EOF ) return 0;
/* skip to start of next field */
while( (ch == ‘n’) || (ch == ‘ ‘) && (ch != EOF) )
ch = fgetc( input_file );
if( ch == EOF ) return 0;
/* read product quantity */
loop = 0;
while( (ch != ‘n’) && (ch != EOF)) {
buffer[loop++] = ch;
ch = fgetc( input_file );
}
buffer[loop] = 0;
record->quantity = atoi( buffer );
if( ch == EOF ) return 0;
/* skip to start of next field */
while( (ch == ‘n’) || (ch == ‘ ‘) && (
ch != EOF) )
ch != EOF) )
ch = fgetc( input_file );
if( ch == EOF ) return 0;
/* read product reorder level */
loop = 0;
while( (ch != ‘n’) && (ch != EOF)) {
buffer[loop++] = ch;
ch = fgetc( input_file );
}
buffer[loop] = 0;
record->reorder = atoi( buffer );
if( ch == EOF ) return 0;
return 1; /* signify record has been read successfully */
}
/* processes file for records */
void processfile( void )
{
struct goods record; /* holds a record read from inputfile */
while( ! feof( input_file )) {
if( getrecord( &record ) == 1 ) {
if( record.quantity <= record.reorder )
printrecord( record );
}
else myexit( 1 ); /* error getting record */
}
}
main()
{
char filename[40]; /* name of database file */
printf(“Example Goods Re-Order File Programn”);
printf(“Enter database file “);
scanf(” %s”, filename );
input_file = fopen( filename, “rt” );
if( input_file == NULL ) {
printf(“Unable to open datafile %sn”, filename );
myexit( 1 );
}
processfile();
myexit( 0 );
}
The datafile (a standard ASCII text file) used for this example looks like
baked beans
1.20
10
5
greggs coffee
2.76
5
10
walls ice-cream
3.47
5
5
cadburys chocs
4.58
12
10
POINTERS
Pointers enable us to effectively represent complex data structures, to change values as arguments to functions, to work with memory which has been dynamically allocated, and to more concisely and efficiently deal with arrays. A pointer provides an indirect means of accessing the value of a particular data item. Lets see how pointers actually work with a simple example,
Pointers enable us to effectively represent complex data structures, to change values as arguments to functions, to work with memory which has been dynamically allocated, and to more concisely and efficiently deal with arrays. A pointer provides an indirect means of accessing the value of a particular data item. Lets see how pointers actually work with a simple example,
int count = 10, *int_pointer;
declares an integer count with a value of 10, and also an integer pointer called int_pointer. Note that the prefix * defines the variable to be of type pointer. To set up an indirect reference between int_pointer and count, the & prefix is used, ie,
int_pointer = &count
This assigns the memory address of count to int_pointer, not the actual value of count stored at that address.
POINTERS CONTAIN MEMORY ADDRESSES, NOT VALUES!
To reference the value of count using int_pointer, the * is used in an assignment, eg,
x = *int_pointer;
Since int_pointer is set to the memory address of count, this operation has the effect of assigning the contents of the memory address pointed to by int_pointer to the variable x, so that after the operation variable x has a value of 10.
#include
main()
{
int count = 10, x, *int_pointer;
/* this assigns the memory address of count to int_pointer */
int_pointer = &count;
/* assigns the value stored at the address specified by int_pointer to x */
x = *int_pointer;
printf(“count = %d, x = %dn”, count, x);
}
This however, does not illustrate a good use for pointers.
The following program illustrates another way to use pointers, this time with characters,
#include
main()
{
char c = ‘Q’;
char *char_pointer = &c;
printf(“%c %cn”, c, *char_pointer);
c = ‘Z’;
printf(“%c %cn”, c, *char_pointer);
*char_pointer = ‘Y’;
/* assigns Y as the contents of the memory address specified by char_pointer */
printf(“%c %cn”, c, *char_pointer);
}
CLASS EXERCISE C23
Determine the output of the pointer programs P1, P2, and P3.
Determine the output of the pointer programs P1, P2, and P3.
/* P1.C illustrating pointers */
#include
main()
{
int count = 10, x, *int_pointer;
/* this assigns the memory address of count to int_pointer */
int_pointer = &count;
/* assigns the value stored at the address specified by int_pointer to x */
x = *int_pointer;
printf(“count = %d, x = %dn”, count, x);
}
/* P2.C Further examples of pointers */
#include
main()
{
char c = ‘Q’;
char *char_pointer = &c;
printf(“%c %cn”, c, *char_pointer);
c = ‘/’;
printf(“%c %cn”, c, *char_pointer);
*char_pointer = ‘(‘;
/* assigns ( as the contents of the memory address specified by char_pointer */
printf(“%c %cn”, c, *char_pointer);
}
CLASS EXERCISE C24
/* P3.C Another program with pointers */
#include
main()
{
int i1, i2, *p1, *p2;
i1 = 5;
p1 = &i1;
i2 = *p1 / 2 + 10;
p2 = p1;
printf(“i1 = %d, i2 = %d, *p1 = %d, *p2 = %dn”, i1, i2, *p1, *p2);
}
CLASS EXERCISE C25
Determine the output of the pointer programs P1, P2, and P3.
Determine the output of the pointer programs P1, P2, and P3.
/* P1.C illustrating pointers */
#include
main()
{
int count = 10, x, *int_pointer;
/* this assigns the memory address of count to int_pointer */
int_pointer = &count;
/* assigns the value stored at the address specified by int_pointer to x */
x = *int_pointer;
printf(“count = %d, x = %dn”, count, x);
}
count = 10, x = 10;
/* P2.C Further examples of pointers */
#include
main()
{
char c = ‘Q’;
char *char_pointer = &c;
printf(“%c %cn”, c, *char_pointer);
c = ‘/’;
printf(“%c %cn”, c, *char_pointer);
*char_pointer = ‘(‘;
/* assigns ( as the contents of the memory address specified by char_pointer */
printf(“%c %cn”, c, *char_pointer);
}
Q Q
/ /
( (
/* P3.C Another program with pointers */
#include
main()
{
int i1, i2, *p1,
*p2;
*p2;
i1 = 5;
p1 = &i1;
i2 = *p1 / 2 + 10;
p2 = p1;
printf(“i1 = %d, i2 = %d, *p1 = %d, *p2 = %dn”, i1, i2, *p1, *p2);
}
i1 = 5, i2 = 12, *p1 = 5, *p2 = 5
Practice Exercise 10: Pointers
1. Declare a pointer to an integer called address.
2. Assign the address of a float variable balance to the float pointer temp.
3. Assign the character value ‘W’ to the variable pointed to by the char pointer letter.
4. What is the output of the following program segment?
int count = 10, *temp, sum = 0;
temp = &count;
*temp = 20;
temp = ∑
*temp = count;
printf(“count = %d, *temp = %d, sum = %dn”, count, *temp, sum );
5. Declare a pointer to the text string “Hello” called message.
Practise Exercise 10: Pointers
1. Declare a pointer to an integer called address.
1. Declare a pointer to an integer called address.
int *address;
2. Assign the address of a float variable balance to the float pointer temp.
temp = &balance;
3. Assign the character value ‘W’ to the variable pointed to by the char pointer letter.
*letter = ‘W’;
4. What is the output of the following program segment?
int count = 10, *temp, sum = 0;
temp = &count;
*temp = 20;
temp = ∑
*temp = count;
printf(“count = %d, *temp = %d, sum = %dn”, count, *temp, sum );
count = 20, *temp = 20, sum = 20
5. Declare a pointer to the text string “Hello” called message.
char *message = “Hello”;
POINTERS AND STRUCTURES
Consider the following,
Consider the following,
struct date {
int month, day, year;
};
struct date todays_date, *date_pointer;
date_pointer = &todays_date;
(*date_pointer).day = 21;
(*date_pointer).year = 1985;
(*date_pointer).month = 07;
++(*date_pointer).month;
if((*date_pointer).month == 08 )
……
Pointers to structures are so often used in C that a special operator exists. The structure pointer operator, the ->
;, permits expressions that would otherwise be written as,
;, permits expressions that would otherwise be written as,
(*x).y
to be more clearly expressed as
x->y
making the if statement from above program
if( date_pointer->month == 08 )
…..
/* Program to illustrate structure pointers */
#include
main()
{
struct date { int month, day, year; };
struct date today, *date_ptr;
date_ptr = &today;
date_ptr->month = 9;
date_ptr->day = 25;
date_ptr->year = 1983;
printf(“Todays date is %d/%d/%d.n”, date_ptr->month,
date_ptr->day, date_ptr->year % 100);
}
So far, all that has been done could’ve been done without the use of pointers. Shortly, the real value of pointers will become apparent.
STRUCTURES CONTAINING POINTERS
Naturally, a pointer can also be a member of a structure.
Naturally, a pointer can also be a member of a structure.
struct int_pointers {
int *ptr1;
int *ptr2;
};
In the above, the structure int_pointers is defined as containing two integer pointers, ptr1 and ptr2. A variable of type struct int_pointers can be defined in the normal way, eg,
struct int_pointers ptrs;
The variable ptrs can be used normally, eg, consider the following program,
#include
main() /* Illustrating structures containing pointers */
{
struct int_pointers { int *ptr1, *ptr2; };
struct int_pointers ptrs;
int i1 = 154, i2;
ptrs.ptr1 = &i1;
ptrs.ptr2 = &i2;
*ptrs.ptr2 = -97;
printf(“i1 = %d, *ptrs.ptr1 = %dn”, i1, *ptrs.ptr1);
printf(“i2 = %d, *ptrs.ptr2 = %dn”, i2, *ptrs.ptr2);
}
The following diagram may help to illustrate the connection,
|————|
| i1 |<--------------
|————| |
| i2 |
|————| | |
| | | |
|————| | |
| ptr1 |—————
|————| | ptrs
| ptr2 |——–
|————|
POINTERS AND CHARACTER STRINGS
A pointer may be defined as pointing to a character string.
A pointer may be defined as pointing to a character string.
#include
main()
{
char *text_pointer = “Good morning!”;
for( *text_pointer != ‘