Vous êtes sur la page 1sur 10

LECTURE THREE FILES, STRUCTURES AND MEMORY

ALLOCATION
What these lecture notes coer
These lecture notes should cover the following topics:
File handling in C.
Special streams stdin, stdout and stderr.
Defining new types of variable struct and typedef.
Dynamic memory (the point of pointers
! recap of new language features from wee" three.
#ecture Three $ Files, Structures and %emory !llocation........................................................................&
'hat these lecture notes cover..............................................................................................................&
File handling in C..................................................................................................................................&
(ailing out in an emergency (the e)it command..................................................................................*
+eading from a file fgets and fscanf......................................................................................................*
Special streams stdin, stdout and stderr...................................................................................,
-ow we S-./#D read input from the user (fgets, atoi and atof...........................................,
!dding new types to C typedef and struct statements.................................................................0
Dynamic memory allocation..................................................................................................................1
! note about returning pointers from functions.....................................................................................2
! recap of synta) learned in wee" three................................................................................................3
F!le han"l!n# !n C$
To read and write files in C, we use a special pointer type, FILE *. FILE * is a special pointer type
which contains information about how to open, close, write to and read from files.
The first thing that we must do with any file is to open it using fopen. The fopen command has
several formats. -ere are three e)amples:
#define FILE3 "file3.txt"
FILE *fptr; /* Declare a file pointer */
car filena!e"#$ "file%.txt"; /* &tring containing a file na!e */
fptr$ fopen '"file(.txt","r"); /* *pen file ( for reading */
fptr$ fopen 'filena!e,"+"); /* *pen te file in filena!e for +riting
,is +ill delete te current contents of
te file so -e ./0EF1L */
fptr$ fopen 'FILE3,"a"); /* *pen te file in "file3.txt" for
appending 2 tat is to say tat ne+ -its
of te file +ill -e +ritten after te
current file */
4ach of these e)amples would set fptr to point at the re5uested file.
IM%ORTANT RULE: /se a FILE * type variable (called a file pointer to store information about
your file. /se fopen to attempt to open the file in the appropriate way. fopen returns 31LL if it
fails to open the file. 6/## is a special pointer location which is set to indicate 7this pointer is not
pointing at anything7.
'e can chec" if we got the file open using:
&
if 'fptr $$ 31LL) 4
printf '"5ro-le! opening te file6n");
/* ,a7e so!e appropriate action 2 for exa!ple, return fro!
!ain */
8
This is 4++.+ C-4C896: (chec"ing that the file was open and is very important. 9 will tal" more
about this later in the course.
9f we have opened the file for writing or appending then we can use fprintf ;ust the same as
printf but its first argument should be the name of the file pointer. For e)ample to print 7-ello
'orld7 to the file output.t)t opened using fptr:
#include 9stdio.:
int !ain'int argc, car *arg;"#)
4
FILE *fptr;
fptr$ fopen '"+", "output.txt");
if 'fptr $$ 31LL) 4
fprintf 'stderr, ".ould not open output.txt6n");
return 2(;
8
fprintf 'fptr, "<ello =orld>6n");
fclose 'fptr);
return ?;
8
.f course you can<t 5uite be sure where on your dis" the file will be written. This will depend on the
particular computer you run it on. =F9> %4???@
&a!l!n# out !n an e'er#enc( )the e*!t co''an"+
'hat do you do if you run out of memoryA .r if your program finds some other unrecoverable
problem (a file you need isn<t there to be read. .ne option is ;ust to ;ust print an error message and
stop. (ut if you are deep in a function within a function then stopping itself might be a problem. The
solution is the exit function which lives in 9stdli-.:
'ithin a function you can write:
exit'@(); /* *r +ate;er nu!-er you +ant to exit +it */
This acts e)actly the same as if we had returned that value from main. This is almost only ever used
when you have a problem with your code. (For e)ample a file is missing or you have run out of
memory.
Rea"!n# ,ro' a ,!le ,#ets an" ,scan,
9f we have opened the file for reading then we can use fscanf in the same way as scanf but, again,
its first argument should be the name of the file pointer. For e)ample:
FILE *filepointer%; /* File pointer */
int i; /* integer to -e read */
int noAread; /* .ec7 on nu!-er of tings read */
filepointer%$ fopen '"!yfile.dat","r"); /* *pen te file for read */
/* 5ut in cec7s ere to !a7e sure it is open */
/* 1se fscanf to try to get an int */
noAread$ fscanf'filepointer,"Bd",Ci);
if 'noAread $$ E*F) 4
printf '"End of file>6n");
*
/* Do so!eting a-out tis error */
8
/* =e expected to read ( integer 2 cec7 tis */
if 'noAread >$ () 4
printf'"1na-le to read an int6n");
/* Do so!eting a-out tis error */
8
IM%ORTANT RULE: The fscanf function, li"e scanf returns the number of arguments which it
has successfully read. 9t returns the special value E*F (end of file if it has reached the end of the file.
! better way to read from a file is the fgets function. fgets ta"es three arguments $ a string to be
read into, a number of characters to read and a FILE * pointer to read from. fgets returns a pointer
to the string or, if it encounters end of file or some other reading error it returns 31LL.
!n e)ample of use of fgets is shown below:
const int D/ELE3 (???;
FILE *fptr;
car readline "D/ELE3#;
fptr$ fopen '"test.dat","r");
/* .ec7 +e got te file open */
+ile ' fgets'readline, D/ELE3, fptr) >$ 31LL) 4
/* Do so!eting +it readline ere */
8
Bou might find the +ile loop confusing here $ it is doing an awful lot of wor". 9t is actually 5uite
common in C to put a function within the +ile loop. Finally, having read from a file, it is
important that we 7close7 the file again. 'e do this using fclose.
fclose'fptr);
(eginners often forget that fopen needs a file name but fclose needs a filepointer.
S-ec!al strea's stdin, stdout an" stderr
!s mentioned in the previous wor"sheet there are three special streams of type FILE * which can be
used with routines which ta"e FILE * arguments. These streams are all defined in stdio.
stdin gets input from the "eyboard.
stdout puts output to the screen.
stderr puts output to an error stream (usually also the screen.
The difference between printing to stderr and stdout is subtle. Sometimes, output can be
redirected into a file (often using a system called 7pipes7 which 9 will not tal" about on this course.
4rrors often want to be handled differently. 9t is a good habit for a C programmer should print errors
li"e so:
fprintf 'stderr,",ere is an error6n");
9f a message is a critical error in your program you should print it li"e this rather than using printf
although you will see no difference between them.
Ho. .e SHOULD rea" !n-ut ,ro' the user )fgets, atoi an" atof+
The best way to read a line of input from the user is to use fgets with the stdin file handle.
,
car line"(???#;
fgets 'line, (???, stdin);
/*0eads at !ost (??? caracters fro! stdin or until te user presses
return */
-aving read a line of te)t from the "eyboard into a string, we can then use various conversion utilities
in stdli-.
For e)ample atoi ta"es a string and returns an integer. atof ta"es a string and returns a dou-le.
int i;
dou-le f;
car string"#$ "%3";
car string%"#$ "(%.(";
i$ atoi 'string); /* &ets i to %3 */
f$ atof 'string%); /* &ets f to (%.( */
CAUTIONF fgets from stdin puts a G6nG character on the end of the string (from where the
user typed G6nG to end the line. Sometimes we need to strip this G6nG to use the string. 'e can do
this by treating the string as a character array and moving along it until we find a G6nG then replacing
the G6nG with a G6?G.
A""!n# ne. t(-es to C typedef an" struct state'ents
Bou might be wondering about that peculiar FILE thing that seems to be usable li"e an int or a
float in functions. FILE is an e)ample of an important part of the C language "nown as a
structure. ! structure is a built up part of the C language which behaves li"e a built in type. 'e can
declare a group of associated variables which are associated as a structure.
IM%ORTANT RULE: ! struct statement declares a structure which can hold information of
e)isting types (or indeed other structures. ! struct should be declared at the top of the code or in a
header file.
For e)ample, if we are writing a program for a ban", we might decide that an account is a fundamental
data type in such a program. Therefore we declare a structure which deals with each account:
struct account 4
car acctAolder"H?#; /* 3a!e of older */
car address"(??#; /* /ddress of older */
dou-le -alance; /* Ialance in pounds */
int acctAtype; /* type of account ($ sa;ings %$ current */
8;
'e can declare variables to have this type. !nd we can access elements using the dot notation shown
below:
struct account ne+Aacct;
strcpy 'ne+Aacct.acctAolder, "&. <ol!es");
strcpy 'ne+Aacct.address, "%%%I Ia7er &t., London");
ne+Aacct.-alance$ %3.J?;
ne+Aacct.type$ (;
'e can use any of these variables within a struct wherever we could use a variable of the same type.
So, for e)ample, we could add this:
0
float interest;
float rate$ (.KJ;
interest$ ne+Aacct.-alance * rate / (??.?;
printf '"/dding interest of Bf6n",interest);
ne+Aacct.-alanceL$ interest;
'e can ma"e our struct loo" even more li"e a built in type such as int or float by using a
typedef statement. For e)ample:
typedef struct i!aginaryAnu!-er 4
dou-le realApart;
dou-le i!agApart;
8 ID/MA31D;
we can then use the new type 9%!:C6/% pretty much wherever we can use an int. For e)ample:
ID/MA31D x,y;
dou-le a$ %.?;
x.realApart$ 3.?;
x.i!agApart$ a;
'e can also use these typedef types in functions for e)ample:
ID/MA31D !ultAi!ag 'ID/MA31D, ID/MA31D);
/* Function to !ultiply i!aginary nu!-ers */
ID/MA31D !ultAi!ag 'ID/MA31D x, ID/MA31D y)
4
ID/MA31D ans;
ans.realApart$ x.realApart*y.realApart 2 x.i!agApart*y.i!agApart;
ans.i!agApart$ x.realApart*y.i!agApart L y.realApart*x.i!agApart;
return ans;
8
IM%ORTANT RULE: typedef can be used to associate a label with a structure. (y convention,
we put our typedef names in !##CC!DS or at least 9nitial#etterCaps in order to distinguish them
from built in types and variable names. #i"e a struct statement, typedef should be at the start
of the code or in a header file.
'e can even have arrays of typedef variables. For e)ample:
ID/MA31D points"%#;
points"?#.realApart$ 3.?;
points"?#.i!agApart$ (.?;
points"(#.realApart$ @3.J;
points"(#.i!agApart$ @%.?;
Bou can also use typedef to create another name for a built in type. For e)ample you could write:
typedef int Lengt;
the only common use for this is in defining things which are a pain in the nec" to type. For e)ample, if
your program uses a lot of unsigned car values (recall that such a variable can store a number
from E to *FF then you might want to:
typedef unsigned car ucar;
simply to save typing. (Drogrammers are notoriously laGy.
F
IM%ORTANT RULE: 'e can build structs up from other structs. For e)ample, we might want
to define a rectangle in the imaginary plane by defining two of its corners. 'e could do so as follows
(assuming the previous definition of ID/MA31D has already been defined earlier in the program:
typedef struct i!agArect 4
ID/MA31D corner(;
ID/MA31D corner%;
8 ID/MA0E.,;
'e can access the bits of the rectangle as follows:
ID/MA0E., rect(;
rect(.corner(.i!agApart$ 3.(;
rect(.corner(.realApart$ (.%;
rect(.corner%.i!agApart$ @%.3;
rect%.corner%.realApart$ (.N;
Bou can also use typedef to create another name for a built in type. For e)ample you could write:
typedef dou-le Lengt;
This would allow you to use #ength wherever you could have used double. 4.g.
Lengt roo!AsiOe$(?.N;
Lengt roo!A+idt$(%.3;
This isn<t particularly useful, however. The only common use for this is in defining things which are a
pain in the nec" to type. For e)ample, if your program uses a lot of unsigned car values (recall
that such a variable can store a number from E to *FF then you might want to:
typedef unsigned car ucar;
simply to save typing. (Drogrammers are notoriously laGy.
D(na'!c 'e'or( allocat!on
#et<s start by tal"ing about that first advantage: getting things which are the right siGe. :oing bac" to
our 7Sieve of 4ratosthenes7 e)ample $ let<s say we want to write a program which allows the user to
enter a number and it prints all primes between & whatever number the user chooses. -ow can we go
about thisA 'ell, getting the number from the user isn<t a problem $ but how do we ma"e sure our
array can hold this many numbersA 'ell, one approach is to wor" out how large an array the computer
can hold and ma"e your array that large $ but this has a couple of problems:
& 9f you run the same program on a computer with smaller memory it will brea".
* Bour program is using an unnecessarily vast amount of memory $ your user might be puGGled why
they are ta"ing up so much space on the computer if they only want to use &*.
'hat you really need is what programmers call dynamic memory allocation $ that is to say the ability
to choose how much memory (allocate memory to use when your program is running (dynamically.
The way we do this in C is to use !alloc, realloc and free. These functions are part of the
stdli-. library =6ote: on most machines, they are also part of the !alloc. library so don<t be
surprised if you see programmers #include9!alloc.: instead of #include9stdli-.:#.
-ere<s a !alloc statement in action:
1
#include 9stdli-.:
#include 9stdio.:
const int D/EALE3$(???;
int !ain 'int argc, car *arg;"#)
4
int *array;
int i;
int n;
car string"D/EALE3#;
printf '"<o+ !any nu!-ers sall +e a;e in an arrayP6n");
/* Met a nu!-er fro! te user */
fgets'string,D/EALE3,stdin);
n$ atoi 'string);
if 'n 9 () 4
fprintf 'stderr, "Qou !ust gi;e a positi;e nu!-er6n");
return 2(;
8
array$ 'int *)!alloc'n * siOeof'int));
if 'array $$ 31LL) 4
fprintf 'stderr,"*ut of De!ory>6n");
return 2(;
8
for 'i$ ?; i 9 n; iLL)
array"i#$ i;
for 'i$ ?; i 9 n; iLL)
printf '"Ele!ent Bd is Bd6n",i,array"i#);
free 'array);
return ?;
8
This code doesn<t do anything particularly special $ it gets memory for an array of <n< integers, fills
them with the integers from E to nH& and then prints them out $ finally it frees the memory. #et<s loo"
at how it does it. The first new statement is that confusing loo"ing:
array$ 'int *)!alloc'n * siOeof'int));
sometimes you will also see people write:
array$ !alloc 'n * siOeof 'int));
For various reasons CII compilers will complain about this. This statement is getting enough memory
for <n< integers. 9t<s wor"ing in the following way:
()siOeof'int) uses the siOeof command (remember that was one of the "eywords of C to get
the siGe of an int in some measure which is important to the computer $ call them bytes for now.
(asically this means 7enough memory for one integer7. 'e could have written siGeof(double.
* !alloc'x) reserves enough memory for x bytes and returns a pointer to this reserved memory.
, Therefore !alloc'n * siOeof'int)) obviously returns a pointer to enough memory for n
ints.
0 The 'int *) bit: !alloc returns a ;oid * but the pointer we<re setting is an int *. +ecall
that we can use a cast to tell the compiler 79 "now what 9<m doing7 if we want to set two things of
different types to be e5ual. 'int *) casts the pointer returned by !alloc to be a pointer to int not
a pointer to ;oid.
=Bou might be worried a little by the idea of a pointer to ;oid $ after all, you learned earlier that ;oid
meant 7nothing7. ! function returning ;oid cannot return anything and a function which is
prototyped as ta"ing ;oid as an argument ta"es no arguments. ! pointer to ;oid simply means a
J
pointer which we don<t really "now the type of yet. CII is pic"y about such things and insist you
immediately cast this to something.@
The synta) of 7free7 is simple $ it says 7free the memory that was saved by malloc7.
IM%ORTANT RULE/ 'e can use !alloc to grab memory and free to free it again.
'type *)!alloc 'siOeof'type)) gets enough memory for & variable of type type
'type *)!alloc 'n*siOeof'type)) gets enough memory for n of them.
! virtuous programmer free s all memory that they !alloc ed.
.f course a computer only has a finite amount of memory. 9f the computer has run out of memory then
the !alloc command returns the special value 31LL to mean 7-elp, 9 have no more memory left7. !
good programmer always chec"s that malloc did not return 31LL. (!s 9 did in the e)ample.
A note a0out return!n# -o!nters ,ro' ,unct!ons
Sometimes you will want to return a pointer from a function. .ne good reason to do this is because
you might allocate memory in the function. -ere is an e)ample:
#include9stdio.:
#include9stdli-.:
dou-le *setAupAaccounts'int);
/* 5rototype for function to set up -an7 accounts */
int !ain'int argc, car *arg;"#)
4
int noAaccounts;
dou-le *accounts;
int i;
/* .ode to -e added ere gets user to input noAaccounts */
.
.
.
accounts$ setAupAaccounts'noAaccounts);
/* .ode ere does so!e processing +it te accounts*/
.
.
.
free'accounts);
8
2
dou-le *setAupAaccounts'int n)
/* .ode to process n ne+ accounts */
4
dou-le *array;
array$ 'dou-le *)!alloc'n*siOeof'dou-le));
if 'array $$ 31LL) 4
fprintf 'stderr,"*ut of !e!ory>6n");
/* Qipe 2 do so!eting ere */
8
/* Do so!e set up tings ere for accounts*/
.
.
.
return array;
8
A reca- o, s(nta* learne" !n .ee1 three
Files in C can be opened and closed using fopen and fclose which use file handles of the type
FILE *. fopen returns 31LL if it fails to open a file.
'e can write to a file using fprintf 'file_ptr,"<ello =orld6n"); ;ust li"e using a
printf statement.
'e can read a line from a file using fgets which reads a certain numbers of characters into a string
from a file. For e)ample:
car line"D/EALE3#;
FILE *fptr;
.
. (code to open file)
.
fgets 'line, D/EALE3, fptr);
stdin, stdout, stderr: are three special file handles which deal with, respectively, input from
the user, output to the screen and output to an error recording device (usually also the screen.
'e can use fgets to read input from the user.
car line"(???#;
fgets 'line, (???, stdin);
'e can use atoi and atof from stdli-. to read int and float from strings. This can be
combined with fgets from stdin.
int i;
float f;
i$ atoi '"N%"); /* &ets i to N% */
f$ atof '"3.(N"); /* &ets f to 3.(N */
struct and typedef can be used in C to create a user defined type which acts li"e built in types
such as int and float. ! structure can contain data of any already defined type including other
structures. !n e)ample is shown below:
typedef struct ani!al 4
car na!e"H?#;
int noAlegs;
car colour"H?#;
int noAears;
8 /3ID/L;
3
This defines !69%!# to be a data type which can be used li"e int, float or char. 'e have already seen
F9#4 which was defined li"e this. ! structure defined with a typedef li"e this can be used li"e so:
/3ID/L tiger;
tiger is now a variable li"e any other. 9t can be passed to functions and returned from them. 9ndividual
parts of a structure can be accessed using the . notation as follows:
tiger.noAlegs$ N;
tiger.noAears$ %;
sprintf 'tiger.na!e,",igger te tiger");
sprintf 'tiger.colour,"!ainly stripey");
by tradition, typedef names (that is the !69%!# part not the name of the variable, tiger are !##
C!DS or at least 9nitial#etterCaps.
stdli-. includes !alloc and free which are used as follows:
!alloc is passed a siGe $ usually calculated using the siOeof function $ and returns a pointer to that
much free memory. 'hile not necessary (e)cept in CII H see note above, it is programmers often cast
the !alloc to the type of the pointer it is being assigned to. Some !alloc e)amples are:
int *sie;e;
dou-le *-an7Aaccounts;
car *userAna!e;
sie;e$ 'int *)!alloc'(??*siOeof 'int));
-an7Aaccounts$ 'dou-le *) !alloc '(? * siOeof 'dou-le));
userAna!e$ 'car *) !alloc '%N * siOeof 'car));
!alloc returns 31LL if it cannot find any free memory to allocate. This should always be
chec"ed.
!nything !alloc ed must be free d. ! free statement ta"es as its argument a pointer to a memory
location which was returned by !alloc.
&E

Vous aimerez peut-être aussi