Distinguish function pointer and pointer function _.
There are a lot of complaints about the constantly changing handling of pointers and arrays, but it should be clear now. With the foundation of the previous lecture, the content of this lecture is relatively easy to understand.
1. pointer to the function (function pointer)
To analyze such a declaration, void (* f) (); although the priority of () is higher than *, because of the existence of parentheses, the first action is to unreference, therefore, f is a pointer. The next execution () indicates that f points to a function, and this function does not return any value. Now we can conclude that f is a pointer to a function that does not accept parameters and does not return any value. It is short for pointer to function ).
In comparison, int (* p) [100], p is a pointer to an array containing 100 integer elements. They share a common feature: pointer Declaration (*) and identifier (f or p) are restricted in a bracket. Because the priority of the brackets is the highest, we can get the above results from the identifier analysis from the inside out.
<1>. Initialization
Note that the pointer to a function points to a function rather than a common variable, and the function to which it points also has a specific type, the type of a function is determined by the type of its return value and the list of parameters, and is irrelevant to the function name. You can use a function name or a function pointer of the same type during function pointer initialization (of course, there are also zero pointer constants ). Assume that there are void test (), int wrong_match (int) and function pointer void (* ptf )().
The following Initialization is incorrect because the function pointer type does not match the function type:
F = wrong_match;
F = & wrong_match;
Ptf = wrong_match;
Ptf = & wrong_match;
The following initialization and assignment are valid:
F = test;
F = & test;
Ptf = test;
Ptf = & test;
F = pf;
It should be explained that both test and & test can be used to initialize function pointers.C language requires that the function name will be converted to a pointer to this function, unless this function name is used as the operand of the & or sizeof operator (Note: The function name used for the sizeof operator is invalid ).That is to say, test in f = test; is automatically converted to & test, and f = & test; has been shown to use & test, so test will not be converted again. Therefore, directly referencing a function name is equivalent to applying the & operator to the function name. Both methods get a pointer to the function.
<2>. Call a function using a function pointer
You can call a function using a function pointer in either of the following ways:
F = test;
Ptf = test;
F ();
(* F) (); // parentheses on both sides of the pointer are very important, indicating that f is first referenced and then the corresponding function is called.
Ptf ();
(* Ptf) (); // no fewer parentheses
The preceding statements can call the test function. The ansi c standard regards f () as the abbreviated form of (* f) () and recommends f () because it is more in line with the logic of function calls.Note: If the pointer to the function is not initialized or has0 (zero pointer constant), the pointer cannot be used in function calls. A pointer can be safely used to call a function only when it is initialized or pointed to a function after being assigned a value.
<3>. Explore function name
The following program is available:
# Include <stdio. h>
Voidtest ()
{
Printf ("test called! /N ");
}
Int main ()
{
Void (* f )();
F = test;
F ();
(* F )();
// Test ++ ;//Error, The standard prohibits auto-increment operations on pointers to Functions
// Test = test + 2 ;//ErrorFunction names cannot be assigned values or used for arithmetic operations.
Printf ("% p/n", test );
Printf ("% p/n", & test );
Printf ("% p/n", * test );
Return 0;
}
The running result on my machine is:
Test called!
Test called!
004013EE
004013EE
004013EE
What is hard to understand in this program is that all three output statements can obtain the function entry address. First, let's look at the function name test, which is similar to the array name (Note: It's just similar). It is a symbol used to identify the entry address of a function, when using the function, the number of letters will be converted to the pointer pointing to this function. The pointer value is the entry address of the function. & test has previously stated that the address for obtaining the function is displayed. For * test, we can think that because test has been converted into a function pointer and points to this function, * test is the name of the function pointed to by this pointer, according to the rule that the function name will be converted to the pointer to the function, this function is also converted into a pointer, so * test is eventually a pointer to the function test. If they are output in % p format, the entry address of the test function expressed in hexadecimal notation is obtained. Note that the function address is unknown during the compilation period, but is determined at the link.
2. Return pointer function (pointer function)
By analogy with pointer arrays (remember), it is easier to understand pointer functions. The so-called pointer function is a function that returns a pointer. A function can return either an integer value, a real value, or a pointer value without returning any value. Declaration of a pointer function: int * f (int I, int j); recall the declaration of the pointer array: char * cars [10]; similarly, it is written as an easy-to-understand (not industry-standard) int * f (int I, int j). This makes it very clear that () has a higher priority *, therefore, f is first combined with (), so f is a function with two int parameters and returns a pointer to the int type.
Many library functions in C language are pointer functions, such as string processing functions. Below are some function prototypes:
Char * strcat (char * dest, const char * src );
Char * strcpy (char * dest, const char * src );
Char * strchr (const char * s, int c );
Char * strstr (const char * src, const char * sub );
Note that the return value of a function is not only a pointer to a variable, but also a pointer to a function. The declaration of such a function may be a little painful, but it should be understandable and mastered to practice two or three times. First, let's look at the Declaration: int (* function (int) (double *, char); to understand the meaning of this Declaration, first let's look at function (int ), declare a function as a function with an int-type formal parameter. The return value of this function is a pointer, which is exactly the function pointer int (*) We will talk about at the beginning (*) (double *, char); this pointer points to a function. This function returns the int type with two parameters, double * and char. If typedef is used, this statement can be simplified:
Typedef int (* ptf) (double *, char );
Ptf function (int );
Note that for typedef int (* ptf) (double *, char), do not use # define to view typedef, if you think of # define, you will think that (* ptf) (double *, char) is the alias of int, but such an alias does not seem to be a legal name, as a result, you will be confused. In fact, the above statement defines ptf as an alias of the function pointer type. It is equivalent to int (*) (double *, char) of the function pointer type, that is to say, ptf is also a type.
3. Mixed Use of function pointers and pointer Functions
A function pointer can be used not only as a return value type, but also as a function form parameter. If both the form parameter and return value of a function are function pointers, this statement looks more complex, for example:
Void (* signal (int sig, void (* func) (intsiga) (int siga); it looks annoying. Let's analyze it step by step. Now we need to analyze signal. Because signal is closely related to the brackets with the highest priority, it is first combined with parentheses. Therefore, signal is a function with two parameters in the brackets: signal, one is int type and the other is a pointer to the function. Next, from the left-side view, * indicates the pointer to an object, and its position indicates that it is of the signal return value type. Now we can remove the signal that has been analyzed and obtain void (*) (int siga). It's clear. It is also a function pointer, which is the same as the second parameter type in the signal form parameter table. It is a pointer to a function that accepts an int-type parameter and does not return any value. Similarly, typedef can simplify this statement:
Typedef void (* p_sig) (int );
P_sig signal (int sig, p_sig func );
This signal function is a library function in C language, in signal. h is a function commonly used in UNIX/Linux programming to process signals generated in the system. Therefore, I will explain it here separately.
4. function pointer Array
Another common usage of function pointers is function pointer array. Assume that there is a file processing program, and you can use a menu button to select the corresponding operations (open the file, read the file, write the file, and close the file ). These operations are implemented as functions with the same type, respectively:
Void open ();
Void read ();
Void write ();
Void close ();
Now define the alias PF: typedefvoid (* PF) () for a function pointer type. Put the above four operation addresses into an array and get:
PF file_options [] = {
& Open,
& Read,
& Write,
& Close
};
The elements in this array are pointers to functions that do not accept parameters and do not return any values. Therefore, this is a function pointer array. Next, define a pointer action of the function pointer type and initialize it as the first element of the array of the function pointer: PF * action = file_options; if it is hard to understand, it can be compared to int ia [4] = {0, 1, 2, 3}; int * ip = ia;. Here PF is equivalent to int, which should be better understood. By performing the subscript operation on the pointer action, you can call any operation in the array, for example, action [2] () will call the write operation, and so on. In practice, pointer actions can be associated with the mouse or other GUI objects for the purpose.
5. Complex statements about pointers
The array of function pointers in point 4th adopts typedef for declaration, which should be promoted because it is more readable. If typedef is not used, the analysis will be complicated and the result will be void (* file_options []) (). I don't want to talk too much about complicated statements in C language, because there are not many opportunities to use in practice, and we recommend that you use typedef to simplify the complexity of the statement. There is an extremely effective method for analyzing complex statements-the right left rule. The general description of the right-left rule is: Read the declaration from the undefined variable name, first look to the right, and then look to the left. In case of parentheses, the reading direction is adjusted. After all the content in the brackets is analyzed, the brackets are displayed. This continues until the entire statement is analyzed. To analyze an example: int * (* fp) (int) [10];
Reading steps:
1. Read from undefined variable names ------------------------------------------------ fp
2. If you look to the right, there is nothing, and you encounter it), you will see a * ------ A pointer pointing to an object.
3. Jump out of brackets and encounter (int) ------------------------------------- a function with an int parameter.
4. Look left and find a * ------------------------------------------- (function) that returns a pointer to an object.
5. Jump out of brackets and look to the right. [10] ------------------------------ an array of 10 elements
6. Look left and find a * --------------------------------------------------- pointer to an object.
7. Look left and find int --------------------------------------------------- int type
Therefore, fp is a pointer to a function. This function returns a pointer to an array, which has 10 int * elements.
I will not give more examples for this. The following are some statements. If you are interested, try to analyze them. The answer will be given in the next lecture:
1. int * (* a [5]) ();
2. void * (* B) (char, int (*)());
3. float (* c [10]) (int *) [5];
4. int (* d) [2] [3]) [4] [5];
5. int (* e) (int *) [15]) (int *);
6. int (* f [4] [5] [6]) (int *) [10];
7. int * (* g) () [10]) ();