Sie sind auf Seite 1von 10

LECTURE THREE FILES, STRUCTURES AND MEMORY ALLOCATION

What these lecture notes co er 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 */ char filename !" "file#.txt"; /* $trin% containin% a file name */ fptr" fopen &"file'.txt"("r"); /* *pen file ' for readin% */ fptr" fopen &filename("+"); /* *pen the file in filename for +ritin% ,his +ill delete the current contents of the file so -e ./0EF1L */ fptr" fopen &FILE3("a"); /* *pen the file in "file3.txt" for appendin% 2 that is to say that ne+ -its of the file +ill -e +ritten after the 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-lem openin% the file6n"); /* ,a7e some appropriate action 2 for example( return from main */ 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.h: int main&int ar%c( char *ar%; !) 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-.h: 'ithin a function you can write: exit&@'); /* *r +hate;er num-er you +ant to exit +ith */

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; /* inte%er to -e read */ int noAread; /* .hec7 on num-er of thin%s read */ filepointer#" fopen &"myfile.dat"("r"); /* *pen the file for read */ /* 5ut in chec7s here to ma7e sure it is open */ /* 1se fscanf to try to %et an int */ noAread" fscanf&filepointer("Bd"(Ci); if &noAread "" E*F) 4 printf &"End of file>6n");

/* Do somethin% a-out this error */ 8 /* =e expected to read ' inte%er 2 chec7 this */ if &noAread >" ') 4 printf&"1na-le to read an int6n"); /* Do somethin% a-out this 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 f%ets function. f%ets ta"es three arguments $ a string to be read into, a number of characters to read and a FILE * pointer to read from. f%ets 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 f%ets is shown below: const int D/ELE3 '???; FILE *fptr; char readline D/ELE3!; fptr" fopen &"test.dat"("r"); /* .hec7 +e %ot the file open */ +hile & f%ets&readline( D/ELE3( fptr) >" 31LL) 4 /* Do somethin% +ith readline here */ 8 Bou might find the +hile loop confusing here $ it is doing an awful lot of wor". 9t is actually 5uite common in C to put a function within the +hile 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.h 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(",here 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 f%ets with the stdin file handle.

char line '???!; f%ets &line( '???( stdin); /*0eads at most '??? characters from stdin or until the 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-.h 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; char strin% !" "#3"; char strin%# !" "'#.'"; i" atoi &strin%); /* $ets i to #3 */ f" atof &strin%#); /* $ets f to '#.' */ CAUTIONF f%ets 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 char acctAholder H?!; /* 3ame of holder */ char address '??!; /* /ddress of holder */ dou-le -alance; /* Ialance in pounds */ int acctAtype; /* type of account '" sa;in%s #" 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.acctAholder( "$. <olmes"); 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:

float interest; float rate" '.KJ; interest" ne+Aacct.-alance * rate / '??.?; printf &"/ddin% 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 ima%inaryAnum-er 4 dou-le realApart; dou-le ima%Apart; 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.ima%Apart" a; 'e can also use these typedef types in functions for e)ample: ID/MA31D multAima% &ID/MA31D( ID/MA31D); /* Function to multiply ima%inary num-ers */ ID/MA31D multAima% &ID/MA31D x( ID/MA31D y) 4 ID/MA31D ans; ans.realApart" x.realApart*y.realApart 2 x.ima%Apart*y.ima%Apart; ans.ima%Apart" x.realApart*y.ima%Apart L y.realApart*x.ima%Apart; 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" points ?!.ima%Apart" points '!.realApart" points '!.ima%Apart" 3.?; '.?; @3.J; @#.?;

Bou can also use typedef to create another name for a built in type. For e)ample you could write: typedef int Len%th; 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 unsi%ned char values (recall that such a variable can store a number from E to *FF then you might want to: typedef unsi%ned char uchar; simply to save typing. (Drogrammers are notoriously laGy . 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 ima%Arect 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'.ima%Apart" rect'.corner'.realApart" rect'.corner#.ima%Apart" rect#.corner#.realApart" 3.'; '.#; @#.3; '.N;

Bou can also use typedef to create another name for a built in type. For e)ample you could write: typedef dou-le Len%th; This would allow you to use #ength wherever you could have used double. 4.g. Len%th roomAsiOe"'?.N; Len%th roomA+idth"'#.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 unsi%ned char values (recall that such a variable can store a number from E to *FF then you might want to: typedef unsi%ned char uchar; 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 malloc( realloc and free. These functions are part of the stdli-.h library =6ote: on most machines, they are also part of the malloc.h library so don<t be surprised if you see programmers #include9malloc.h: instead of #include9stdli-.h:!. -ere<s a malloc statement in action:

#include 9stdli-.h: #include 9stdio.h: const int D/EALE3"'???; int main &int ar%c( char *ar%; !) 4 int *array; int i; int n; char strin% D/EALE3!; printf &"<o+ many num-ers shall +e ha;e in an arrayP6n"); /* Met a num-er from the user */ f%ets&strin%(D/EALE3(stdin); n" atoi &strin%); if &n 9 ') 4 fprintf &stderr( "Qou must %i;e a positi;e num-er6n"); return 2'; 8 array" &int *)malloc&n * siOeof&int)); if &array "" 31LL) 4 fprintf &stderr("*ut of Demory>6n"); return 2'; 8 for &i" ?; i 9 n; iLL) array i!" i; for &i" ?; i 9 n; iLL) printf &"Element 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 *)malloc&n * siOeof&int)); sometimes you will also see people write: array" malloc &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 . * malloc&x) reserves enough memory for x bytes and returns a pointer to this reserved memory. , Therefore malloc&n * siOeof&int)) obviously returns a pointer to enough memory for n ints. 0 The &int *) bit: malloc 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 malloc 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

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 malloc to grab memory and free to free it again. &type *)malloc &siOeof&type)) gets enough memory for & variable of type type &type *)malloc &n*siOeof&type)) gets enough memory for n of them. ! virtuous programmer free s all memory that they malloc ed. .f course a computer only has a finite amount of memory. 9f the computer has run out of memory then the malloc 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.h: #include9stdli-.h: dou-le *setAupAaccounts&int); /* 5rototype for function to set up -an7 accounts */ int main&int ar%c( char *ar%; !) 4 int noAaccounts; dou-le *accounts; int i; /* .ode to -e added here %ets user to input noAaccounts */ . . . accounts" setAupAaccounts&noAaccounts); /* .ode here does some processin% +ith the accounts*/ . . . free&accounts);

dou-le *setAupAaccounts&int n) /* .ode to process n ne+ accounts */ 4 dou-le *array; array" &dou-le *)malloc&n*siOeof&dou-le)); if &array "" 31LL) 4 fprintf &stderr("*ut of memory>6n"); /* Qipe 2 do somethin% here */ 8 /* Do some set up thin%s here 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 f%ets which reads a certain numbers of characters into a string from a file. For e)ample: char line D/EALE3!; FILE *fptr; . . (code to open file) . f%ets &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 f%ets to read input from the user. char line '???!; f%ets &line( '???( stdin); 'e can use atoi and atof from stdli-.h to read int and float from strings. This can be combined with f%ets 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 animal 4 char name H?!; int noAle%s; char colour H?!; int noAears; 8 /3ID/L;

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 ti%er; 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: ti%er.noAle%s" N; ti%er.noAears" #; sprintf &ti%er.name(",i%%er the ti%er"); sprintf &ti%er.colour("mainly 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-.h includes malloc and free which are used as follows: malloc 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 malloc to the type of the pointer it is being assigned to. Some malloc e)amples are: int *sie;e; dou-le *-an7Aaccounts; char *userAname; sie;e" &int *)malloc&'??*siOeof &int)); -an7Aaccounts" &dou-le *) malloc &'? * siOeof &dou-le)); userAname" &char *) malloc &#N * siOeof &char)); malloc returns 31LL if it cannot find any free memory to allocate. chec"ed. This should always be

!nything malloc ed must be free d. ! free statement ta"es as its argument a pointer to a memory location which was returned by malloc.

&E

Das könnte Ihnen auch gefallen