Anda di halaman 1dari 12

Formatted Output and the printf function

One of the most important and common tasks in virtually every program is the printing of output. Programs use output to request input from a user, to display status messages, and to inform the user of the results of computations that the program performs. For obvious reasons, the manner in which the program displays its output can have a profound effect on the usefulness and usability of a program. When a program prints its output in a neatly formatted fashion, the output is always easier to read and understand. As a result, being able to write programs easily that produce attractive output is an essential feature of most programming languages. C has a family of library functions that provide this capability. All of these functions reside in the stdio library. Although the library contains several functions for printing formatted output, it is likely that you will only use two of them with any frequency. One, the printf (short for "print formatted") function, writes output to the computer monitor. The other, fprintf, writes output to a computer file. They work in almost exactly the same way, so learning how printf works will give you (almost) all the information you need to use fprintf.

Using printf to print messages


To use the printf function, you must first insure that you have included the stdio library in your program. You do this by placing the C preprocessor directive # i n c l u d e< s t d i o . h > at the beginning of your program. If you are also including other libraries, you will have other # i n c l u d e directives; the order of these does not matter. When you actually use the printf function, that is, when you want your program to print something on the screen, you will place a call to the function in your source code. When we want a function to perform its task we say we "call" it, and a function call is a type of program statement. All function calls have the same basic format. The first part of the call is always the name of the function (in this case, printf). Following the function name is an argument list or parameter list . The terms "argument" and "parameter" are synonymous in computer programming. An argument list provides information for the function. In the same way that a mathematical function takes some input value, performs a transformation, and produces a result (output), functions in C typically require some input as well. For the printf function, the argument list will provide the information that the function should print to the screen. We generally say that we pass arguments to a function. An argument list has a particular form as well. First, a pair of parentheses always encloses the list of arguments. Inside the parentheses, we separate multiple arguments from each other with a comma. Since a function call is a kind of statement, you will also need to follow the call with a semicolon, just after the closing parenthesis of the argument list. We can formalize a function call then as follows: function_name (argument1, argument2, ...); The "..." signifies that there may be more arguments. In fact, there may also be fewer arguments. Different functions require different kinds of input. Some functions need only one parameter, others may need many, and some do not need any parameters at all. In this last case, the argument list would simply be a pair of parentheses with nothing inside. In most cases, any given function needs a particular number of parameters. That is, we might have a function that requires three pieces of information to perform its task. Every time we call that function, we will need to provide exactly three parameters in its argument list. The printf function is unusual,

because the number of parameters it needs is variable. It always requires at least one argument, called the format string. Depending on what this argument contains, we may need to pass other parameters to printf as well. In C, a "string" is a sequence of one or more characters that the programmer intends to use as a unit (such as a word or sentence). The first program you saw printed a sentence, "Hello world," to the screen. The series of characters that forms this sentence is a string. To ensure that the compiler processes a string as a string, rather than as identifiers, we use a pair of double quotes around a string constant to show that it is a string. This is quite similar to using single quotes to indicate a character constant. It is important to remember that the single and double quotes are not interchangeable. Later, you will learn the difference between a one-character string, such as "a" and a single character, such as 'a'. For now, you must simply try to remember that they are different. The following mnemonic may help you remember when to use double quotes and when to use single quotes. A character is always just one character, while a string usually contains several characters. Thus, a character is usually "shorter" than a string. The single quote is also "shorter" than the double quote, so you use the "short" with the "short." In its simplest form, a format string is just a series of characters that you want to print to the screen. It will print exactly as it appears in the argument list, except that the double quotes will not appear. This is generally how you would use printf to print a prompt to request that the user of a program enter some data. For example, if you wanted to ask a user to type a number, you might call printf as follows: p r i n t f( " P l e a s et y p ea ni n t e g e rt h e np r e s sE n t e r :" ) ; When the computer executes this statement, the message will appear on the screen: P l e a s et y p ea ni n t e g e rt h e np r e s sE n t e r :|

You will often use this simplest kind of format string when you want to display some sort of status message or explanation on the screen. For instance, if you wrote a program that you knew would take some time to perform a task, you would probably want to let the user know that the program was working and had not crashed. You might use printf to tell the user what the program is doing: p r i n t f( " S e a r c h i n g ,p l e a s ew a i t . . . " ) ; On the screen, you would see: S e a r c h i n g ,p l e a s ew a i t . . . |

In both of the examples above, once the message has appeared, the cursor will remain at the end of the printed output. If you called printf again, the next message would appear immediately after the first one. Usually, this will not be what you want. Instead, you will want to print the next message on the next line of the screen, but you will need to tell printf to do this; it will not happen automatically. You know that if you are typing that you press the Enter key to get from one line to the next, but, as a programmer, if you press the Enter key inside the double quotes of the format string, the cursor will go to the next line of your source code file. If you then type the double

quote, closing parenthesis, and semicolon and then try to compile the program, the compiler will give you a syntax error. Usually, the error message will tell you that you have an "unterminated string constant." This is because the compiler expects to find the closing double quote on the same line as the opening double quote.

More control using escape sequences


Obviously, then, we need another way to tell printf to send the cursor to the next line after printing the rest of the characters in the format string. C uses escape sequences within a format string to indicate when we want printf to print certain special characters, such as the character that the Enter key produces. The escape character for a newline (which sends the cursor to the beginning of the next line on the screen) is \n. The backslash is called the escape character in this context and it indicates that the programmer wants to insert a special character into the format string. Without the backslash, printf would simply print the 'n'. You might guess that the 'n' is an abbreviation for "newline." C provides several escape sequences, but only a few are common. Others that you might find useful appear in the following table: Escape sequence Action \n prints a newline \b prints a backspace (backs up one character) \t prints a tab character \\ prints a backslash \" prints a double quote If we alter the second example above as follows: p r i n t f( " S e a r c h i n g ,p l e a s ew a i t . . . \ n " ) ; the screen will appear as before, except that now the cursor will be on the next line. Furthermore, if the program contains another printf statement later on, the next output will be printed on that same next line. S e a r c h i n g ,p l e a s ew a i t . . . |

Here are a few more examples of printf statements that make use of escape sequences: p r i n t f( " \ n N a m e \ t A d d r e s s \ n " ) ; produces: N a m e | A d d r e s s

p r i n t f( " J o e ' sD i n e r \ b " ) ; displays: J o e ' sD i n e |

p r i n t f( " P l e a s et y p e\ " Y e s \ "o r\ " N o \ " :" ) ; prints: P l e a s et y p e" Y e s "o r" N o " :|

Using printf to print values with format specifiers


As you can see, escape sequences give us some ability to format output even when we use the simplest form or the printf function, but printf is actually much more powerful than we have seen. First, assume for a moment that you have declared a variable in your program as follows: i n tn u m b e r=1 0 ; Now suppose that you want to prove to yourself that the variable number really does hold the value 10. You want to display the string "The value of number is 10" on the screen. You might try calling printf as follows: p r i n t f( " T h ev a l u eo fn u m b e ri sn u m b e r \ n " ) ; / *T h i sw o n ' tw o r k* / Of course, because printf prints the format string exactly as it appears (except for the escape sequences), what you will see on the screen is: T h ev a l u eo fn u m b e ri sn u m b e r |

The problem is that within the program's source code, we have only one way to refer to the variable number and that is by its name. The names of identifiers are made up of characters, so if we place a variable's name in a format string, printf will simply print that name. Just as C solves the problem of displaying special characters within a format string through the use of escape sequences, it solves this problem using another special notation within the format string. Besides escape sequences, the format string argument can also contain format specifiers. A format specifier is a placeholder that performs two functions. First, it shows where in the output to place an item not otherwise represented in the format string and it indicates how printf should represent the item. The "item" is most often a variable, but it can also be a constant. In particular, format specifiers allow us to print the values of variables as well as printing their names. All format specifiers begin with a percent sign, just as all escape sequences begin with a backslash. What follows the percent sign tells at least what data type printf should expect to print. It can also indicate exactly how the programmer wants printf to display it. Schematically, we can represent the syntax for a format specifier as follows: %[flags][width][.precision]type_character As usual, italics indicate placeholders for which a programmer must substitute a specific value. The square brackets that appear in this syntax template mean that the placeholders within are optional. They can appear or

not, as the needs of the programmer dictate. The brackets themselves do not appear in the source program. Most of the time, format specifiers will not include any of the optional items. The options give the programmer precise control over the spacing of the output and even over how much of the output printf will display. Thus, most often a format specifier will simply be a percent sign followed by a "type character." The type character is what tells printf what data type to print. The following table shows the most common type characters (several others exist): type character print format d integer number printed in decimal (preceded by a minus sign if the number is negative) f floating point number (printed in the form dddd.dddddd) E floating point number (printed in scientific notation: d.dddEddd) g floating point number (printed either as f or E, depending on value and precision) x integer number printed in hexadecimal with lower case letters X integer number printed in hexadecimal with upper case letters c character s string For example, the format string "%d" indicates to printf that it should write an integer in base 10 format, whereas the format string "%s" tells printf to print a string. Notice that the format specifiers tell what kind of thing the programmer wants to display, but they do not tell what value to print. That means that printf will need some additional information in the form of an additional argument. A format string can contain more than one format specifier and the format specifier(s) can appear in conjunction with other text, including escape sequences. Each format specifier that appears in the format string requires an additional argument in the argument list. The additional argument specifies what value printf should substitute for the format specifier. For instance, the following call to printf will display the value of our variable number: p r i n t f( " T h ev a l u eo fn u m b e ri s% d \ n " ,n u m b e r ) ; T h ev a l u eo fn u m b e ri s1 0 |

The two arguments to this call to printf combine to tell the function exactly what to write on the screen. What happens is that the printf function actually takes apart the format string and checks each character before displaying it. Whenever it encounters the percent sign, it checks the next character. If the next character is a type character, printf retrieves the next argument in the argument list and prints its value. If the next character is not a type character, printf simply displays the percent sign. For example, p r i n t f( " T h ev a l u eo fn u m b e ri s% q \ n " ,n u m b e r ) ; will print: T h ev a l u eo fn u m b e ri s% q |

Although it is unlikely that you will ever really want to do so, you may be asking, "so what if I want to print something like '%d' on the screen." If printf finds the sequence %d in a format string, it will substitute a value for it. To print one of the format specifiers to the screen, then, you have to "trick" printf. The following call: p r i n t f( " T h e%\ b df o r m a ts p e c i f i e rp r i n t sab a s e1 0n u m b e r . \ n " ) ; will display: T h e% df o r m a ts p e c i f i e rp r i n t sab a s e1 0n u m b e r . |

In the format string, a blank space follows the percent sign, not a type character, so printf will simply display the percent sign. It then displays the blank space (the next character in the format string), and then it displays the backspace character (specified with the escape sequence \b). This effectively erases the blank space. The next character in the format string is the letter 'd', which printf writes in the place where it originally wrote the blank. We mentioned above that we can have more than one format specifier in a format string. If we do this, we will need one additional argument for each of the format specifiers. Furthermore, the arguments must appear in the same order as the format specifiers. Examine the following examples: p r i n t f( " T h ev a l u eo fn u m b e r ,% d ,m u l t i p l e db y2 ,i s% d . \ n " , n u m b e r ,n u m b e r * 2 ) ; prints: T h ev a l u eo fn u m b e r ,1 0 ,m u l t i p l i e db y2 ,i s2 0 . |

As you can see from the previous example, the argument can be an expression such as number * 2 as well as a variable. p r i n t f( " T h ev a l u eo fn u m b e r ,% d ,m u l t i p l e db y2 ,i s% d . \ n " , n u m b e r * 2 ,n u m b e r ) ; displays: T h ev a l u eo fn u m b e r ,2 0 ,m u l t i p l i e db y2 ,i s1 0 . |

In the preceding example, the order of the additional parameters is wrong, so the output is plainly nonsensical. You must remember that printf does not understand English, so it cannot determine which argument belongs with which format specifier. Only the order of the parameters matters. The printf function substitutes the first of the additional arguments for the first format specifier, the second of the additional arguments for the second format specifier, and so on. Thus, p r i n t f( " % d+% d=% d \ n " ,n u m b e r ,n u m b e r * 2 ,n u m b e r+n u m b e r * 2 ) ; writes:

1 0+2 0=3 0 |

Because printf uses the additional parameters to give it the values to substitute for the format specifiers, it is essential that, as a programmer, you supply enough parameters. For instance, if we rewrite the preceding example as follows so that we have three format specifiers in the format string, but only two additional parameters: p r i n t f( " % d+% d=% d \ n " ,n u m b e r ,n u m b e r * 2 ) ; printf will print something bizarre on the screen. Since it has no value for the third format specifier, it will print a garbage value. We have no way to predict exactly what value it will display (it may even coincidentally be the right value!), but it would not be surprising to see output such as: 1 0+2 0=4 7 9 7 |

The moral of the story is that if you see strange output when you are using format specifiers, one of the first things you should check is the order and number of the additional arguments. You might also see unexpected output for one other reason. The type character in the format specifier determines completely how printf will display a value. If you include a format specifier with a particular type character in your format string and then give an argument of a different data type, printf will display the value of the argument using the syntax for values corresponding to the type character, not the syntax corresponding to the data type of the argument. For example, p r i n t f( " % d " ,' a ' ) ; will print: 9 7 |

since the ASCII code for 'a' is 97. p r i n t f( " % f " ,5 ) ; will display: 5 . 0 0 0 0 0 0 |

In each example, printf makes an implicit type conversion of its argument to force it to agree with the data type

that the type character specifies. In some special cases, you can use this automatic conversion to your advantage, but most of the time, you will want to ensure that the data type of the argument matches the type character.

More control using format specifier options


The syntax template for a format specifier given above provides for several options. These options allow the programmer to control precisely how output will appear on the screen. The syntax template appears again here for easy reference: %[flags][width][.precision]type_character Again, the order of the options is just as important as the order of arguments to the printf function. In other words, if you want to use multiple options, they must appear in the same order as they do in the syntax template. Field width specifiers Although the first option is flags, it is actually the least common, so we will leave its discussion for last. The width option is the option you will use most frequently. This option is often called a field width. We usually use field widths to line up columns of data to form tables on the screen. Printing things in tables makes output more readable. We can also use field widths for other reasons as well. Since they allow us to control exactly where a value will appear on a line of the screen, we can also use field widths when we want to "draw" with characters. The value that the format specifier indicates is sometimes called a "field" so the field width controls how many columns the field will occupy on the screen. The value that we substitute for the italicized width in an actual format specifier can be one of two things. Most often, it will be an integer. For example, assume that your program contains a declaration for a character variable as follows: c h a rd i g i t=' 2 ' ; If the body of the code contains the following statement: p r i n t f( " % 3 c \ n " ,d i g i t ) ; what printf will display is: | 2

Notice that two blank spaces precede the digit '2'; this means the entire field (two blanks and one non-blank character) occupies three columns. In addition, notice that the blanks come before the digit. We call this right justification. Right justification implies that items on a single row of the screen will line up along the right margin. Thusm if we immediately make another call to printf as follows: p r i n t f( " % 3 c \ n " ,d i g i t + 1 ) ; the screen will look like this: 2 3

The field width you specify is the minimum number of columns that output will occupy. If a complete representation of a value requires more columns, printf will print the whole value, overriding the field width. For example, consider the following call to printf: p r i n t f( " % 3 f \ n " ,1 4 . 5 ) ; The field width specifier in this call is 3, but the value, 14.5 actually requires four columns (the decimal point requires a column as well as the digits. In this case, the display will be: 1 4 . 5 |

If we alter the call: p r i n t f( " % 3 f \ n % 3 f " ,1 4 . 5 ,3 . 2 ) ; printf writes: 1 4 . 5 3 . 2 |

Notice that because the field width was too small, the right justification fails; the two numbers do not line up along the right hand margin. A field width that requires fewer columns than the actual data value requires will always result in this failure. You may be wondering at this point how justification allows us to print tables. So far, we have only put one value on each line, but if we print several values before each newline, we can use field widths to force them to line up. Consider the following series of printf statements: p r i n t f( " % 1 0 s % 1 0 s \ n " ," m o n t h " ," d a y " ) ; p r i n t f( " % 1 0 d % 1 0 d \ n " ,1 ,1 0 ) ; p r i n t f( " % 1 0 d % 1 0 d \ n " ,1 2 ,2 ) ; What appears on the screen when these statements executes is a table: m o n t h 1 1 2 d a y 1 0 2

Notice in particular that the field widths always start from the last column printed. At the beginning, the cursor is in the extreme upper left corner of the screen. The format string in the first printf statement specifies that the function should print the string "month" using 10 columns. Since "month" only requires 5 columns, printf precedes the string with five blanks. At this point, the cursor will be in the eleventh column. The next format specifier requires printf to write the string "day", also using 10 columns. The string "day" takes up three columns, so printf must precede it with seven blanks, starting from the current cursor position. In other words, the column count begins just after the last letter of the string "month".

In a situation like this, where we are printing only constants, we could simply embed the blanks in the format string and not bother with format specifiers or additional arguments. The sequence of statements: p r i n t f( " p r i n t f( " p r i n t f( " m o n t h 1 1 2 d a y \ n " ) ; 1 0 \ n " ) ; 2 \ n " ) ;

would produce exactly the same output. In most situations, however, the additional arguments will be variables. As such, we cannot necessarily determine what values they will hold when the program executes. In particular, when we have numeric variables, we will not be able to predict whether the value of the variable will be a onedigit number or a 4-digit number. Only by using field widths can we guarantee that the columns will line up correctly. Occasionally, when we write a program, we cannot even predict how large a field width we will need when a program executes. This implies that the field width itself needs to be a variable, for which the program will compute a value. Although it is rare for this situation to arise, it is worth mentioning how you can accomplish this. Just as was the case when we wanted to print the value of a variable, if we try to use a variable's name as a field width specifier, printf will simply print the name to the screen. For example, assume that you have declared an integer variable named width and have somehow computed a value for it. The call: p r i n t f( " % w i d t h d \ n " ,1 0 ) ; will print: % w i d t h d |

To solve this problem, C uses an asterisk in the position of the field width specifier to indicate to printf that it will find the variable that contains the value of the field width as an additional parameter. For instance, assume that the current value of width is 5. The statement: p r i n t f( " % * d % * d \ n " ,w i d t h ,1 0 ,w i d t h ,1 2 ) ; will print: | 1 0 1 2

Notice that the order of the additional parameters is exactly the same as the order of the specifiers in the format string, and that even though we use the same value (width) twice as a field width, it must appear twice in the parameter list. Precision specifiers Precision specifiers are most common with floating point numbers. We use them, as you might expect from the name, to indicate how many digits of precision we want to print. Compilers have a default precision for floating

point numbers. The help facility or user's manual for your compiler will tell you what this default is, although you can also determine its value by simply printing a floating point number with a %f format specifier and counting how many digits there are after the decimal point. Quite often, we want to control this precision. A common example would be printing floating point numbers that represent monetary amounts. In this case, we will typically want just two digits after the decimal point. You can see from the syntax template that a period must precede the precision specifier. The period really is a syntactic device to help the compiler recognize a precision specifier when no field width exists, but the choice of a period serves to help remind the programmer that it represents the number of places after a decimal point in a floating point number. Just as for the field width specifier, the programmer may use a number or an asterisk as a precision specifier. The asterisk again indicates that the actual value of the precision specifier will be one of the additional parameters to the printf call. For example, p r i n t f( " % . 2 f \ n " ,3 . 6 7 5 ) ; will print: 3 . 6 8 |

Notice that printf rounds the number when a precision specifier requires that some digits must not appear. p r i n t f( " % . * f \ n " ,w i d t h ,1 0 . 4 ) ; assuming that the current value of width is 3, will print: 1 0 . 4 0 0 |

Precision specifiers have no effect when used with the %c format specifier. They do have an effect when printing integers or strings, however. When you use a precision specifier with integer data, one of two things may happen. If the precision specifier is smaller than the number of digits in the value, printf ignores the precision specifier. Thus, p r i n t f( " % . 1 d \ n " ,2 0 ) ; will print the entire number, "20". Here, the precision specifier is less than the number of digits in the value. On the other hand, if the precision specifier is larger than the number of digits in the value, printf will "pad" the number with leading zeros: p r i n t f( " % . 4 d \ n " ,2 0 ) ; will print "0020". With string data, the precision specifier actually dictates the maximum field width. In other words, a programmer can use a precision specifier to force a string to occupy at most a given number of columns. For instance, p r i n t f( " % . 5 s \ n " ," h e l l ow o r l d " ) ; will print only "hello" (the first five characters). It is fairly rare to use precision specifiers in this fashion, but one situation in which it can be useful is when you need to print a table where one column is a string that may exceed the field width. In this case, you may wish to truncate the long string, rather than allow it to destroy the justification of the columns. Generally, when this happens, you will use both a field width specifier and a precision

specifier, thus defining both the maximum and minimum number of columns that the string must occupy. Thus, if name is a variable that contains a string, p r i n t f( " % 1 0 . 1 0 s \ n " ,n a m e ) ; will force printf to use exactly 10 columns to display the value of name . If the value is less than ten characters long, printf will pad with leading blanks; if the value has more than ten characters, printf will print only the first ten. Flags Flags are fairly uncommon in format specifiers and although several flag options exist, you are most likely to use only two of them. The first is a minus sign, which you will use in conjunction with a field width specifier. By default, whenever printf must pad output with blanks to make up a field width, the blanks precede the representation of the data. This results in right justification, as previously mentioned. In a few situations, you may wish to left justify data. That is, you may want values to line up along the left side, rather than the right side. In most cases, it will be best to right justify numbers and left justify strings. For instance, if you wanted to print a table of student names followed by their test scores, you would probably want the table to appear as follows:
M a r yJ o n e s S a mS m i t h J o h nC o o k 8 9 1 0 0 7 8

The names are lined up along the left, while the scores are lined up along the right. To print a single line of this table, your format string might look as follows:
" % 1 5 . 1 5 s % 4 d "

The minus sign indicates left justification for the name, which must occupy exactly 15 columns. The %4d format specifier tells printf to right justify the score and to have it occupy four columns. Since we can assume that no score will actually be larger than a three digit number, specifying a field width of four ensures that we will have a blank space between the name and the score. The other flag that you may want to use is a plus sign. This flag is only meaningful with numeric data. By default, when printf displays a number, it prints a minus sign for negative numbers, but it does not print a plus sign for positive numbers. If you want the plus sign to appear, this flag will cause printf to display it. Thus, p r i n t f( " % + . 3 f " ,2 . 5 ) ; will print "+2.500".

Anda mungkin juga menyukai