Chapter 13
The C language provides no direct facilities for input and output (IO), and, instead, these operations are supplied as functions in the standard library. This chapter describes the most commonly used functions. It also discusses the topic of command-shell redirection which, while non-standard, is widely supported, and the topic of command-line arguments, which enables a program to receive instructions from its calling environment.
It is important to realise that this chapter does not present all the functions related to IO in the standard library and, of the functions it does discuss, it does not cover every detail. More complete information can be found in, for example, [KR88, pages 241–248] and [HS95, pages 343–383].
13.1 Formatted IO
The standard functions for formatted IO, printf() and scanf(), have been mentioned at a cursory level in previous chapters. These functions are very powerful and possess a level of sophistication beyond the scope of this text (although we will touch on these more complex aspects briefly). However, for most common purposes, they are intuitive, flexible and simple to use.
The function printf() is a general purpose print function that converts and formats its arguments to a character string, and prints the result to standard output (typically the screen). The general interface for printf() is
int printf(const char *format, arg1, arg2, ...);
The first argument is a format string, which defines the layout of the printed text. This is followed by zero or more optional arguments, with the number of arguments, and their type, being determined by the contents of the format string. The return value is the number of characters printed, unless an error occurs during output whereupon the return value is EOF.
The format string is composed of ordinary characters and conversion specification characters. The former are printed verbatim, while the latter are used to control the conversion of the optional arguments following the format string. Conversion specifications are identified by a % character followed by a number of optional fields and terminated by a type conversion character. A simple example is
printf("%d green %s sitting on a wall.\n", 10, "bottles");
where the ordinary characters “green” and “sitting on a wall.\n” are printed verbatim, and the conversion specifiers %d and %s insert the additional arguments at the appropriate locations. The
type conversion character must match its associated argument type; in the example, the %d indicates an integer argument and the %s indicates a string argument.
There are di erent conversion characters for ints (d, i, o, x, c), unsigned ints (u), doubles (f, e, g), strings (s), and pointers (p). Details of these may be found in any C reference text. To print a % character, the conversion specification %% is used.
Between the % and the type conversion character there may exist a number of optional fields. These control the formatting of the converted argument. Consider, for example, the conversion specifier %-#012.4hd (this example is from [HS95, page 368]).
if image dont show plz download c programming pdf file
The first field is a set of flags, which modify the meaning of the conversion operation (e.g., make the argument left-justified, or pad with zeros). The second field specifies a minimum width reserved for the converted argument (in characters), and so provides padding for under-sized values. The third field is a precision specification, which has various di erent meanings for integers, floating point values and strings. The fourth field is a size modifier, which indicates conversion to a longer or shorter type than the default conversion types (where the default types are, for example, int or double).
Again, a good reference text will have more information regarding these conversion specifications. Most often printf() involves just the % and a conversion character, and rarely get more complex than the following example,
printf("Value = %-10.3f radians.\n", fval);
which, if passed the floating point value 3.14159, would print
Value = 3.142 radians.
where the converted floating point value is left-justified (due to the - flag), is padded with su cient space for 10 characters, and displays 3 digits after the decimal point.
It is essential that the type conversion specifier matches the type of the argument, as the compiler cannot catch type-mismatches for variable-length argument lists. However, there is no need for conversion characters for types float and short, etc, as these types are automatically converted to double and int, respectively, by the usual argument promotion rules.1
Aside. The ability of write functions with variable-length argument lists is not restricted to im-plementers of the standard library. The standard provides facilities that enable application pro-grammers to write functions with these same capabilities. The standard header stdarg.h contains a set of macro definitions that define how to step through an argument list. The declaration of a variable-length argument list is marked by ellipsis (...) in the function interface, and typically the type and number of arguments is specified using a format string, as in the following example.
int varfunc(char *format, ...);
Note, the ellipsis declaration may only appear at the end of an argument list. The implementation of such functions using the macros from stdarg.h is beyond the scope of this text.2
1 It is permitted, but bad practice, to call a function without it being previously declared. However, this prevents the compiler from performing type-checking. As a result, the compiler has di erent type conversion rules for arguments passed to functions that have explicit prototypes, and functions that don’t. Functions with variable-length argument lists similarly bypass compiler type-checking, and so incur the same type promotion rules as for non-prototyped
functions.
2See [KR88, page 156] for a nice example, which shows an implementation of a simplified version of printf().
13.1.2 Formatted Input: scanf()
The scanf() function is the input analog of printf(), providing many of the same conversion specifications in the opposite direction (although there are di erences, so be wary). It obtains data from standard input, which is typically the keyboard. The general interface for scanf() is
int scanf(const char *format, ...);
This is identical to printf() in form, with a format string and a variable argument list, but an important di erence is that the arguments for scanf() must be pointer types. This allows the input data to be stored at the address designated by the pointer using pass-by-reference semantics. For example,
double fval;
scanf("%lf", fval); /* Wrong */
scanf("%lf", &fval); /* Correct, store input in fval. */
scanf() reads characters from standard input and interprets them according to the format string specification. It stops when it exhausts the format string, or when some input fails to match a conversion specification. Its return value is the number of values successfully assigned in its variable-length argument list.3 If a conflict occurs between the a conversion specification and the actual input, the character causing the conflict is left unread and is processed by the next standard input operation.
The mechanics of the format string and its conversion specifications are even more complicated for scanf() than for printf(), and there are many details and caveats that will not be discussed here. Most of the conversion characters for printf()—d, i, o, x, c, u, f, e, g, s, p, etc—have similar meanings for scanf(), but there are certain di erences, some subtle. Thus, one should not use the documentation for one as a guide for the other. Some of these di erences are as follows.
• Where printf() has four optional fields, scanf() has only two. It has the width and size modifier fields but not the flags and precision fields.
• For printf() the width field specifies a minimum reserve of space (i.e., padding), while for scanf() it defines a maximum limit on the number of characters to be read.4
• An asterisk character (*) may be used in place of the width field for both printf() and scanf(), but with di erent meanings. For printf() it allows the width field to be determined by an additional argument, but for scanf() it suppresses assignment of an input value to its argument.
• The conversion character [ is not valid for printf(), but for scanf() it permits a scanset of characters to be specified, which allows scanf() to control exactly the characters it reads in.
• The size modifier field is typically neglected for printf(), but is vital for scanf(). For example, to read a float, one uses the conversion specifier %f. To read a double, the size modifier l (for long) must appear, %lf.
Of the above, the third and fourth points are rather advanced features that we will not dwell on further.5 However, the last point is important, and a common source of errors for new C programmers. The conversion specifier and size modifier must match the associated argument type or the result is undefined.
3 scanf() will return 0 if the first conversion specification does not match the first parsed value, unless that value is the end-of-file character (which for Win32 keyboard input is produced by typing Ctrl-Z). For this case, or if there
is an error, scanf() returns EOF.
4To complicate matters further, the %c conversion in scanf() provides yet another interpretation of the width field: the input of an array of characters. For example, the conversion %10c reads 10 characters into a character array.
5The best available detailed explanation of these and other aspects of the standard library is [HS95, HS02].
The scanf() format string consists of conversion specifiers, ordinary characters, and white-space. Where ordinary characters appear in the format string, they must match exactly the format of the input. For example, the following statement is used to read a date of the form dd/mm/yy.
int day, month, year;
scanf("%d/%d/%d", &day, &month, &year);
In general scanf() ignores white-space characters in its format string, and skips over white-space in stdin as it looks for input values. Exceptions to this rule arise with the %c and %[ conversion specifiers, which do not skip white-space. For example, if the user types in “one two” for each of the statements below, they will obtain di erent results.
char s[10], c;
scanf("%s%c", s, &c); /* s = "one", c = ’ ’ */ scanf("%s %c", s, &c); /* s = "one", c = ’t’ */
In the first case, the %c reads in the next character after %s leaves o , which is a space. In the second, the white-space in the format string causes scanf() to consume any white-space after “one”, leaving the first non-space character (t) to be assigned to c.
While the many details of scanf() formatting complicates a complete understanding, its basic use is quite simple. Rarely does an input statement get more complicated than
short a;
double b;
char c[20];
scanf("%hd %lf %s", &a, &b, c);
However, it is worth noting that the above form of string (%s) input is not ideal. A string is read up to the first white-space character unless terminated early by a width field. Thus, a very long input of consecutive non-space characters may overflow the string’s character bu er. To prevent overflow, a string conversion specification should always include a width field. Consider a situation where a user types in the words “small supererogatory” for the following input code.
char s1[10], s2[10], s3[10];
scanf("%9s %9s %9s", s1, s2, s3);
Notice the width fields are one-less than the array sizes to allow room for the terminating \0. The first word “small” fits into s1, but the second word is over-long—its first nine characters “supererog” are placed in s2 and the rest “atory” goes into s3.
A few final warnings about scanf(). First, keep in mind that the arguments in its variable length argument list must be pointers; forgetting the & in front of non-pointer variables is a very common mistake. Second, when there is a conflict between a conversion specification and the actual input, the o ending character is left unread. Thus, an expression like
while (scanf("%d", &val) != EOF)
is dangerous as it will loop forever if there is a conflict. Third, while scanf() is a good choice when the exact format of the input is known, other input techniques may be better suited if the format may vary. For example, the combination of fgets() and sscanf(), described in the next section, is a useful alternative if the input format is not precisely known. The fgets() function reads a line of characters into a bu er, and sscanf() extracts the data, and can pick out di erent parts using multiple passes if necessary.
Input and Output
The C language provides no direct facilities for input and output (IO), and, instead, these operations are supplied as functions in the standard library. This chapter describes the most commonly used functions. It also discusses the topic of command-shell redirection which, while non-standard, is widely supported, and the topic of command-line arguments, which enables a program to receive instructions from its calling environment.
It is important to realise that this chapter does not present all the functions related to IO in the standard library and, of the functions it does discuss, it does not cover every detail. More complete information can be found in, for example, [KR88, pages 241–248] and [HS95, pages 343–383].
13.1 Formatted IO
The standard functions for formatted IO, printf() and scanf(), have been mentioned at a cursory level in previous chapters. These functions are very powerful and possess a level of sophistication beyond the scope of this text (although we will touch on these more complex aspects briefly). However, for most common purposes, they are intuitive, flexible and simple to use.
13.1.1 Formatted Output: printf()
The function printf() is a general purpose print function that converts and formats its arguments to a character string, and prints the result to standard output (typically the screen). The general interface for printf() is
int printf(const char *format, arg1, arg2, ...);
The first argument is a format string, which defines the layout of the printed text. This is followed by zero or more optional arguments, with the number of arguments, and their type, being determined by the contents of the format string. The return value is the number of characters printed, unless an error occurs during output whereupon the return value is EOF.
The format string is composed of ordinary characters and conversion specification characters. The former are printed verbatim, while the latter are used to control the conversion of the optional arguments following the format string. Conversion specifications are identified by a % character followed by a number of optional fields and terminated by a type conversion character. A simple example is
printf("%d green %s sitting on a wall.\n", 10, "bottles");
where the ordinary characters “green” and “sitting on a wall.\n” are printed verbatim, and the conversion specifiers %d and %s insert the additional arguments at the appropriate locations. The
type conversion character must match its associated argument type; in the example, the %d indicates an integer argument and the %s indicates a string argument.
There are di erent conversion characters for ints (d, i, o, x, c), unsigned ints (u), doubles (f, e, g), strings (s), and pointers (p). Details of these may be found in any C reference text. To print a % character, the conversion specification %% is used.
Between the % and the type conversion character there may exist a number of optional fields. These control the formatting of the converted argument. Consider, for example, the conversion specifier %-#012.4hd (this example is from [HS95, page 368]).
if image dont show plz download c programming pdf file
The first field is a set of flags, which modify the meaning of the conversion operation (e.g., make the argument left-justified, or pad with zeros). The second field specifies a minimum width reserved for the converted argument (in characters), and so provides padding for under-sized values. The third field is a precision specification, which has various di erent meanings for integers, floating point values and strings. The fourth field is a size modifier, which indicates conversion to a longer or shorter type than the default conversion types (where the default types are, for example, int or double).
Again, a good reference text will have more information regarding these conversion specifications. Most often printf() involves just the % and a conversion character, and rarely get more complex than the following example,
printf("Value = %-10.3f radians.\n", fval);
which, if passed the floating point value 3.14159, would print
Value = 3.142 radians.
where the converted floating point value is left-justified (due to the - flag), is padded with su cient space for 10 characters, and displays 3 digits after the decimal point.
It is essential that the type conversion specifier matches the type of the argument, as the compiler cannot catch type-mismatches for variable-length argument lists. However, there is no need for conversion characters for types float and short, etc, as these types are automatically converted to double and int, respectively, by the usual argument promotion rules.1
Aside. The ability of write functions with variable-length argument lists is not restricted to im-plementers of the standard library. The standard provides facilities that enable application pro-grammers to write functions with these same capabilities. The standard header stdarg.h contains a set of macro definitions that define how to step through an argument list. The declaration of a variable-length argument list is marked by ellipsis (...) in the function interface, and typically the type and number of arguments is specified using a format string, as in the following example.
int varfunc(char *format, ...);
Note, the ellipsis declaration may only appear at the end of an argument list. The implementation of such functions using the macros from stdarg.h is beyond the scope of this text.2
1 It is permitted, but bad practice, to call a function without it being previously declared. However, this prevents the compiler from performing type-checking. As a result, the compiler has di erent type conversion rules for arguments passed to functions that have explicit prototypes, and functions that don’t. Functions with variable-length argument lists similarly bypass compiler type-checking, and so incur the same type promotion rules as for non-prototyped
functions.
2See [KR88, page 156] for a nice example, which shows an implementation of a simplified version of printf().
13.1.2 Formatted Input: scanf()
The scanf() function is the input analog of printf(), providing many of the same conversion specifications in the opposite direction (although there are di erences, so be wary). It obtains data from standard input, which is typically the keyboard. The general interface for scanf() is
int scanf(const char *format, ...);
This is identical to printf() in form, with a format string and a variable argument list, but an important di erence is that the arguments for scanf() must be pointer types. This allows the input data to be stored at the address designated by the pointer using pass-by-reference semantics. For example,
double fval;
scanf("%lf", fval); /* Wrong */
scanf("%lf", &fval); /* Correct, store input in fval. */
scanf() reads characters from standard input and interprets them according to the format string specification. It stops when it exhausts the format string, or when some input fails to match a conversion specification. Its return value is the number of values successfully assigned in its variable-length argument list.3 If a conflict occurs between the a conversion specification and the actual input, the character causing the conflict is left unread and is processed by the next standard input operation.
The mechanics of the format string and its conversion specifications are even more complicated for scanf() than for printf(), and there are many details and caveats that will not be discussed here. Most of the conversion characters for printf()—d, i, o, x, c, u, f, e, g, s, p, etc—have similar meanings for scanf(), but there are certain di erences, some subtle. Thus, one should not use the documentation for one as a guide for the other. Some of these di erences are as follows.
• Where printf() has four optional fields, scanf() has only two. It has the width and size modifier fields but not the flags and precision fields.
• For printf() the width field specifies a minimum reserve of space (i.e., padding), while for scanf() it defines a maximum limit on the number of characters to be read.4
• An asterisk character (*) may be used in place of the width field for both printf() and scanf(), but with di erent meanings. For printf() it allows the width field to be determined by an additional argument, but for scanf() it suppresses assignment of an input value to its argument.
• The conversion character [ is not valid for printf(), but for scanf() it permits a scanset of characters to be specified, which allows scanf() to control exactly the characters it reads in.
• The size modifier field is typically neglected for printf(), but is vital for scanf(). For example, to read a float, one uses the conversion specifier %f. To read a double, the size modifier l (for long) must appear, %lf.
Of the above, the third and fourth points are rather advanced features that we will not dwell on further.5 However, the last point is important, and a common source of errors for new C programmers. The conversion specifier and size modifier must match the associated argument type or the result is undefined.
3 scanf() will return 0 if the first conversion specification does not match the first parsed value, unless that value is the end-of-file character (which for Win32 keyboard input is produced by typing Ctrl-Z). For this case, or if there
is an error, scanf() returns EOF.
4To complicate matters further, the %c conversion in scanf() provides yet another interpretation of the width field: the input of an array of characters. For example, the conversion %10c reads 10 characters into a character array.
5The best available detailed explanation of these and other aspects of the standard library is [HS95, HS02].
The scanf() format string consists of conversion specifiers, ordinary characters, and white-space. Where ordinary characters appear in the format string, they must match exactly the format of the input. For example, the following statement is used to read a date of the form dd/mm/yy.
int day, month, year;
scanf("%d/%d/%d", &day, &month, &year);
In general scanf() ignores white-space characters in its format string, and skips over white-space in stdin as it looks for input values. Exceptions to this rule arise with the %c and %[ conversion specifiers, which do not skip white-space. For example, if the user types in “one two” for each of the statements below, they will obtain di erent results.
char s[10], c;
scanf("%s%c", s, &c); /* s = "one", c = ’ ’ */ scanf("%s %c", s, &c); /* s = "one", c = ’t’ */
In the first case, the %c reads in the next character after %s leaves o , which is a space. In the second, the white-space in the format string causes scanf() to consume any white-space after “one”, leaving the first non-space character (t) to be assigned to c.
While the many details of scanf() formatting complicates a complete understanding, its basic use is quite simple. Rarely does an input statement get more complicated than
short a;
double b;
char c[20];
scanf("%hd %lf %s", &a, &b, c);
However, it is worth noting that the above form of string (%s) input is not ideal. A string is read up to the first white-space character unless terminated early by a width field. Thus, a very long input of consecutive non-space characters may overflow the string’s character bu er. To prevent overflow, a string conversion specification should always include a width field. Consider a situation where a user types in the words “small supererogatory” for the following input code.
char s1[10], s2[10], s3[10];
scanf("%9s %9s %9s", s1, s2, s3);
Notice the width fields are one-less than the array sizes to allow room for the terminating \0. The first word “small” fits into s1, but the second word is over-long—its first nine characters “supererog” are placed in s2 and the rest “atory” goes into s3.
A few final warnings about scanf(). First, keep in mind that the arguments in its variable length argument list must be pointers; forgetting the & in front of non-pointer variables is a very common mistake. Second, when there is a conflict between a conversion specification and the actual input, the o ending character is left unread. Thus, an expression like
while (scanf("%d", &val) != EOF)
is dangerous as it will loop forever if there is a conflict. Third, while scanf() is a good choice when the exact format of the input is known, other input techniques may be better suited if the format may vary. For example, the combination of fgets() and sscanf(), described in the next section, is a useful alternative if the input format is not precisely known. The fgets() function reads a line of characters into a bu er, and sscanf() extracts the data, and can pick out di erent parts using multiple passes if necessary.
No comments:
Post a Comment