آوزش زبان c قسمت 7:
frequently really are standard on all implementations. In particular the I/O functions vary very little.
It is now time to look at exactly how scanf and printf work and what they can do - you might be surprised at just how complex they really are!
The original C specification did not include commands for input and output. Instead the compiler writers were supposed to implement library functions to suit their machines. In practice all chose to implement printf and scanf and after a while C programmers started to think of them as if these functions were I/O keywords! It sometimes helps to remember that they are functions on a par with any other functions you may care to define. If you want to you can provide your own implementations of printf or scanf or any of the other standard functions - we'll discover how later.
The printf (and scanf) functions do differ from the sort of functions that you will created for yourself in that they can take a variable number of parameters. In the case of printf the first parameter is always a string (c.f. "Hello World") but after that you can include as many parameters of any type that you want to. That is, the printf function is usually of the form:
printf(string,variable,variable,variable...)
where the ... means you can carry on writing a list of variables separated by commas as long as you want to. The string is all-important because it specifies the type of each variable in the list and how you want it printed. The string is usually called the control string or the format string. The way that this works is that printf scans the string from left to right and prints on the screen, or any suitable output device, any characters it encounters - except when it reaches a % character. The % character is a signal that what follows it is a specification for how the next variable in the list of variables should be printed. printf uses this information to convert and format the value that was passed to the function by the variable and then moves on to process the rest of the control string and anymore variables it might specify. For example:
printf("Hello World");
only has a control string and, as this contains no % characters it results in Hello World being displayed and doesn't need to display any variable values. The specifier %d means convert the next value to a signed decimal integer and so:
printf("Total = %d",total);
will print Total = and then the value passed by >total as a decimal integer.
If you are familiar other programming languages then you may feel happy about the printf function because something like:
printf("Total = %d",total);
looks like the sort of output command you might have used before. For example, in BASIC you would write:
PRINT "Total = ",total
but the C view of output is at a lower level than you might expect. The %d isn't just a format specifier, it is a conversion specifier. It indicates the data type of the variable to be printed and how that data type should be converted to the characters that appear on the screen. That is %d says that the next value to be printed is a signed integer value (i.e. a value that would be stored in a standard int variable) and this should be converted into a sequence of characters (i.e. digits) representing the value in decimal. If by some accident the variable that you are trying to display happens to be a float or a double then you will still see a value displayed - but it will not correspond to the actual value of the float or double.
The reason for this is twofold.
-
The first difference is that an int uses two bytes to store its value, while a float uses four and a double uses eight. If you try to display a float or a double using %d then only the first two bytes of the value are actually used.
-
The second problem is that even if there wasn't a size difference ints, floats and doubles use a different binary representation and %d expects the bit pattern to be a simple signed binary integer.
This is all a bit technical, but that's in the nature of C. You can ignore these details as long as you remember two important facts:
-
The specifier following % indicates the type of variable to be displayed as well as the format in which that the value should be displayed;
-
If you use a specifier with the wrong type of variable then you will see some strange things on the screen and the error often propagates to other items in the printf list.
If this seems complicated then I would agree but I should also point out that the benefit is being able to treat what is stored in a variable in a more flexible way than other languages allow. Other languages never let on to the programmer that what is in fact stored in a variable is a bit pattern, not the decimal value that appears to be stored there when you use a printf (or whatever) statement. Of course whether you view this as an advantage depends on what you are trying to do. It certainly brings you closer to the way the machine works.
You can also add an 'l' in front of a specifier to mean a long form of the variable type and h to indicate a short form (long and short will be covered later in this course). For example, %ld means a long integer variable (usually four bytes) and %hd means short int. Notice that there is no distinction between a four-byte float and an eight-byte double. The reason is that a float is automatically converted to a double precision value when passed to printf - so the two can be treated in the same way. (In pre-ANSI all floats were converted to double when passed to a function but this is no longer true.) The only real problem that this poses is how to print the value of a pointer? The answer is that you can use %x to see the address in hex or %o to see the address in octal. Notice that the value printed is the segment offset and not the absolute address - to understand what we am going on about you need to know something about the structure of your processor.
The % specifiers that you can use in ANSI C are:
Usual variable type Display
%c char single character
%d (%i) int signed integer
%e (%E) float or double exponential format
%f float or double signed decimal
%g (%G) float or double use %f or %e as required
%o int unsigned octal value
%p pointer address stored in pointer
%s array of char sequence of characters
%u int unsigned decimal
%x (%X) int unsigned hex value
Formatting Your Output
The type conversion specifier only does what you ask of it - it convert a given bit pattern into a sequence of characters that a human can read. If you want to format the characters then you need to know a little more about the printf function's control string.
Each specifier can be preceded by a modifier which determines how the value will be printed. The most general modifier is of the form:
flag width.precision
The flag can be any of:
flag meaning
- left justify
+ always display sign
space display space if there is no sign
0 pad with leading zeros
# use alternate form of specifier
The width specifies the number of characters used in total to display the value and precision indicates the number of characters used after the decimal point.
For example, %10.3f will display the float using ten characters with three digits after the decimal point. Notice that the ten characters includes the decimal point, and a - sign if there is one. If the value needs more space than the width specifies then the additional space is used - width specifies the smallest space that will be used to display the value. (This is quiet reassuring, you won't be the first programmer whose program takes hours to run but the output results can't be viewed because the wrong format width has been specified!)
The specifier %-1Od will display an int left justified in a ten character space. The specifier %+5d will display an int using the next five character locations and will add a + or - sign to the value.
The only complexity is the use of the # modifier. What this does depends on which type of format it is used with:
%#o adds a leading 0 to the octal value
%#x adds a leading 0x to the hex value