It is tempting but incorrect to think that a pointer to an integer is the same kind of object as a pointer to a floating point object or any other type for that matter. This is not necessarily the case. Compilers distinguish between pointers to different kinds of objects. There are occasions however when it is actually necessary to convert one kind of pointer into another. This might happen with a type of variable called "unions" or even functions which allocate storage for special uses. These objects are met later on in this book. When this situation comes about, the cast operator has to be used to make sure that pointers have compatible types when they are assigned to one another. The cast operator for variables, See The Cast Operator, is written in front of a variable to force it to be a particular type: (type) variable
For pointers it is: (type *) pointer
Look at the following statement: char *ch; int *i; i = (int *) ch;
This copies the value of the pointer ch to the pointer i. The cast operator makes sure that the pointers are in step and not talking at cross purposes. The reason that pointers have to be `cast' into shape is a bit subtle and depends upon particular computers. In practice it may not actually do anything, but it is a necessary part of the syntax of C.
Pointer casting is discussed in greater detail in the chapter on Structures and Unions.
Node:Function pointers, Next:Calling functions by pointer, Previous:Types Casts and Pointers, Up:Pointers
Pointers to functions
This section is somewhat outside of the main development of the book. You might want to omit it on first reading.
Let's now consider pointers to functions as opposed to variables. This is an advanced feature which should be used with more than a little care. The idea behind pointers to functions is that you can pass a function as a parameter to another function! This seems like a bizarre notion at first but in fact it makes perfect sense.
Pointers to functions enable you to tell any function which sub-ordinate function it should use to do its job. That means that you can plug in a new function in place of an old one just by passing a different parameter value to the function. You do not have to rewrite any code. In machine code circles this is sometimes called indirection or vectoring.
When we come to look at arrays, we'll find that a pointer to the start of an array can be found by using the name of the array itself without the square brackets []. For functions, the name of the function without the round brackets works as a pointer to the start of the function, as long as the compiler understands that the name represents the function and not a variable with the same name. So--to pass a function as a parameter to another function you would write function1(function2);
If you try this as it stands, a stream of compilation errors will be the result. The reason is that you must declare function2() explicitly like this: int function2();
If the function returns a different type then clearly the declaration will be different but the form will be the same. The declaration can be placed together with other declarations. It is not important whether the variable is declared locally or globally, since a function is a global object regardless. What is important is that we declare specifically a pointer to a function which returns a type (even if it is void). The function which accepts a function pointer as an argument looks like this: function1 (a) int (*a)(); { int i; i = (*a)(parameters); }
This declares the formal parameter a to be a pointer to a function returning a value of type int. Similarly if you want to declare a pointer to a function to a general type typename with the name fnptr, you would do it like this: typename (*fnptr)();
Node:Calling functions by pointer, Next:Questions 13, Previous:Function pointers, Up:Pointers
Calling a function by pointer
Given a pointer to a function how do we call the function? The syntax is this: variable = (*fnptr)(parameters);
An example let us look at a function which takes an integer and returns a character. int i; char ch, function();
Normally this function is called using the statement: ch = function(i);
but we can also do the same thing with a pointer to the function. First define char function(); char (*fnptr)(); fnptr = function;
then call the function with ch = (*fnptr)(i);
A pointer to a function can be used to provide a kind of plug-in interface to a logical device, i.e. a way of choosing the right function for the job. void printer(),textscreen(),windows(); switch (choice) { case 1: fnptr = printer; break; case 2: fnptr = textscreen; break; case 3: fnptr = windows; } Output(data,fnptr);
This is the basis of `polymorphism' found in object oriented languages: a choice of a logical (virtual) function based on some abstract label (the choice). The C++ language provides an abstract form of this with a more advanced syntax, but this is the essence of virtual function methods in object oriented languages.
BEWARE! A pointer to a function is an automatic local variable. Local variables are never initialized by the compiler in C. If you inadvertently forget to initialize the pointer to a function, you will come quickly to grief. Make sure that your pointers are assigned before you use them!
Node:Questions 13, Previous:Calling functions by pointer, Up:Pointers
Questions
What is a pointer?
How is a variable declared to be a pointer?
What data types can pointers "point to"?
Write a statement which converts a pointer to a character into a pointer to a double type. (This is not as pointless as it seems. It is useful in dealing with unions and memory allocation functions.)
Why is it incorrect to declare: float *number = 2.65; ?
Node:Standard Output and Standard Input, Next:Assignments Expressions and Operators, Previous:Pointers, Up:Top
Standard Output and Standard Input
Talking to the user.
Getting information in and out of a computer is the most important thing that a program can do. Without input and output computers would be quite useless.
C treats all its output as though it were reading or writing to different files. A file is really just an abtraction: a place where information comes from or can be sent to. Some files can only be read, some can only be written to, others can be both read from and written to. In other situations files are called I/O streams.
C has three files (also called streams) which are always open and ready for use. They are called stdin, stdout and stderr, meaning standard input and standard output and standard error file. Stdin is the input which usually arrives from the keyboard of a computer. stdout is usually the screen. stderr is the route by which all error messages pass: usually the screen. This is only `usually' because the situation can be altered. In fact what happens is that these files are just handed over to the local operating system to deal with and it chooses what to do with them. Usually this means the keyboard and the screen, but it can also be redirected to a printer or to a disk file or to a modem etc.. depending upon how the user ran the program.
The keyboard and screen are referred to as the standard input/output files because this is what most people use, most of the time. Also the programmer never has to open or close these, because C does it automatically. The C library functions covered by stdio.h provides some methods for working with stdin and stdout. They are simplified versions of the functions that can be used on any kind of file, See Files and Devices. In order of importance, they are: printf () scanf () getchar() putchar() gets () puts ()
printf again:
Example 9:
Output 9:
Formatting with printf:
Example 10:
Output 10:
Special Control Characters again:
Questions 15:
scanf:
Conversion characters:
How does scanf see the input:
First account of scanf:
The dangerous function:
Keeping scanf under control:
Example 11:
Matching without assigning:
Formal Definition of scanf:
Summary of points about scanf:
Questions 15b:
Low Level Input/Output:
Questions 15c:
Node:printf again, Next:Example 9, Previous:Standard Output and Standard Input, Up:Standard Output and Standard Input
printf
The printf function has been used widely up to now for output because it provides a neat and easy way of printing text and numbers to stdout (the screen). Its name is meant to signify formatted printing because it gives the user control over how text and numerical data are to be laid out on the screen. Making text look good on screen is important in programming. C makes this easy by allowing you to decide how the text will be printed in the available space. The printf function has general form: printf ("string...",variables,numbers)
It contains a string (which is not optional) and it contains any number of parameters to follow: one for each blank field in the string.
The blank fields are control sequences which one can put into the string to be filled in with numbers or the contents of variables before the final result is printed out. These fields are introduced by using a % character, followed by some coded information, which says something about the size of the blank space and the type of number or string which will be filled into that space. Often the string is called the control string because it contains these control characters.
The simplest use of printf is to just print out a string with no blank fields to be filled: printf ("A pretty ordinary string.."); printf ("Testing 1,2,3...");
The next simplest case that has been used before now is to print out a single integer number: int number = 42; printf ("%d",number);
The two can be combined: int number = 42; printf ("Some number = %d",number);
The result of this last example is to print out the following on the screen: Some number = 42
The text cursor is left pointing to the character just after the 2. Notice the way that %d is swapped for the number 42. %d defines a field which is filled in with the value of the variable.
There are other kinds of data than integers though. Any kind of variable can be printed out with printf. %d is called a conversion character for integers because it tells the compiler to treat the variable to be filled into it as an integer. So it better had be an integer or things will go wrong! Other characters are used for other kinds of data. Here is a list if the different letters for printf.
d
signed denary integer
u
unsigned denary integer
x
hexadecimal integer
o
octal integer
s
string
c
single character
f
fixed decimal floating point
e
scientific notation floating point
g
use f or e, whichever is shorter
The best way to learn these is to experiment with different conversion characters. The example program and its output below give some impression of how they work:
Node:Example 9, Next:Output 9, Previous:printf again, Up:Standard Output and Standard Input
Example Listing/*******************************************************//* *//* printf Conversion Characters and Types *//* *//*******************************************************/ #include
Node:Output 9, Next:Formatting with printf, Previous:Example 9, Up:Standard Output and Standard Input
Outputsigned integer -10unsigned integer 10This is wrong! 10See what happens when you get the character wrong!Hexadecimal FFFFFFF6 AOctal 37777777766 12Float and double 3.560000 3.520000 ditto 3.560000E+00 3.520000E+00 ditto 3.560000 3.520000single character zwhole string -> any old string
Node:Formatting with printf, Next:Example 10, Previous:Output 9, Up:Standard Output and Standard Input
Formatting with printf
The example program above does not produce a very neat layout on the screen. The conversion specifiers in the printf string can be extended to give more information. The % and the character type act like brackets around the extra information. e.g. %-10.3f
is an extended version of %f, which carries some more information. That extra information takes the form: % [-] [fwidth] [.p] X
where the each bracket is used to denote that the item is optional and the symbols inside them stand for the following.
[fwidth]
This is a number which specifies the field width of this "blank field". In other words, how wide a space will be made in the string for the object concerned? In fact it is the minimum field width because if data need more room than is written here they will spill out of their box of fixed size. If the size is bigger than the object to be printed, the rest of the field will be filled out with spaces.
[-]
If this included the output will be left justified. This means it will be aligned with the left hand margin of the field created with [fwidth]. Normally all numbers are right justified, or aligned with the right hand margin of the field "box".
[.p]
This has different meanings depending on the object which is to be printed. For a floating point type (float or double) p specifies the number of decimal places after the point which are to be printed. For a string it specifies how many characters are to be printed.
Some valid format specifiers are written below here. %10d %2.2f %25.21s %2.6f
The table below helps to show the effect of changing these format controls. The width of a field is draw in by using the bars. Object to Control Spec. Actual Outputbe printed 42 %6d 4242 %-6d 42 324 %10d 324-1 %-10d -1 -1 %1d -1(overspill) 'z' %3c z'z' %-3c z 2.71828 %10f 2.718282.71828 %10.2f 2.712.71828 %-10.2f 2.71 2.71828 %2.4f 2.7182(overspill)2.718 %.4f 2.71802.718 %10.5f 2.71800 2.71828 %10e 2.71828e+002.71828 %10.2e 2.17e+002.71828 %10.2g 2.71 "printf" %s printf"printf" %10s printf"printf" %2s printf(overspill)"printf" %5.3s pri"printf" %-5.3s pri "printf" %.3s pri
Node:Example 10, Next:Output 10, Previous:Formatting with printf, Up:Standard Output and Standard Input
Example Listing/***********************************************//* *//* Multiplication Table *//* *//***********************************************/ #include
Node:Output 10, Next:Special Control Characters again, Previous:Example 10, Up:Standard Output and Standard Input
Output 1 2 3 4 5 6 7 8 9 10 2 4 6 8 10 12 14 16 18 20 3 6 9 12 15 18 21 24 27 30 4 8 12 16 20 24 28 32 36 40 5 10 15 20 25 30 35 40 45 50 6 12 18 24 30 36 42 48 54 60 7 14 21 28 35 42 49 56 63 70 8 16 24 32 40 48 56 64 72 80 9 18 27 36 45 54 63 72 81 90 10 20 30 40 50 60 70 80 90 100
Node:Special Control Characters again, Next:Questions 15, Previous:Output 10, Up:Standard Output and Standard Input
Special Control Characters
Control characters are invisible on the screen. They have special purposes usually to do with cursor movement. They are written into an ordinary string by typing a backslash character \ followed by some other character. These characters are listed below.
\b
backspace BS
\f
form feed FF (also clear screen)
\n
new line NL (like pressing return)
\r
carriage return CR (cursor to start of line)
\t
horizontal tab HT
\v
vertical tab
\"
double quote
\'
single quote character '
\\
backslash character \
\ddd
character ddd where ddd is an ASCII code given in octal or base 8, See Character Conversion Table.
\xddd
character ddd where ddd is an ASCII code given in hexadecimal or base 16, See Character Conversion Table.
Node:Questions 15, Next:scanf, Previous:Special Control Characters again, Up:Standard Output and Standard Input
Questions
Write a program which simply prints out: 6.23e+00
Investigate what happens when you type the wrong conversion specifier in a program. e.g. try printing an integer with %f or a floating point number with %c. This is bound to go wrong - but how will it go wrong?
What is wrong with the following statements?
printf (x);
printf ("%d");
printf ();
printf ("Number = %d");
Hint: if you don't know, try them in a program!
Node:scanf, Next:Conversion characters, Previous:Questions 15, Up:Standard Output and Standard Input
scanf
scanf is the input function which gets formatted input from the file stdin (the keyboard). This is a very versatile function but it is also very easy to go wrong with. In fact it is probably the most difficult to understand of all the C standard library functions.
Remember that C treats its keyboard input as a file. This makes quite a difference to the way that scanf works. The actual mechanics of scanf are very similar to those of printf in reverse scanf ("string...",pointers);
with one important exception: namely that it is not variables which are listed after the control string, but pointers to variables. Here are some valid uses of scanf: int i;char ch;float x; scanf ("%d %c %f", &i, &ch, &x);
Notice the & characters which make the arguments pointers. Also notice the conversion specifiers which tell scanf what types of data it is going to read. The other possibility is that a program might already have pointers to a particular set of variables in that case the & is not needed. For instance: function (i,ch,x) int *i;char *ch;float *x; {scanf ("%d %c %f", i, ch, x);}
In this case it would actually be wrong to write the ampersand & symbol.
Node:Conversion characters, Next:How does scanf see the input, Previous:scanf, Up:Standard Output and Standard Input
Conversion characters
The conversion characters for scanf are not identical to those for printf and it is much more important to be precise and totally correct with these than it is with printf.
d
denary integer (int or long int)
ld
long decimal integer
x
hexadecimal integer
o
octal integer
h
short integer
f
float type
lf
long float or double
e
float type
le
double
c
single character
s
character string
The difference between short integer and long integer can make or break a program. If it is found that a program's input seems to be behaving strangely, check these carefully. (See the section on Errors and Debugging for more about this.)
Node:How does scanf see the input, Next:First account of scanf, Previous:Conversion characters, Up:Standard Output and Standard Input
How does scanf see the input?
When scanf is called in a program it checks to see what is in the input file, that is, it checks to see what the user has typed in at the keyboard. Keyboard input is usually buffered. This means that the characters are held in a kind of waiting bay in the memory until they are read. The buffer can be thought of as a part of the input file stdin, holding some characters which can be scanned though. If the buffer has some characters in it, scanf will start to look through these; if not, it will wait for some characters to be put into the buffer.
There is an important point here: although scanf will start scanning through characters as soon as they are in the buffer, the operating system often sees to it that scanf doesn't get to know about any of the characters until the user has pressed the RETURN or ENTER key on the computer or terminal. If the buffer is empty scanf will wait for some characters to be put into it.
To understand how scanf works, it is useful to think of the input as coming in `lines'. A line is a bunch of characters ending in a newline character \n. This can be represented by a box like the one below: -------------------------------------- some...chars.738/. '\n' --------------------------------------
As far as scanf is concerned, the input is entirely made out of a stream of characters. If the programmer says that an integer is to be expected by using the %d conversion specifier then scanf will try to make sense of the characters as an integer. In other words, it will look for some characters which make up a valid integer, such as a group of numbers all between 0 and 9. If the user says that floating point type is expected then it will look for a number which may or may not have a decimal point in it. If the user just wants a character then any character will do!
Node:First account of scanf, Next:The dangerous function, Previous:How does scanf see the input, Up:Standard Output and Standard Input
First account of scanf
Consider the example which was give above. int i;char ch;float x; scanf ("%d %c %f", &i, &ch, &x);
Here is a simplified, ideal view of what happens. scanf looks at the control string and finds that the first conversion specifier is %d which means an integer. It then tries to find some characters which fit the description of an integer in the input file. It skips over any white space characters (spaces, newlines) which do not constitute a valid integer until it matches one. Once it has matched the integer and placed its value in the variable i it carries on and looks at the next conversion specifier %c which means a character. It takes the next character and places it in ch. Finally it looks at the last conversion specifier %f which means a floating point number and finds some characters which fit the description of a floating point number. It passes the value onto the variable x and then quits.
This brief account of scanf does not tell the whole story by a long way. It assumes that all the characters were successfully found and that everything went smoothly: something which seldom happens in practice!
Node:The dangerous function, Next:Keeping scanf under control, Previous:First account of scanf, Up:Standard Output and Standard Input
The dangerous function
What happens if scanf doesn't find an integer or a float type? The answer is that it will quit at the first item it fails to match, leaving that character and the rest of the input line still to be read in the file. At the first character it meets which does not fit in with the conversion string's interpretation scanf aborts and control passes to the next C statement. This is why scanf is a `dangerous' function: because it can quit in the middle of a task and leave a lot of surplus data around in the input file. These surplus data simply wait in the input file until the next scanf is brought into operation, where they can also cause it to quit. It is not safe, therefore, to use scanf by itself: without some check that it is working successfully.
scanf is also dangerous for the opposite reason: what happens if scanf doesn't use up all the characters in the input line before it satisfies its needs? Again the answer is that it quits and leaves the extra characters in the input file stdin for the next scanf to read, exactly where it left off. So if the program was meant to read data from the input and couldn't, it leaves a mess for something else to trip over. scanf can get out of step with its input if the user types something even slightly out of line. It should be used with caution...
0 comments: on " "
Post a Comment