D.1 - Hochschule Ravensburg
Transcription
D.1 - Hochschule Ravensburg
Hochschule Ravensburg-Weingarten Fakultät Elektrotechnik und Informatik Mechatronik Information Processing Elementary C/C++ Programming Contents D C-BASED INPUT/OUTPUT..........................................................................................................................D-2 D.1 THE C I/O-SYSTEM ..................................................................................................................................D-2 D.2 C I/0 USES STREAMS ...............................................................................................................................D-3 D.2.1 Streams................................................................................................................................................D-4 D.2.2 Text Streams and Binary Streams......................................................................................................D-5 D.3 UNDERSTANDING PRINTF( ) AND SCANF( )..............................................................................................D-6 D.3.1 printf( )................................................................................................................................................D-6 D.3.1.1 Printf Control String and Conversion Specifiers......................................................................................D-9 D.3.1.1.1 Modifier Tables.................................................................................................................................D-10 D.3.1.1.2 Flags...................................................................................................................................................D-10 D.3.1.1.3 Conversions .......................................................................................................................................D-11 D.3.1.2 Example of printf() usage........................................................................................................................D-12 D.3.2 scanf( ) ..............................................................................................................................................D-13 D.3.2.1 Scanf Control String and Conversion Specifiers....................................................................................D-17 D.3.2.2 Length Modifiers And Conversion Specifiers For Formatted Input Functions....................................D-17 D.3.2.2.1 Length Specifiers ..............................................................................................................................D-17 D.3.2.2.2 Conversion Specifiers .......................................................................................................................D-18 D.3.2.2.3 Scanset ...............................................................................................................................................D-18 D.3.2.3 Example of scanf() usage ........................................................................................................................D-20 D.4 THE C FILE SYSTEM...............................................................................................................................D-21 D.4.1 fopen( )..............................................................................................................................................D-22 D.4.1.1 D.4.2 Example of fopen() usage .......................................................................................................................D-24 fputc( )...............................................................................................................................................D-25 D.4.2.1 D.4.3 Example of fputc() usage ........................................................................................................................D-25 fgetc( ) ...............................................................................................................................................D-26 D.4.3.1 D.4.4 Example of fgetc() usage.........................................................................................................................D-26 feof( ).................................................................................................................................................D-27 D.4.4.1 D.4.5 Example of feof() usage ..........................................................................................................................D-27 fclose( ) .............................................................................................................................................D-28 D.4.5.1 D.4.6 Example of fclose() usage.......................................................................................................................D-28 ferror( ) and rewind( ) ......................................................................................................................D-29 D.4.6.1 D.4.6.2 D.4.7 Example of ferror() usage. ......................................................................................................................D-29 Example of rewind() usage .....................................................................................................................D-30 fread( ) and fwrite( ).........................................................................................................................D-31 D.4.7.1 D.4.8 The use of fwrite() and fread()................................................................................................................D-32 fseek( ) and Random-Access I/O......................................................................................................D-33 D.4.8.1 D.4.9 Example of fseek() usage ........................................................................................................................D-34 fprintf( ) and fscanf( ) .......................................................................................................................D-35 D.4.9.1 D.4.9.2 D.4.10 Example of fprintf() usage ......................................................................................................................D-35 Example of fscanf() usage.......................................................................................................................D-36 fflush()..........................................................................................................................................D-37 D.4.10.1 Example of fflush() usage .......................................................................................................................D-38 D.5 ERASING FILES .......................................................................................................................................D-39 D.6 MORE EXAMPLES TO C-BASED I/O .......................................................................................................D-40 D.6.1 The use of EOF during keyboard input ...........................................................................................D-40 DPM_C_I/O.doc Page D-1 of 40 Rüdiger Siol 11.12.2009 15:24 Hochschule Ravensburg-Weingarten Fakultät Elektrotechnik und Informatik Mechatronik Information Processing Elementary C/C++ Programming D C-Based Input/Output D.1 The C I/O-System This appendix presents a brief overview of the C I/O system. Even though you will normally use the C++ I/O system, there are several reasons why you may need to understand the fundamentals of C-based I/O. First, if you will be working on C code (especially if you are converting it to C++), then you will need to understand how the C I/O system works. Second, it is common to find both C and C++ I/O within the same program. This is true especially when the program is very large and has been written by multiple programmers over a long period of time. Third, a great number of existing C programs continue to be used and maintained. Finally, many books and periodicals contain programs written in C. To understand these programs, you need to understand the basics of the C l/O system. For C++ programs, you should use the C++ object oriented I/O system. This appendix covers the most commonly used C-based I/O functions. However, the C standard library contains a very rich and diverse assortment of I/O functions-more than can be covered here. If you will be doing extensive work in C, you will want to explore its I/O system in detail. The C-based I/O system requires either the header file stdio.h or the new-style header <cstdio>. A C program must use the stdio.h since C does not support C++-style headers. A C++ program uses either one. The header <cstdio> puts its contents into the std namespace. The header file stdio.h puts its contents into the global namespace, which is in keeping with C. The examples in this appendix are C programs, so they use the C-style header stdio.h, and no namespace statement is required. C-Based I/O command line arguments int main (int argc, char **argv) fpr printf, putchar, puts stdin / stdout stderr scanf, getchar, gets Application -program (-software) i tc , pu ntf , ge anf fsc tc, text file ts fge fopen, fclose, fgetpos fsetpos, ftell, fseek fre sscanf uts , fp fw rit e ad sprintf physical records String (r.siol) 09.01.2007 DPM_C_I/O.doc Hochschule Ravensburg-Weingarten Technik | Wirtschaft | Sozialwesen Page D-2 of 40 106 Rüdiger Siol 11.12.2009 15:24 Hochschule Ravensburg-Weingarten Fakultät Elektrotechnik und Informatik Mechatronik Information Processing Elementary C/C++ Programming The C language standard was updated in 1999, resulting in the C99 standard for C. At that time, a few enhancements were made to the C I/O system. However, because C++ is built on C89, it does not support any features added by C99. (Furthermore, at the time of this writing, no widely available compiler supports C99, nor is there any widely distributed code that uses the C99 features.) Thus, none of the features added to the C I/O system by C99 are described here. If you are interested in the C language, including a complete description of its I/O system and those features added by the C99 standard, I recommend my1 book C: The Complete Reference, 4th edition, McGraw-Hill/Osborne. D.2 C I/0 Uses Streams Like the C++ I/O system, the C-based I/O system operates on streams. At the beginning of a program's execution, three predefined text streams are opened. They are stdin, stdout, and stderr. (Some compilers also open other, implementation-dependent streams.) These streams are the C versions of cin, cout, and cerr, respectively. They each refer to a standard I/O device connected to the system, as shown here: Stream stdin stdout stderr Device keyboard screen screen Remember that most operating systems, including Windows, allow I/O redirection, so functions that read or write to these streams may be redirected to other devices. You should never try to explicitly open or close these streams. Each stream that is associated with a file has a file control structure of type FILE. This structure is defined in stdio.h. You must not make modifications to this file control block. 1 Herbert Schildt DPM_C_I/O.doc Page D-3 of 40 Rüdiger Siol 11.12.2009 15:24 Hochschule Ravensburg-Weingarten Fakultät Elektrotechnik und Informatik Mechatronik Information Processing Elementary C/C++ Programming D.2.1 Streams2 A stream is a logical abstraction that isolates input and output operations from the physical characteristics of terminals and structured storage devices. They provide a mapping between a program’s data and the data as actually stored on the external devices. Two forms of mapping are supported, for text streams and for binary streams. Streams also provide buffering, which is an abstraction of a file designed to reduce hardware I/O requests.Without buffering, data on an I/O device must be accessed one item at a time. This inefficient I/O processing slows program execution considerably. The stdio.h functions use buffers in primary storage to intercept and collect data as it is written to or read from a file. When a buffer is full its contents are actually written to or read from the file, thereby reducing the number of I/O accesses. A buffer's contents can be sent to the file prematurely by using the fflush() function. The stdio.h header offers three buffering schemes: o unbuffered o block buffered o line buffered. The setvbuf() function is used to change the buffering scheme of any output stream. When an output stream is unbuffered, data sent to it are immediately read from or written to the file. When an output stream is block buffered, data are accumulated in a buffer in primary storage. When full, the buffer's contents are sent to the destination file, the buffer is cleared, and the process is repeated until the stream is closed. Output streams are block buffered by default if the output refers to a file. A line buffered output stream operates similarly to a block buffered output stream. Data are collected in the buffer, but are sent to the file when the line is completed with a newline character ('\n'). A stream is declared using a pointer to a FILE. There are three FILE pointers that are automatically opened for a program: o FILE *stdin o FILE *stdout o FILE *stderr The FILE pointers stdin and stdout are the standard input and output files, respectively, for interactive console I/O. The stderr file pointer is the standard error output file, where error messages are written to. The stderr stream is written to the console. The stdin and stdout streams are line buffered while the stderr stream is unbuffered. 2 Metroworks Corporation; some parts out of the documentation. DPM_C_I/O.doc Page D-4 of 40 Rüdiger Siol 11.12.2009 15:24 Hochschule Ravensburg-Weingarten Fakultät Elektrotechnik und Informatik Mechatronik Information Processing Elementary C/C++ Programming D.2.2 Text Streams and Binary Streams In a binary stream, there is no transformation of the characters during input or output and what is recorded on the physical device is identical to the program’s internal data representation. A text stream consists of sequences of characters organized into lines, each line terminated by a new-line character. To conform to the host system’s convention for representing text on physical devices, characters may have to be added altered or deleted during input and output. Thus, there may not be a one-to-one correspondence between the characters in a stream and those in the external representation. These changes occur automatically as part of the mapping associated with text streams. Of course, the input mapping is the inverse of the output mapping and data that are output and then input through text streams will compare equal with the original data. In MSL3, the text stream mapping affects only the linefeed (LF) character, ‘\n’ and the carriage return (CR) character, ‘\r’. The semantics of these two control characters are: \n Moves the current print location to the start of the next line. \r Moves the current print location to the start of the current line. where “current print location “is defined as “that location on a display device where the next character output by the fputc function would appear”. The ASCII character set defines the value of LF as 0x0a and CR as 0x0d and these are the values that these characters have when they are part of a program's data. On physical devices in the Macintosh operating system, newline characters are represented by 0x0d and CR as 0x0a; in other words, the values are interchanged. To meet this requirement, the MSL C library for the Mac, interchanges these values while writing a file and again while reading so that a text stream will be unchanged by writing to a file and then reading back. MPW chose 0x0a for the newline character in its text file, so, when the MPW switch is on, this interchange of values does not take place. However, if you use this option, you must use the MSL C and C++ libraries that were compiled with this option on. These versions of the libraries are marked with an N (on 68k) or NL (on PPC), for example ANSI (N/2i) C.68k.Lib or ANSI (NL) C.PPC.Lib. See the notes on the mpwc_newline pragma in the CodeWarrior C Compilers Reference. On Windows, the situation is different. There, lines are terminated with the character pair CR/LF. As a consequence, in the Windows implementation of MSL, when a text stream is written to a file, a single newline character is converted to the character pair CR/LF and the reverse transformation is made during reading. The library routines that read a file have no means of determining the mode in which text files were written and thus some assumptions have to be made. On the Mac, it is assumed that the Mac convention is used. Under MPW, it is assumed that the MPW convention is to be used and on Windows, the DOS convention. 3 MSL – Metroworks Standard Library DPM_C_I/O.doc Page D-5 of 40 Rüdiger Siol 11.12.2009 15:24 Hochschule Ravensburg-Weingarten Fakultät Elektrotechnik und Informatik Mechatronik Information Processing Elementary C/C++ Programming D.3 Understanding printf( ) and scanf( ) The two most commonly used C-based I/O functions are printf() and scanf(). The printf( ) function writes data to the console; scanf( ), its complement, reads data from the keyboard. Because the C language does not support operator overloading, or the use of << and >> as I/O operators, it relies on printf( ) and scanf( ) for console I/O. Both printf( ) and scanf( ) can operate on any of the built-in data types, including characters, strings, and numbers. However, since these functions are not object-oriented, they cannot operate directly upon class types that you create. D.3.1 printf( ) The printf( ) function has this prototype: int printf(const char *fmt_string, ... ); The first argument, fmt_string, defines the way any subsequent arguments are displayed. This argument is often called the format string. It contains two things: text and format specifiers. Text is printed on the screen and has no other effect. The format specifiers define the way arguments that follow the format string are displayed. A format specifier begins with a percent sign, and is followed by the format code. The format specifiers are shown in Format Table. There must be exactly the same number of arguments as there are format specifiers, and the format specifiers and the arguments are matched in order. Text and format specifiers in printf The printf() function has the prototype: int printf (const char * format, … ); %[Flag][Width][.Precision][Length modifier]Conversion Specifier %[F][W][P][L]C % F W P L C = = = = = = A percent sign [Flag] [Width] [Precision] [Length modifier] Conversion Specifier -, +, 0, # or space decimal digit string . or .* or . decimal digit string h, l, hh, ll, j, z or t c,d,e,E,f,F,g,G,i,n,o,p,s,u,x,X or % Options are shown in []. (r.siol) 17.01.2007 Hochschule Ravensburg-Weingarten Technik | Wirtschaft | Sozialwesen 111 For example, this printf( ) call, printf("Hi %c %d %s", 'c', 10, "there!"); displays: Hi c 10 there!. The printf( ) function returns the number of characters output. It returns a negative value if an error occurs. DPM_C_I/O.doc Page D-6 of 40 Rüdiger Siol 11.12.2009 15:24 Hochschule Ravensburg-Weingarten Fakultät Elektrotechnik und Informatik Mechatronik Information Processing Elementary C/C++ Programming The format specifiers The format specifiers may have modifiers that specify the field width, the number of decimal places, and a left-justification flag. An integer placed between the % sign and the format specifier acts as a minimum-field-width specifier. Code %c %d %i %e %E %f %g %G %o %s %u %x %X %p %n %% Format Character Signed decimal integers Signed decimal integers Scientific notation (lowercase e) Scientific notation (uppercase E) Decimal floating point Uses %e or %f, whichever is shorter Uses %E or %F, whichever is shorter Unsigned octal String of characters Unsigned decimal integers Unsigned hexadecimal (lowercase letters) Unsigned hexadecimal (uppercase letters) Displays a pointer The associated argument is a pointer to an integer into which the number of characters written so far is placed Displays a % sign This pads the output with spaces to ensure that it is at least a certain minimum length. If the string or number is greater than that minimum, it will be printed in full, even if it overruns the minimum. If you want to pad with 0s, place a 0 before the field-width specifier. For example, %05d will pad a number of less than five digits with 0s so that its total length is five. To specify the number of decimal places printed for a floating-point number, place a decimal point after the field-width specifier, followed by the number of decimal places you want to display. For example, %10.4f will display a number at least ten characters wide, with four decimal places. When this is applied to strings or integers, the number following the period specifies the maximum field length. Far example, %5.7s will display a string that is at least five characters long, but that does not exceed seven characters. lf the string is longer than the maximum field width, the characters will be truncated from the end. By default, all output is right-justified: If the field width is larger than the data printed, the data will be placed on the right edge of the field. You can force the information to be leftjustified by placing a minus sign directly after the %. For example, %-10.2f will left-justify a floating-point number, with two decimal places in a ten-character field. DPM_C_I/O.doc Page D-7 of 40 Rüdiger Siol 11.12.2009 15:24 Hochschule Ravensburg-Weingarten Fakultät Elektrotechnik und Informatik Mechatronik Information Processing Elementary C/C++ Programming Here is a program that demonstrates field-width specifiers and left-justification: #include <stdio.h> int main() { printf("|%10.5f|\n", 123.23); printf("|%-10.5f|\n", 123.23); printf("|%10.5s|\n", "Hello there"); printf("|%-10.5s|\n", "Hello there"); return 0; } This program displays the following output: | 123.23000| |123.23000 | | Hello| |Hello | There are two format specifier modifiers that allow printf( ) to display short and long integers. These modifiers can be applied to the d, i, o, u and x type specifiers. The l (ell) modifier tells printf( ) that a long data type follows. For example, %ld means that a long int is to be displayed. The h modifier instructs printf( ) to display a short int. Therefore, %hu indicates that the data is of the short, unsigned integer type. The l and h modifiers can also be applied to the n specifier, to indicate that the corresponding argument is a pointer to a long or short integer, respectively. If your compiler fully complies with Standard C++, then you can use the l modifier with the c format to indicate a wide character. You can also use the l modifier with the s format to indicate a wide-character string. The L modifier can prefix the floating-point specifiers e, f and g. In this context, it indicates that a long double follows. DPM_C_I/O.doc Page D-8 of 40 Rüdiger Siol 11.12.2009 15:24 Hochschule Ravensburg-Weingarten Fakultät Elektrotechnik und Informatik Mechatronik Information Processing Elementary C/C++ Programming D.3.1.1 Printf Control String and Conversion Specifiers The format character array contains normal text and conversion specifications. Conversion specifications must have matching arguments in the same order in which they occur in format. The various elements of the format string is specified in the ANSI standards to be in this order from left to right. o o o o o o Apercent sign Optional flags -,+,0,# or space Optional minimum field width specification Optional precision specification Optional size specification Conversion specifier c,d,e,E,f,F,g,G,i,n,o,p,s,u,x,X or % A conversion specification describes the format its associated argument is to be converted to. A specification starts with a percent sign (%), optional flag characters, an optional minimum width, an optional precision width, and the necessary, terminating conversion type. Doubling the percent sign (%%) results in the output of a single %. An optional flag character modifies the formatting of the output; it can be left or right justified, and numerical values can be padded with zeroes or output in alternate forms. More than one optional flag character can be used in a conversion specification. “Length Modifiers And Conversion Specifiers For Formatted Output Functions” see following tables, describes the flag characters. The optional minimum width is a decimal digit string. If the converted value has more characters that the minimum width, it is expanded as required. If the converted value has fewer characters than the minimum width, it is, by default, right justified (padded on the left). If the - flag character is used, the converted value is left justified (padded on the right). NOTE The maximum minimum field width allowed in MSL Standard Libraries is 509 characters. The optional precision width is a period character (.) followed by decimal digit string. For floating point values, the precision width specifies the number of digits to print after the decimal point. For integer values, the precision width functions identically to, and cancels, the minimum width specification. When used with a character array, the precision width indicates the maximum width of the output. A minimum width and a precision width can also be specified with an asterisk (*) instead of a decimal digit string. An asterisk indicates that there is a matching argument, preceding the conversion argument, specifying the minimum width or precision width. The terminating character, the conversion type, specifies the conversion applied to the conversion specification's matching argument “Length Modifiers And Conversion Specifiers For Formatted Output Functions” see following tables, describes the conversion type characters. DPM_C_I/O.doc Page D-9 of 40 Rüdiger Siol 11.12.2009 15:24 Hochschule Ravensburg-Weingarten Fakultät Elektrotechnik und Informatik Mechatronik Information Processing Elementary C/C++ Programming D.3.1.1.1 Modifier Tables Length Modifiers And Conversion Specifiers For Formatted Output Functions Modifier Description Size The h flag followed by d, i, o, u, x, or X conversion specifier indicates h that the corresponding argument is a short int or unsigned short int. l ll L The lower case L followed by d, i, o, u, x, or X conversion specifier indicates the argument is a long int or unsigned long int. The lower case L followed by a c conversion specifier, indicates that the argument is of type wint_t. The lower case L followed by an s conversion specifier, indicates that the argument is of type wchar_t. The double l followed by d, i, o, u, x, or X conversion specifier indicates the argument is a long long or unsigned long long The upper case L followed by e, E, f, g, or G conversion specifier indicates a long double. D.3.1.1.2 Flags Modifier Description Flags + space # 0 The conversion will be left justified. The conversion, if numeric, will be prefixed with a sign (+ or -). By default, only negative numeric values are prefixed with a minus sign (-). If the first character of the conversion is not a sign character, it is prefixed with a space. Because the plus sign flag character (+) always prefixes a numeric value with a sign, the space flag has no effect when combined with the plus flag. For c, d, i, and u conversion types, the # flag has no effect. For s conversion types, a pointer to a Pascal string, is output as a character string. For o conversion types, the # flag prefixes the conversion with a 0. For x conversion types with this flag, the conversion is prefixed with a 0x. For e, E, f, g, and G conversions, the # flag forces a decimal point in the output. For g and G conversions with this flag, trailing zeroes after the decimal point are not removed. This flag pads zeroes on the left of the conversion. It applies to d, i, o, u, x, X, e, E, f, g, and G conversion types. The leading zeroes follow sign and base indication characters, replacing what would normally be space characters. The minus sign flag character overrides the 0 flag character. The 0 flag is ignored when used with a precision width for d, i , o, u, x, and X conversion types. DPM_C_I/O.doc Page D-10 of 40 Rüdiger Siol 11.12.2009 15:24 Hochschule Ravensburg-Weingarten Fakultät Elektrotechnik und Informatik Mechatronik Information Processing Elementary C/C++ Programming D.3.1.1.3 Conversions Modifier Description Conversions d i o u x, X n f, F e, E g, G c s p #s The corresponding argument is converted to a signed decimal. The corresponding argument is converted to a signed decimal. The argument is converted to an unsigned octal. The argument is converted to an unsigned decimal. The argument is converted to an unsigned hexadecimal. The x conversion type uses lowercase letters (abcdef) while X uses uppercase letters (ABCDEF). This conversion type stores the number of items output by printf() so far. Its corresponding argument must be a pointer to an int. The corresponding floating point argument (float, or double) is printed in decimal notation. The default precision is 6 (6 digits after the decimal point). If the precision width is explicitly 0, the decimal point is not printed. For the f conversion specifier, a double argument representing infinity produces [-]inf; a double argument representing a NaN (Not a number) produces [-]nan. For the F conversion specifier, [-]INF or [-]NAN are produced instead. The floating point argument (float or double) is output in scientific notation: [-]b.aaae±Eee. There is one digit (b) before the decimal point. Unless indicated by an optional precision width, the default is 6 digits after the decimal point (aaa). If the precision width is 0, no decimal point is output. The exponent (ee) is at least 2 digits long. The e conversion type uses lowercase e as the exponent prefix. The E conversion type uses uppercase E as the exponent prefix. The g conversion type uses the f or e conversion types and the G conversion type uses the F or E conversion types. Conversion type e (or E) is used only if the converted exponent is less than -4 or greater than the precision width. The precision width indicates the number of significant digits. No decimal point is output if there are no digits following it. The corresponding argument is output as a character. The corresponding argument, a pointer to a character array, is output as a character string. Character string output is completed when a null character is reached. The null character is not output. The corresponding argument is taken to be a pointer. The argument is output using the X conversion type format. The corresponding argument, a pointer to a Pascal string, is output as a character string. A Pascal character string is a length byte followed by the number characters specified in the length byte. Note: This conversion type is an extension to the ANSI C library but applied in the same manner as for other format variations. DPM_C_I/O.doc Page D-11 of 40 Rüdiger Siol 11.12.2009 15:24 Hochschule Ravensburg-Weingarten Fakultät Elektrotechnik und Informatik Mechatronik Information Processing Elementary C/C++ Programming D.3.1.2 Example of printf() usage #include <stdio.h> int main(void) { int i = 25; char c = 'M'; short int d = 'm'; static char s[] = "Metrowerks!"; static char pas[] = "\pMetrowerks again!"; float f = 49.95; double x = 1038.11005; int count; printf("%s printf() demonstration:\n%n", s, &count); printf("The last line contained %d characters\n",count); printf("Pascal string output: %#20s\n", pas); printf("%-4d %x %06x %-5o\n", i, i, i, i); printf("%*d\n", 5, i); printf("%4c %4u %4.10d\n", c, c, c); printf("%4c %4hu %3.10hd\n", d, d, d); printf("$%5.2f\n", f); printf("%5.2f\n%6.3f\n%7.4f\n", x, x, x); printf("%*.*f\n", 8, 5, x); return 0; } The output is: Metrowerks! printf() demonstration: The last line contained 36 characters Pascal string output: Metrowerks again! 25 19 000019 31 25 M 77 0000000077 m 109 0000000109 $49.95 1038.11 1038.110 1038.1101 1038.11005 DPM_C_I/O.doc Page D-12 of 40 Rüdiger Siol 11.12.2009 15:24 Hochschule Ravensburg-Weingarten Fakultät Elektrotechnik und Informatik Mechatronik Information Processing Elementary C/C++ Programming D.3.2 scanf( ) C's general-purpose console input function is scanf( ). It can read all the built-in data types and automatically convert numbers into the proper internal format. It is much like the reverse of printf( ). The general form of scanf( ) is int scanf(const char *fmt_string, ... ); The format string consists of three classifications of characters: o Format specifiers o Whitespace characters o Non-whitespace characters The scanf( ) function returns the number of fields that are input. It returns EOF (defined in stdio.h) if an error occurs. Text and format specifiers in scanf The scanf() function has the prototype: int scanf (const char * format, … ); %[*][Width] [Length modifier] Conversion specifier %[S][W][L]C % S W = = = L C = = A percent sign [*] skip the argument. [Width] maximum field length monifier; a whitespace character in the contral string causes scanf( ) to skip over one or more whitespace characters in the input stream. [Length] length specifiers: h, l, hh or ll Conversion specifier Options are shown in [] (r.siol) 17.01.2007 Hochschule Ravensburg-Weingarten Technik | Wirtschaft | Sozialwesen 113 The input format specifiers are preceded by a % sign. They tell scanf( ) what type of data is to be read next. For example, %s reads a string, while %d reads an integer. These codes are listed in the Meaning Table below. A whitespace character in the contral string causes scanf( ) to skip over one or more whitespace characters in the input stream. A whitespace character is either a space, a tab, or a newline. In essence, one whitespace character in the contral string will cause scanf( ) to read, but not store, any number (including zero) of whitespace characters up to the first nonwhitespace character. A non-whitespace character causes scanf( ) to read and discard a matching character. For example, "%d, %d" causes scanf( ) to first read an integer, then read and discard a comma, and finally read another integer. If the specified character is not found, scanf( ) will terminate. DPM_C_I/O.doc Page D-13 of 40 Rüdiger Siol 11.12.2009 15:24 Hochschule Ravensburg-Weingarten Code %c %d %i %e %f %g %o %s %x %p %n %u %[ ] %% Fakultät Elektrotechnik und Informatik Mechatronik Information Processing Elementary C/C++ Programming Meaning Read a single character Read a decimal integer Read an integer in either decimal, octal, or hexadecimal format. Read a floating-point number Read a floating-point number Read a floating-point number Read an octal number Read astring Read a hexadecimal number Read a pointer Receives an integer value equal to the number of characters read so far Read an unsigned decimal integer Scan for a set of characters Read a percent sign All the variables used to receive values through scanf( ) must be passed by their addresses. This means that all arguments must be pointers to the variables used as arguments. (C does not support references or the reference parameter.) Passing pointers allows scanf( ) to alter the contents of an argument. For example, if you want to read an integer into the variable count, use the following scanf( ) call: scanf ( "%d", &count); Strings will be read into character arrays, and the array name, without any index, is the address of the first element in an array. So, to read a string into the character array address, you would use char address[80]; scanf ( "%s", address); In this case, address is already a pointer, and need not be preceded by the & operator. The data items read by scanf( ) must be separated by spaces, tabs, or newlines. Punctuation such as commas, semicolons, and the like do not count as separators. This means that scanf("%d%d", &r, &c); will accept an input of 10 20, but will fail with 10,20. As in printf( ), the scanf( ) format codes are matched, in order, with the variables receiving input in the argument list. An * placed after the % and before the format code will read data of the specified type, but will not assign it to any variable. Thus, scanf("%d%*c%d", &x, &y); when given the input 10/20, will place the value 10 into x, discard the division sign, and give y the value 20. DPM_C_I/O.doc Page D-14 of 40 Rüdiger Siol 11.12.2009 15:24 Hochschule Ravensburg-Weingarten Fakultät Elektrotechnik und Informatik Mechatronik Information Processing Elementary C/C++ Programming The format specifiers can specify a maximum-field-length modifier. This is an integer number placed between the % and the format-specifier code that limits the number of characters read for any field. For example, if you want to read no more than 20 characters into str, then you would write scanf("%20s", str); If the input stream is greater than 20 characters, then a subsequent call to input begins where this call leaves off. For example, if ABCDEFGHIJKLMNOPQRSTUVWXYZ is entered as the response to the scanf( ) call in this example, then only the first 20 characters, or up to the 'T,' are placed into str, because of the maximum-size specifier. This means that the remaining characters, "UVWXYZ," have not yet been used. If another scanf( ) call is made, such as scanf("%s", str); then the characters "UVWXYZ" are placed into str. If a whitespace is encountered, input for a field may terminate before the maximum field length is reached. In this case, scanf( ) will move on to the next field. Although spaces, tabs, and newlines are used as field separators, they are read like any other characters when single characters are being read. For example, with an input stream of "x y," scanf("%c%c%c", &a, &b, &c); will return with the character 'x' in a, a space in b, and the character 'y' in c. Another feature of scanf( ) is the scanset. A scanset defines a set of characters that will be matched by scanf( ) and stored in a character-array. The scanf( ) function continues to input characters as long as they are members of the scanset. When a character is entered that does not match any in the scanset, scanf( ) null-terminates the corresponding array and moves on to the next (if any) field. You define a scanset by putting a list of the characters you want to scan for inside square brackets. The beginning square bracket must be prefixed by a percent sign. For example, this scanset tells scanf( ) to read only the letters X, Y, and Z. % [XYZ] The argument corresponding to the scanset must be a pointer to a character array. Upon return fram scanf( ), the array will contain a null-terminated string composed of the characters read. For example, the following program uses a scanset to read digits into s1. As soon as a non-digit is entered, s1 is null-terminated, and characters are read into s2 until the next whitespace character is entered. DPM_C_I/O.doc Page D-15 of 40 Rüdiger Siol 11.12.2009 15:24 Hochschule Ravensburg-Weingarten Fakultät Elektrotechnik und Informatik Mechatronik Information Processing Elementary C/C++ Programming /* A simple scanset example. */ #include <stdio.h> int main() { char s1[80], s2[80]; printf("Enter numbers, then some letters\n"); scanf("%[0123456789]%s", s1, s2); printf("%s %s", s1, s2); return 0; } In most implementations, you can specify a range inside a scanset by using a hyphen. For example, the foIlowing scanset tells scanf( ) to accept the characters A through Z: % [A-Z] You can specify more than one range within a scanset. For example, this program reads digits and then letters: /* A scanset example using ranges. */ #include <stdio.h> int main() { char s1[80], s2[80]; printf("Enter numbers, then some letters\n"); scanf("%[0-9]%[a-zA-Z]", s1, s2); printf("%s %s", s1, s2); return 0; } You can specify an inverted set if the first character in the set is a ^. When the ^ is present, it tells scanf( ) to accept any character that is not defined by the scanset. The foIlowing modification of the preceding example uses the ^ to invert the type of characters the scanset will read: /* A scanset example using inverted ranges. */ #include <stdio.h> int main() { char s1[80], s2[80]; printf("Enter non-numbers, then some non-letters\n"); scanf4("%[^0-9]%[^a-zA-Z]", s1, s2); printf("%s %s", s1, s2); return 0; } One important point to remember is that the scanset is case-sensitive. Therefore, if you want to scan for both uppercase and lowercase letters, they must be specified individuaIly. Several of the format specifiers can take modifiers which precisely specify the type of variable that receives the data. To assign data to a long integer, put an l (ell) in front of the format specifier. To assign data to a short integer, put an h in front of the format specifier. These modifiers can be used with the d, i, o, u, x and n format codes. By default, the f, e, and g specifiers tell scanf( ) to assign data to a float. If you put an l (ell) in front of one of these specifiers, scanf( ) assigns the data to a double. Using an L tells scanf( ) that the variable receiving the data is a long double. 4 Doesn’t run correctly ! DPM_C_I/O.doc Page D-16 of 40 Rüdiger Siol 11.12.2009 15:24 Hochschule Ravensburg-Weingarten Fakultät Elektrotechnik und Informatik Mechatronik Information Processing Elementary C/C++ Programming The l (ell) modifier can also be used with the c and s format codes as long as your compiler fully complies with Standard C++. Preceding c with an l indicates a pointer to an object of type wchar_t. Preceding s with an l indicates apointer to a wchar_t array. The l can also be used to modify a scanset for use with wide characters. D.3.2.1 Scanf Control String and Conversion Specifiers The format argument is a character array containing normal text, white space (space, tab, newline), and conversion specifications. The normal text specifies literal characters that must be matched in the input stream. A white space character indicates that white space characters are skipped until a non-white space character is reached. The conversion specifications indicate what characters in the input stream are to be converted and stored. The conversion specifications must have matching arguments in the order they appear in format. Because scanf() stores data in memory, the matching conversion specification arguments must be pointers to objects of the relevant types. A conversion specification consists of the percent sign (%) prefix, followed by an optional maximum width or assignment suppression, and ending with a conversion type. A percent sign can be skipped by doubling it in format; %% signifies a single % in the input stream. An optional width is a decimal number specifying the maximum width of an input field. scanf() will not read more characters for a conversion than is specified by the width. An optional assignment suppression character (*) can be used to skip an item by reading it but not assigning it. A conversion specification with assignment suppression must not have a corresponding argument. The last character, the conversion type, specifies the kind of conversion requested. “Length Modifiers And Conversion Specifiers For Formatted Input Functions”, describes the conversion type characters. D.3.2.2 Length Modifiers And Conversion Specifiers For Formatted Input Functions D.3.2.2.1 Length Specifiers Modifier Description Length Specifiers hh The hh flag indicates that the following d, i, o, u, x, X or n conversion specifier applies to an argument that is of type char or unsigned char. h Theh flag indicates that the following d, i, o, u, x, X or n conversion specifier applies to an argument that is of type short int or unsigned short int. l When used with integer conversion specifier, the l flag indicates long int or an unsigned long int type. When used with floating point conversion specifier, the l flag indicates a double. When used with a c or s conversion specifier, the l flag indicates that the corresponding argument with type pointer to wchar_t. ll When used with integer conversion specifier, the ll flag indicates that the corresponding argument is of type long long or an unsigned long long. L TheL flag indicates that the corresponding float conversion specifier corresponds to an argument of type long double. DPM_C_I/O.doc Page D-17 of 40 Rüdiger Siol 11.12.2009 15:24 Hochschule Ravensburg-Weingarten Fakultät Elektrotechnik und Informatik Mechatronik Information Processing Elementary C/C++ Programming D.3.2.2.2 Conversion Specifiers Modifier Description Conversion Specifiers d A decimal integer is read. i A decimal, octal, or hexadecimal integer is read. The integer can be prefixed with a plus or minus sign (+, - ), 0 for octal numbers, 0x or 0X for hexadecimal numbers. o An octal integer is read. u An unsigned decimal integer is read. x, X A hexadecimal integer is read. e, E A floating point number is read. The number can be in plain decimal format (e.g. 3456.483) or in scientific notation ([-]b.aaae[-]dd f g, G s A character string is read. The input character string is considered terminated when a white space character is reached or the maximum width has been reached. The null character is appended to the end of the array. c A character is read. White space characters are not skipped, but read using this conversion specifier. p A pointer address is read. The input format should be the same as that output by the p conversion type in printf(). n This conversion type does not read from the input stream but stores the number of characters read in ist corresponding argument. [scanset] Input stream characters are read and filtered determined by the scanset. D.3.2.2.3 Scanset The conversion specifier %[ allows you to specify a scanset, which is a sequence of characters that will be read and stored in the string pointed to by the scanset's corresponding argument. The characters between the [ and the terminating ] define the scanset. A null character is appended to the end of the character sequence. Input stream characters are read until a character is found that is not in the scanset. If the first character of scanset is a circumflex5 (^) then input stream characters are read until a character from the scanset is read. A null character is appended to the end of the character array. Thus, the conversion specifier %[abcdef] specifies that the scanset is abcdef and any of the characters ‘a’ through ‘f’ are to be accepted and stored. As soon as any character outside this set is encountered, reading and storing will cease. Thus, for example, assuming we have the declaration: char str[20]; the execution of sscanf("acdfxbe", "%[abcdef]", str); will store acdf in str; the ‘x’ and following characters will not be stored because the ‘x’ is not in the scanset. 5 „caret“ is the better expression for ^ DPM_C_I/O.doc Page D-18 of 40 Rüdiger Siol 11.12.2009 15:24 Hochschule Ravensburg-Weingarten Fakultät Elektrotechnik und Informatik Mechatronik Information Processing Elementary C/C++ Programming If the first character of the scanset is the circumflex, ^, then the following characters will define a set of characters such that encountering any one of them will cause reading and storing to stop; any character outside a scanset defined in this way will be accepted, we will call this an exclusionary scanset. Thus execution of sscanf("stuvawxyz", "%[^abcdef]", str); will store stuv in str. If you want ^ to be part of the scanset, you cannot list it as the first character otherwise it will be interpreted as introducing the members of an exclusionary scanset. Thus %[^abc] defines the exclusionary scanset abc whereas %[a^bc] defines the scanset abc^. %[^a^bc] defines the exclusionary scanset abc^, as does %[^^abc]. If you want ] to be in the scanset, it must be the first character of the scanset, immediately following the %[ or, to be in an exclusionary scanset, immediately after the ^, for example, %[]abc] or %[^]abc]. In any other position, the ] will be interpreted as terminating the scanset. To include the - character in the scanset, it must be either listed first (possibly after an initial ^ or last, thus for example, %[-abc], %[abc-], %[^-abc], or%[^abc-]. The C Standard explicitly states: If a - character is in the scanlist and is not the first, nor the second where the first character is a ^, nor the last character, the behavior is implementation-defined. MSL interprets such a use of - in a scanlist as defining a range of characters; thus, the specification %[a-z] as being the equivalent of %[abcdefghijklmnopqrstuvwxyz]. You should bear in mind that this is MSL’s interpretation and such usage may be interpreted differently in other C library implementations. Note also that it is assumed that the numeric value of the character before the - is less than that of the one after. If this relationship does not hold undefined and probably unwanted effects may be experienced. DPM_C_I/O.doc Page D-19 of 40 Rüdiger Siol 11.12.2009 15:24 Hochschule Ravensburg-Weingarten Fakultät Elektrotechnik und Informatik Mechatronik Information Processing Elementary C/C++ Programming D.3.2.3 Example of scanf() usage #include <stdio.h> int main(void) { int i, k; unsigned int j; char c; char s[40]; double x; printf("Enter an integer surrounded by ! marks\n"); scanf("!%d!", &i); printf("Enter three integers\n"); printf("in hexadecimal, octal, or decimal.\n"); /* note that 3 integers are read, but only the last two are assigned to i and j */ scanf("%*i %i %ui", &i, &j, &k); printf("Enter a character and a character string.\n"); scanf("%c %10s", &c, s); printf("Enter a floating point value.\n"); scanf("%lf", &x); return 0; } The dialog is: Enter an integer surrounded by ! marks !24405! Enter three integers in hexadecimal, octal, or decimal. 0xabc 0234 456 Enter a character and a character string. g string Enter a floating point value. 3e-5 DPM_C_I/O.doc Page D-20 of 40 Rüdiger Siol 11.12.2009 15:24 Hochschule Ravensburg-Weingarten Fakultät Elektrotechnik und Informatik Mechatronik Information Processing Elementary C/C++ Programming D.4 The C File System Although the C file system differs from that used by C++, it largely parallels it. The C file system is composed of several interrelated functions. The most commonly used are listed in the Function and Purpose Table listed below. The common thread that ties the C I/O system tagether is the file pointer. A file pointer is a pointer to information that defines various things about the file, including its name, status, and current position. In essence, the file pointer identifies a specific disk file, and is used by the stream to tell each of the C I/O functions where to perform operations. A file pointer is a pointer variable of type FILE, which is defined in stdio.h. The remainder of this appendix discusses the basic file functions. Function fopen( ) fclose( ) fputc( ) fgetc( ) fwrite( ) fread( ) fseek( ) fprintf( ) fscanf( ) feof( ) ferror( ) rewind( ) remove( ) Purpose Opens a stream Closes a stream Writes a character to a stream Reads a character from a stream Writes a block of data to a stream Reads a block of data from a stream Seeks to specified byte in a stream Is to a stream what printf( ) is to the console Is to a stream what scanf( ) is to the console Returns true if end-of-file is reached Returns true if an error has occurred Resets the file position indicator to the beginning of the file Erases a file Highlevel file access open a file I/O fprintf fscanf fopen putc, fputc getc, fgetc formatted character mode fputs fgets string mode fwrite fread binary fseek ftell rewind positioning write buffer fflush close the file fclose erase the file remove ferror feof clearerr error handling operations on files (r.siol) 10.01.2007 DPM_C_I/O.doc Hochschule Ravensburg-Weingarten Technik | Wirtschaft | Sozialwesen Page D-21 of 40 107 Rüdiger Siol 11.12.2009 15:24 Hochschule Ravensburg-Weingarten Fakultät Elektrotechnik und Informatik Mechatronik Information Processing Elementary C/C++ Programming D.4.1 fopen( ) fopen( ) serves three functions: o It opens a stream for use o It links a file with that stream o It returns a FILE pointer to that stream Most often, and for the rest of this discussion, the file is a disk file. The fopen( ) function has this prototype: FILE *fopen(const char *filename, const char *mode); where filename points to the name of the file that is being opened, and mode points to a string containing the desired open status. The legal values for mode are shown in the Mode Table. The filename must be a string of characters that comprise a filename valid in the operating system; it may also include a path specification. The fopen( ) function returns a pointer of type FILE. This pointer identifies the file, and is used by most other file system functions. It should never be altered by your code. On failure, fopen( ) returns null. As the Mode Table shows, a file can be opened in either text mode or binary mode. In text mode, carriage-return/linefeed sequences are translated into newline characters on input. On output, the reverse occurs: newlines are translated into carriage-return/ linefeeds. No such translations occur on binary files. Mode "r" "w" "a" "rb" "wb" "ab" "r+" "w+" "a+" "r+b" "w+b" "a+b" Meaning Open a text file for reading Create a text file for writing Append to a text file Open a binary file for reading Create a binary file for writing Append to a binary file Open a text file for read/write Create a text file for read/write Append to or create a text file for read/write Open a binary file for read/write Create a binary file for read/write Append to or create a binary file for read/write DPM_C_I/O.doc Page D-22 of 40 Rüdiger Siol 11.12.2009 15:24 Hochschule Ravensburg-Weingarten Fakultät Elektrotechnik und Informatik Mechatronik Information Processing Elementary C/C++ Programming If you want to open a file for writing with the name test, then you could write fp = fopen( "test", "w"); where fp is a variable of type FILE *. However, you will usually see it written like this: if ( (fp = fopen (" test", "w")) ==NULL) { printf("Cannot open file."); exit (1) ; } This method detects any error in opening a file, such as a write-protected or full disk, before attempting to write to it. NULL is a macro defined in stdio.h. If you use fopen( ) to open a file for output, then any preexisting file by that name will be erased and a new file started. If no file by that name exists, then one will be created. If you want to add to the end of an existing file, then you must use mode "a". If the file does not exist, it will be created. Opening a file for read operations requires that the file exists. If it does not, an error will be returned. Finally, if a file is opened for read/write operations, it will not be erased if it exists; however, if it does not exist, it will be created. DPM_C_I/O.doc Page D-23 of 40 Rüdiger Siol 11.12.2009 15:24 Hochschule Ravensburg-Weingarten Fakultät Elektrotechnik und Informatik Mechatronik Information Processing Elementary C/C++ Programming D.4.1.1 Example of fopen() usage #include <stdio.h> #include <stdlib.h> int main(void) { FILE *f; int count; /* create a new file for output */ if (( f = fopen("today_2", "w")) == NULL) { printf("Can't create file.\n"); exit(1); } /* output numbers 0 to 9 */ for (count = 0; count < 10; count++) fprintf(f, "%5d", count); /* close the file */ fclose(f); /* open the file to append */ if (( f = fopen("today_2", "a")) == NULL) { printf("Can't append to file.\n"); exit(1); } /* output numbers 10 to 19 */ for (; count < 20; count++) fprintf(f, "%5d\n", count); /* close file */ fclose(f); return 0; } Created the file foofoo 0 1 11 12 13 14 15 16 17 18 19 2 3 DPM_C_I/O.doc 4 5 6 7 8 9 10 Page D-24 of 40 Rüdiger Siol 11.12.2009 15:24 Hochschule Ravensburg-Weingarten Fakultät Elektrotechnik und Informatik Mechatronik Information Processing Elementary C/C++ Programming D.4.2 fputc( ) The fputc( ) function is used to write characters to a stream that was previously opened für writing by using the fopen( ) function. Its prototype is: int fputc(int ch, FILE *fp); Here, fp is the file pointer returned by fopen( ), and ch is the character to be output. The file pointer tells fputc( ) which disk file to write to. Although ch is an int, only the loworder byte is used. If an fputc( ) operation is a success, then it will return the character written. Upon failure, an EOF is returned. D.4.2.1 Example of fputc() usage #include <stdio.h> #include <stdlib.h> int main(void) { FILE *f; int letter; /* create a new file for output */ if (( f = fopen("foofoo", "w")) == NULL) { printf("Can't create file.\n"); exit(1); } /* output the alphabet to the file one letter */ /* at a time */ for (letter = 'A'; letter <= 'Z'; letter++) fputc(letter, f); fclose(f); return 0; } Output to file foofoo ABCDEFGHIJKLMNOPQRSTUVWXYZ DPM_C_I/O.doc Page D-25 of 40 Rüdiger Siol 11.12.2009 15:24 Hochschule Ravensburg-Weingarten Fakultät Elektrotechnik und Informatik Mechatronik Information Processing Elementary C/C++ Programming D.4.3 fgetc( ) The fgetc( ) function is used to read characters from a stream opened in read mode by fopen( ). Its prototype is int fgetc(FILE *fp); Here, fp is a file pointer of type FILE returned by fopen( ). Although fgetc( ) returns an integer, the high-order byte is zero. The fgetc( ) function will return EOF when an error occurs or the end of the file has been reached. Therefore, to read to the end of a text file you could use the following code: ch = fgetc (fp) ; while(ch!=EOF) { ( ch = fgetc (fp) ; } D.4.3.1 Example of fgetc() usage #include <stdio.h> #include <stdlib.h> int main(void) { FILE *f; char filename[80], c; /* get a filename from the user printf("Enter a filename to read.\n"); gets(filename); */ /* open the file for input */ if (( f = fopen(filename, "r")) == NULL) { printf("Can't open %s.\n", filename); exit(1); } /* read the file one character at a time until /* end-of-file is reached */ while ( (c = fgetc(f)) != EOF) putchar(c); /* print the character */ /* close the file fclose(f); return 0; */ */ } Dialog and output: Enter a filename to read. foofoo ABCDEFGHIJKLMNOPQRSTUVWXYZ DPM_C_I/O.doc Page D-26 of 40 Rüdiger Siol 11.12.2009 15:24 Hochschule Ravensburg-Weingarten Fakultät Elektrotechnik und Informatik Mechatronik Information Processing Elementary C/C++ Programming D.4.4 feof( ) The C file system can also operate on binary data. When a file is opened for binary input, it is possible that an integer value equal to EOF may be read. This would cause the code shown above to indicate an end-of-file condition, even though the physical end of the file had not been reached. To solve this problem, C includes the function feof( ), which is used to determine end-of-file when reading binary data. It has the prototype int feof(FILE *fp); where fp identifies the file. The feof( ) function returns non-zero if the end of the file has been reached; otherwise, zero is returned. Therefore, the following reads a binary file until end-offile is encountered: while(!feof(fp)) ch = fgetc(fp); Of course, this same method can be applied to text files, as well. D.4.4.1 Example of feof() usage #include <stdio.h> #include <stdlib.h> int main(void) { FILE *f; static char filename[80], buf[80] = ""; /* get a filename from the user printf("Enter a filename to read.\n"); gets(filename); */ /* open the file for input */ if (( f = fopen(filename, "r")) == NULL) { printf("Can't open %s.\n", filename); exit(1); } /* read text lines from the file until /* feof() indicates the end-of-file for (; feof(f) == 0 ; fgets(buf, 80, f) ) printf(buf); /* close the file fclose(f); return 0; */ */ */ } Dialog and output Enter a filename to read. myfoo myfoo 483.5820 56 DPM_C_I/O.doc Page D-27 of 40 Rüdiger Siol 11.12.2009 15:24 Hochschule Ravensburg-Weingarten Fakultät Elektrotechnik und Informatik Mechatronik Information Processing Elementary C/C++ Programming D.4.5 fclose( ) The fclose( ) function closes a stream that was opened by a call to fopen( ). It writes any data still remaining in the disk buffer to the file, and does a formal operating-system-level close on the file. A call to fclose( ) frees the file control block associated with the stream and makes it available for reuse. As you probably know, there is an operating system limit to the number of open files you can have at any one time, so it may be necessary to close one file before opening another. The fclose( ) function has the following prototype: int fclose(FILE *fp); where fp is the file pointer returned by the call to fopen( ). A return value of zero signifies a successful close operation; EOF is returned if an error occurs. Generally, the only time fclose( ) will fail is when a disk has been prematurely removed from the drive or there is no more space on the disk. D.4.5.1 Example of fclose() usage #include <stdio.h> #include <stdlib.h> int main(void) { FILE *f; static char name[] = "myfoo"; /* create a new file for output if ( (f = fopen(name, "w")) == NULL) { printf("Can't open %s.\n", name); exit(1); } /* output text to the file fprintf(f, "pizza sushi falafel\n"); fprintf(f, "escargot sprocket\n"); */ */ /* close the file */ if (fclose(f) == -1) { printf("Can't close %s.\n", name); exit(1); } return 0; } Output to file myfoo: pizza sushi falafel escargot sprocket DPM_C_I/O.doc Page D-28 of 40 Rüdiger Siol 11.12.2009 15:24 Hochschule Ravensburg-Weingarten Fakultät Elektrotechnik und Informatik Mechatronik Information Processing Elementary C/C++ Programming D.4.6 ferror( ) and rewind( ) The ferror( ) function is used to determine whether a file operation has produced an error. It has the prototype int ferror(FILE *fp); where fp is a valid file pointer. ferror( ) returns true if an error has occurred during the last file operation; it returns false otherwise. Because each file operation sets the error condition, ferror( ) should be called immediately after each file operation; otherwise, an error may be lost. The rewind( ) function will reset the file position indicator to the beginning of the file specified as its argument. The prototype is void rewind(FILE *fp); where fp is a valid file pointer. D.4.6.1 Example of ferror() usage. #include <stdio.h> #include <stdlib.h> int main(void) { FILE *f; char filename[80], buf[80]; int ln = 0; /* get a filename from the user printf("Enter a filename to read.\n"); gets(filename); */ /* open the file for input */ if (( f = fopen(filename, "r")) == NULL) { printf("Can't open %s.\n", filename); exit(1); } /* read the file one line at a time until end-of-file do { fgets(buf, 80, f); printf("Status for line %d: %d.\n", ln++, ferror(f)); } while (feof(f) == 0); /* close the file fclose(f); return 0; */ */ } Dialog and output Enter a filename to read. foofoo Status for line 0: 0. DPM_C_I/O.doc Page D-29 of 40 Rüdiger Siol 11.12.2009 15:24 Hochschule Ravensburg-Weingarten Fakultät Elektrotechnik und Informatik Mechatronik Information Processing Elementary C/C++ Programming D.4.6.2 Example of rewind() usage #include <stdio.h> #include <stdlib.h> int main(void) { FILE *f; char filename[80], buf[80]; /* get a filename from the user printf("Enter a filename to read.\n"); gets(filename); */ /* open a file for input */ if (( f = fopen(filename, "r")) == NULL) { printf("Can't open %s.\n", filename); } printf("Reading first line twice.\n"); /* move the file position indicator to the beginning of the file rewind(f); /* read the first line fgets(buf, 80, f); printf("Once: %s\n", buf); */ /* move the file position indicator to the beginning of the file rewind(f); /* read the first line again fgets(buf, 80, f); printf("Twice: %s\n", buf); /* close the file fclose(f); return 0; */ */ */ */ } Dialog and output Enter a filename to read. myfoo Reading first line twice. Once: pizza sushi falafel Twice: pizza sushi falafel DPM_C_I/O.doc Page D-30 of 40 Rüdiger Siol 11.12.2009 15:24 Hochschule Ravensburg-Weingarten Fakultät Elektrotechnik und Informatik Mechatronik Information Processing Elementary C/C++ Programming D.4.7 fread( ) and fwrite( ) The C file system provides two functions, fread( ) and fwrite( ), that allow the reading and writing of blocks of data. These functions are similar to C++'s read( ) and write( ) functions. Their prototypes are size_t fread(void *buffer, size_t num_bytes, size_t count, FILE *fp); size_t fwrite(const void *buffer, size_t num_bytes, size_t count, FILE *fp); In the case of fread( ), buffer is a pointer to a region of memory that will receive the data read from the file. The function reads count number of objects, each object being num_bytes in length, from the stream pointed to by fp. fread( ) returns the number of objects read, which may be less than count if an error or the end of the file is encountered. For fwrite( ), buffer is a pointer to the information that will be written to the file. The function writes count number of objects, each object being num_bytes in length, to the stream pointed to by fp.fwrite( ) returns the number of objects written, which will be equal to count, unless an error occurs. As long as the file has been opened for binary operations, fread( ) and fwrite( ) can read and write any type of information. For example, this program writes a float to a disk file: /* Write a floating point number to a disk file. */ #include <stdio.h> int main () { FILE *fp; float f = l2.23F; if ( (fp=fopen ("test" , "wb") ) ==NULL) { printf("Cannot open file.\n"); return 1; } fwrite(&f, sizeof(float), 1, fp); fclose (fp) ; return 0; } As this program illustrates, the buffer can be, and often is, simply a variable. One of the most useful applications of fread( ) and fwrite( ) involves the reading and writing of arrays or structures. For example, the following program writes the contents of the floating-point array balance to the file "balance" by using a single fwrite( ) statement. Next, it reads the array, using a single fread( ) statement, and displays its contents. DPM_C_I/O.doc Page D-31 of 40 Rüdiger Siol 11.12.2009 15:24 Hochschule Ravensburg-Weingarten Fakultät Elektrotechnik und Informatik Mechatronik Information Processing Elementary C/C++ Programming D.4.7.1 The use of fwrite() and fread() #include <stdio.h> int main() { register int i; FILE *fp; float balance[100]; /* open for write */ if ( (fp=fopen ("balance" , "w") ) ==NULL) { printf ("Cannot open file. \n"); return 1; } for(i = 0; i < 100; i++) balance[i] = (float) i; /* This saves the entire balance array in one step. */ fwrite(balance, sizeof balance, 1, fp); fclose(fp) ; /* zero array */ for(i = 0; i < 100; i++) balance[i] = 0.0; /* open for read */ if ( (fp = fopen ("balance" , "r") ) ==NULL) { printf ("Cannot open file. \n") ; return 1; } /* This reads the entire balance array in one step. */ fread(balance, sizeof balance, 1, fp); /* display for(i = 0; printf("%f fclose(fp) return 0; contents of array */ i < 100; i++) ", balance[i]); ; } The program shows as output: 0.000000 1.000000 2.000000 3.000000 4.000000 5.000000 6.000000 7.000000 8.000000 9.000000 10.000000 11.000000 12.000000 13.000000 14.000000 15.000000 16.000000 17.000000 18.000000 19.000000 20.000000 21.000000 22.000000 23.000000 24.000000 25.000000 26.000000 27.000000 28.000000 29.000000 30.000000 31.000000 32.000000 33.000000 34.000000 35.000000 36.000000 37.000000 38.000000 39.000000 40.000000 41.000000 42.000000 43.000000 44.000000 45.000000 46.000000 47.000000 48.000000 49.000000 50.000000 51.000000 52.000000 53.000000 54.000000 55.000000 56.000000 57.000000 58.000000 59.000000 60.000000 61.000000 62.000000 63.000000 64.000000 65.000000 66.000000 67.000000 68.000000 69.000000 70.000000 71.000000 72.000000 73.000000 74.000000 75.000000 76.000000 77.000000 78.000000 79.000000 80.000000 81.000000 82.000000 83.000000 84.000000 85.000000 86.000000 87.000000 88.000000 89.000000 90.000000 91.000000 92.000000 93.000000 94.000000 95.000000 96.000000 97.000000 98.000000 99.000000 Using fread( ) and fwrite( ) to read or write blocks of data is more efficient than using repeated calls to fgetc( ) and fputc( ). DPM_C_I/O.doc Page D-32 of 40 Rüdiger Siol 11.12.2009 15:24 Hochschule Ravensburg-Weingarten Fakultät Elektrotechnik und Informatik Mechatronik Information Processing Elementary C/C++ Programming D.4.8 fseek( ) and Random-Access I/O You can perform random read and write operations using the C I/O system with the help of fseek( ), which sets the file position indicator. Its prototype is int fseek(FILE *fp, long numbytes, int origin); where fp is a file pointer returned by a call to fopen( ), numbytes is the number of bytes from origin to seek to, and origin is one of the following macros (defined in stdio.h): Origin Beginning of file Current position End of file Macro SEEK_SET SEEK_CUR SEEK_END Therefore, to seek numbytes from the start of the file, origin should be SEEK_SET. To seek from the current position, use SEEK_CUR, and from the end of the file, use SEEK_END. The fseek( ) function returns zero on success, and non-zero if a failure occurs. As a general rule, the use of fseek( ) on files opened in text mode is not recommended, because the character translations will cause position errors to result. Therefore, its use is suggested only for files opened in binary mode. For example, if you want to read the 234th byte in a file called test, you could use the following code: int func1 () { FILE *fp; if ( (fp = fopen (" test", "rb")) == NULL) { printf ("cannot open file\n"); exit (1) ; } fseek(fp, 234L, SEEK_SET); return getc(fp); /* read one character */ /* at 234th position */ } DPM_C_I/O.doc Page D-33 of 40 Rüdiger Siol 11.12.2009 15:24 Hochschule Ravensburg-Weingarten Fakultät Elektrotechnik und Informatik Mechatronik Information Processing Elementary C/C++ Programming D.4.8.1 Example of fseek() usage #include <stdio.h> #include <stdlib.h> int main(void) { FILE *f; long int pos1, pos2, newpos; char filename[80], buf[80]; /* get a filename from the user printf("Enter a filename to read.\n"); gets(filename); */ /* open a file for input */ if (( f = fopen(filename, "r")) == NULL) { printf("Can't open %s.\n", filename); exit(1); } printf("Reading last half of first line.\n"); /* get the file position indicator before and after /* reading the first line */ pos1 = ftell(f); fgets(buf, 80, f); pos2 = ftell(f); printf("Whole line: %s\n", buf); /* calculate the middle of the line newpos = (pos2 - pos1) / 2; fseek(f, newpos, SEEK_SET); fgets(buf, 80, f); printf("Last half: %s\n", buf); /* close the file fclose(f); return 0; */ */ */ } The dialog: Enter a filename to read. myfoo Reading last half of first line. Whole line: myfoo 483.5820 56 Last half: 5820 56 Another call: Enter a filename to read. foofoo Reading last half of first line. Whole line: 0 1 2 3 4 Last half: 5 DPM_C_I/O.doc 6 7 8 5 6 7 8 9 10 9 10 Page D-34 of 40 Rüdiger Siol 11.12.2009 15:24 Hochschule Ravensburg-Weingarten Fakultät Elektrotechnik und Informatik Mechatronik Information Processing Elementary C/C++ Programming D.4.9 fprintf( ) and fscanf( ) In addition to the basic I/O functions discussed above, the C I/O system includes fprintf( ) and fscanf( ). These functions behave exactly like printf( ) and scanf( ), except that they operate on files. For this reason, these functions are commonly found in C programs. The prototypes of fprintf( ) and fscanf( ) are int fprintf(FILE *fp, const char *fmt_string, ... ); int fscanf(FILE *fp, const char *fmt_string, ... ); where fp is a file pointer returned by a call to fopen( ). Except for directing their focus to the file defined by fp, they operate exactly like printf( ) and scanf( ), respectively. D.4.9.1 Example of fprintf() usage #include <stdio.h> #include <stdlib.h> int main(void) { FILE *f; static char filename[] = "myfoo"; int a = 56; char c = 'M'; double x = 483.582; /* create a new file for output if (( f = fopen(filename, "w")) == NULL) { printf("Can't open %s.\n", filename); exit(1); } */ /* output formatted text to the file */ fprintf(f, "%10s %4.4f %-10d\n%10c", filename, x, a, c); /* close the file fclose(f); return 0; */ } With the output to the file myfoo myfoo 483.5820 56 M DPM_C_I/O.doc Page D-35 of 40 Rüdiger Siol 11.12.2009 15:24 Hochschule Ravensburg-Weingarten Fakultät Elektrotechnik und Informatik Mechatronik Information Processing Elementary C/C++ Programming D.4.9.2 Example of fscanf() usage #include <stdio.h> #include <stdlib.h> int main(void) { FILE *f; int i; double x; char c; /* create a new file for output and input if (( f = fopen("foobar", "w+")) == NULL) { printf("Can't create new file.\n"); exit(1); } */ /* output formatted text to the file fprintf(f, "%d\n%f\n%c\n", 45, 983.3923, 'M'); */ /* go to the beginning of the file rewind(f); */ /* read from the stream using fscanf() fscanf(f, "%d %lf %c", &i, &x, &c); */ /* close the file */ fclose(f); printf("The integer read is %d.\n", i); printf("The floating point value is %f.\n", x); printf("The character is %c.\n", c); return 0; } Output: The integer read is 45. The floating point value is 983.392300. The character is M. DPM_C_I/O.doc Page D-36 of 40 Rüdiger Siol 11.12.2009 15:24 Hochschule Ravensburg-Weingarten Fakultät Elektrotechnik und Informatik Mechatronik Information Processing Elementary C/C++ Programming D.4.10 fflush() Empty a stream's buffer to its host environment. Prototype #include <stdio.h> int fflush(FILE *stream); Parameters Parameters for this facility are: stream FILE * A pointer to a FILE stream Remarks The fflush() function empties stream's buffer to the file associated with stream. If the stream points to an output stream or an update stream in which the most recent operation was not input, the fflush function causes any unwritten data for that stream to be delivered to the host environment to be written to the file; otherwise the behavior is undefined. NOTE The fflush() function should not be used after an input operation. NOTE Using fflush() for input streams especially the standard input stream (stdin) is undefined and is not supported and will not flush the input buffer. NOTE On embedded/ RTOS systems this function only is implemented for stdin, stdout and stderr files. Return The function fflush() returns EOF if a write error occurs, otherwise it returns zero. DPM_C_I/O.doc Page D-37 of 40 Rüdiger Siol 11.12.2009 15:24 Hochschule Ravensburg-Weingarten Fakultät Elektrotechnik und Informatik Mechatronik Information Processing Elementary C/C++ Programming D.4.10.1 Example of fflush() usage #include <stdio.h> #include <stdlib.h> int main(void) { FILE *f; int count; /* create a new file for output */ if (( f = fopen("file_070117", "w")) == NULL) { printf("Can't open file.\n"); exit(1); } for (count = 0; count < 100; count++) { fprintf(f, "%5d", count); if( (count % 10) == 9 ) { fprintf(f, "\n"); fflush(f); /* flush buffer every 10 numbers */ } } fclose(f); return 0; } Generated data in file_070117 0 1 10 20 30 40 50 60 70 80 90 2 11 21 31 41 51 61 71 81 91 3 12 22 32 42 52 62 72 82 92 DPM_C_I/O.doc 4 13 23 33 43 53 63 73 83 93 5 6 7 8 14 15 16 24 25 26 34 35 36 44 45 46 54 55 56 64 65 66 74 75 76 84 85 86 94 95 96 9 17 27 37 47 57 67 77 87 97 18 28 38 48 58 68 78 88 98 19 29 39 49 59 69 79 89 99 Page D-38 of 40 Rüdiger Siol 11.12.2009 15:24 Hochschule Ravensburg-Weingarten Fakultät Elektrotechnik und Informatik Mechatronik Information Processing Elementary C/C++ Programming D.5 Erasing Files The remove( ) function erases the specified file. Its prototype is int remove(const char *filename); It returns zero upon success, and non-zero if it fails. DPM_C_I/O.doc Page D-39 of 40 Rüdiger Siol 11.12.2009 15:24 Hochschule Ravensburg-Weingarten Fakultät Elektrotechnik und Informatik Mechatronik Information Processing Elementary C/C++ Programming D.6 More Examples to C-Based I/O D.6.1 The use of EOF during keyboard input /* DPM_Example_c */ #include <stdio.h> int main (void) { int zeichen; while ((zeichen = getchar()) != EOF) putchar(zeichen); printf("\nSie haben Strg + D bzw. Strg + Z getippt um End of file (EOF) zu erzeugen.\n"); return 0; } DPM_C_I/O.doc Page D-40 of 40 Rüdiger Siol 11.12.2009 15:24