Have you ever come across something that puzzles you, like an int * (* (*FP1) (int)) [10]; A variable declaration like this? This article will teach you how to understand this complex, C + + declaration from easy to difficult, step-by-step.
We'll start with a simpler statement that we can run into every day, and then step into the const modifier and typedef, as well as the function pointers, and finally introduce a right-to-left rule that allows you to accurately understand any C + + declaration.
It should be emphasized that complex C/s + + declarations are not a good programming style; I'm just here to teach you how to understand these statements. Note: In order to be able to display code and related comments on the same line, this article is best read on a display with at least 1024x768 resolution.
Let's start with a very simple example, as follows:
int n;
This should be understood as "declare n as an int" (n is a variable of type int). Then take a look at the pointer variable, as follows:
int *p;
This should be understood as "declare p as an int *" (p is a variable of int *), or P is a pointer to a variable of type int. I'd like to discuss this here: I think when declaring a variable of a pointer (or reference) type, it's better to write * (or &) before the variable, rather than following the base type. This avoids some misunderstanding of understanding, such as:
Let's look at an example of a pointer pointer:
Char **argv;
Theoretically, there is no limit to the progression of pointers, you can define a pointer to a pointer pointer to a floating-point type variable, and then see the following declaration:
int rollnum[30][4];
int (*p) [4]=rollnum;
int *q[5];
Here, P is declared as a pointer to an array of 4 elements (int type), and Q is declared as an array containing 5 elements (int type). In addition, we can also mix utility * and & in the same declaration, as follows:
int **p1;
P1 is a pointer to a pointer to an int.
int *&p2;
P2 is a reference to a pointer to an int.
int &*p3;
Error:pointer to a reference is illegal.
int &&p4;
Error:reference to a Reference is illegal.
Note: P1 is a pointer to a pointer of type int; P2 is a reference to a pointer of type int; P3 is a pointer to an int type reference (illegal!). P4 is a reference to an int type reference (illegal!). )。
The const keyword may be used when you want to prevent a variable from being changed. When you add a const modifier to a variable, you usually need to initialize it, because at any later time you will not have a chance to change it. For example:
const int n=5;
int const M=10;
The two variables n and M are actually the same type--both const int (shaping constants). Because the C + + standard stipulates that the Const keyword is placed before the type or variable name is equivalent. I personally prefer the first way of declaring because it highlights the role of the Const modifier. When const is used with pointers, it is easy to confuse people. For example, let's take a look at the following p and Q declarations:
const int *p;
int const *Q;
Which one of them represents a const pointer of type INT (const directly modifies int), which represents a const pointer of type int (const direct modifier pointer)? In fact, both P and Q are declared as pointers to the const int type. The const pointer of type int should be declared like this:
int * Const r= &n;
n have been declared as an int
Here, p and Q are pointers to the const int type, which means that you cannot change the value of *p in a later program. R is a const pointer that, when declared, is initialized to the variable n (that is, r=&n;), and the value of R is no longer allowed to be changed (but the value of *r can be changed).
Combining the two const modifiers above, let's declare a const pointer to the const int type, as follows:
const INT * Const p=&n;
N has been declared as const int
Some of the statements given below about const will help you to completely clarify the usage of Const. Note, however, that some of the following declarations cannot be compiled because they need to be initialized at the same time as they are declared. For the sake of brevity, I ignored the initialization section, and each of the following declarations adds two lines of code, because of the addition of the initialization code.
Char * * P1; 
// pointer to pointer to char
const char **p2;
// pointer to pointer to const CHAR 
char * const * p3;
// pointer to const pointer to char
Const char * const * P4;&NB Sp
// Pointer to const pointer to const CHAR 
Char * * Const P5; 
//Const pointer TO&NB sp; pointer to char
Const char * * Const P6; 
/const Pointer to & nbsp; Pointer to const CHAR&NBSP,
char * const * Const P7; 
//const pointer to const pointer TO &NB sp; char
Const char * const * Const P8; 
//const pointer to const pointer to const char
Note: P1 is a pointer to a pointer to a char type, p2 is a pointer to a const char type pointer, p3 is a const pointer to a char type, P4 is a const pointer to a const char type; P5 is a const pointer to a pointer to a char type ; P6 is a const pointer to a pointer to a const char type; P7 is a const pointer to a char type const pointer; P8 is a const pointer to a const pointer to a const char type.
typedef gives you a way to overcome the drawbacks of "* only appropriate for variables and not suitable for types". You can use typedef as follows:
typedef char * PCHAR;
PCHAR p,q;
Both P and Q are declared as pointers. (If you do not use TYPEDEF,Q will be declared as a char variable, this is not quite consistent with our first glance!) Below are some declarations that use TypeDef, and give explanations:
typedef char * A;
A is a pointer to a char
typedef a B ();
B is a function that returns
A pointer to a char
typedef b *C;
c is a pointer to a function
That returns a pointer to a char
typedef c d ();
D is a function returning
A pointer to a function
That returns a pointer to a char
typedef d *e;//E is a pointer to a function
Returning a pointer to a
function that returns a
Pointer to a Char
e Var[10];
var is an array of ten pointers to
Functions returning pointers to
Functions returning pointers to chars.
typedef are often used before a struct declaration, as follows. This allows you to create struct variables without using the keyword struct (in c, the struct keyword is required when creating struct variables, such as struct tagpoint A; in C + +, structs can be ignored, such as Tagpoint b).
typedef struct TAGPOINT
... {
int x;
int y;
}point;
Point P; /**//* Valid C Code */
A function pointer may be the most confusing statement that can cause comprehension. Function pointers are used most when writing TSR programs in the DOS era, and in the Win32 and x-windows times, they are used where callback functions are needed. Of course, there are many other places that need to use function pointers: virtual function tables, some templates in STL, Win NT/2K/XP System services, and so on. Let's look at a simple example of a function pointer:
Int (*p) (char);
Here p is declared as a function pointer, which takes a char type parameter and has a return value of type int. In addition, a function pointer with two float type parameters, a pointer to a pointer of type char, can be declared as follows:
char * * (*p) (float, float);
What about a const pointer parameter with two char types and a function pointer with no return value? Refer to the following:
void * (*a[5]) (char * const, char * const);
The "right left law" is a simple rule, but it allows you to understand all the statements accurately. This rule is used as follows: Start reading the declaration from the inner parenthesis, look right, and then look left. When you touch a parenthesis, you turn the direction of reading. All the contents of the parentheses are parsed out of the range of parentheses. This continues until the entire statement has been parsed.
Make a minor correction to the right-left rule: When you first start reading the declaration, you have to start with the variable name instead of the inner parenthesis.
The following example illustrates the use of the right-left rule.
int * (* (*FP1) (int)) [10];
Read the steps:
1. Start with the variable name--FP1
2. Look to the right, nothing, bump into it, so look left, touch a *--a pointer
3. Jump out of parentheses, hit (int)--a function with an int argument
4. Looking left, a *--(function) is found to return a pointer
5. Jump out of brackets, look right, touch [10]--An array of 10 elements
6. Look left and find a *--pointer
7. Look left, find Int--int type
Summary: FP1 is declared as a pointer to a function that returns a pointer to an array of pointers.
Let's look at one more example:
int * (* (*arr[5]) ()) ();
Read the steps:
1. Start with the variable name--arr
2. Look to the right and find an array--an array of 5 elements
3. Look left and find a *--pointer
4. Jump out of brackets, look right, find ()--function without parameters
5. Look left, Touch *--(function) returns a pointer
6. Jump out of parentheses to the right to find ()--function without parameters
7. Left, find *--(function) returns a pointer
8. Continue to the left and find the Int--int type
There are a number of other examples:
Float (* (*b ()) []) ();
B is a function that returns a
Pointer to an array of pointers
to functions returning floats.
void * (*C) (char, int (*) ());
c is a pointer to a function that takes
Parameters:
A char and a pointer to a
function that takes no
Parameters and returns
an int
and returns a pointer to void.
void * * (*d) (int &, char * * (*) (char *, char * *));
D is a pointer to a function that takes
Parameters:
A reference to an int and a pointer
To a function that takes the parameters:
A pointer to a char and a pointer
To a pointer to a char
and returns a pointer to a pointer
to a Char
and returns a pointer to a pointer to void
Float (* (* e[10]) (int &)) [5];
E is an array of ten pointers to
Functions a single
reference to a int as an argument
and return pointers to
An array of 5 floats.
After dinner, after listening to the song, a little rest, the following begins to summarize the "how to understand C and C + + complex type declaration" to achieve my commitment in the "learning about pointers".
First, let's look at the statement that the pointer binds to the const:
const int *p; P is a pointer to a constant shaping
int const *P; Error
int * const P; P is a constant pointer to shaping
const int * const P; P is a constant pointer to a constant shaping.
What do you think? I hope you will not confuse, I will tell you how to understand, but write here, I suddenly think of some of the const things, here first insert an episode,-_-
I believe you have seen the use of const modifier functions when learning C + +, such as:
const int fun ();
int fun () const;
The last one is that the fun function is a constant member function (c + + Class), the fun function cannot modify the member variables and member functions in the class, which is often seen in the learning of MFC, for example: The HWND GetDlgItem (ID) const; We all know this is the right thing to do.
Back to the subject, to understand the statement clearly,
First, let's start with the declarator in the compiler (declarator), what is a declarator? Simply put, the declarator is the identifier and any pointers that are combined with it, the function brackets, the array subscript, etc. (Definitions refer to "C Expert programming"), the legal declaration has the following limitations:
1. The return value of a function cannot be a function or an array, so fun () () and Fun () [] are illegal
2, the array can not have functions, so fun[] () is illegal
Ii. Priority rules
A, the declaration starts reading from its name, and then the installation priority is read from high to low
B, priority high and low order:
B1, enclosed in parentheses in declarations.
B2, postfix operator: () indicates that the function [] represents an array
B3, prefix operator: * denotes pointing to ... The pointer
C, if const and/or volatile are immediately followed by the type (such as int, etc.), then the const and/or volatile modifier types, otherwise the const and/or volatile modifiers immediately follow the * pointer on their left.
Based on the precedence rules above, let's take the following exercise:
char * const * (*p) ();
1, according to a rule, starting from P, get P is ... ;
2, according to B1 rules, (*p), get P is the pointer, pointing ... ;
3, according to B2 rule, () function subscript takes precedence over *, so (*p) (), get P is pointer, point to a function, the function returns ...
4, according to the C rule know that the const is modified to the left of the * is not the right, so the right of the * should be the return value of the function, so get p is a pointer to a function, the function returns another pointer, the pointer to the ...
5. According to the C rule, the pointer is pointed to a constant pointer of type char.
6, the above, get P is a pointer to a function, the function returns another pointer, and the pointer to a type of a constant pointer of char.
Done!!!!!
Here are some exercises to consolidate, after which the answers are given:
1, char * (*ARRAY[10]) (int **p)
2, void (*signal (int sig, Void (*fun) (int))) (int)
Hehe, I believe you are very disgusted with the above statements, then we come to find a solution, that is, using TypeDef, such as the above practice Void (*signal (int sig, void (*fun))) (int), Using typedef to use is: typedef void (*PTR_TO_FUN) (int)
Ptr_to_fun signal (int, ptr_to_fun)
That's a clear estimate!
Speaking of this, some friends will say: Can you use # define to solve it?? Well, it's OK, but it's not good, why? Many friends probably know that because # define is a simple symbol substitution, no type checking, and others such as # define MAX ((x) > (y)? ( x):(y)) These will bring all sorts of bad things, and here is not much to say, anyway, I do not have to use a # define, except for constants.
Well, after reading, you can rest, you can also look at the above practice of the answer, check, there are questions please put forward:
1, array is a number of arrays, the elements of the array is a pointer, the pointer to a function, the function of the parameter is pointer to the pointer p, the function returns another pointer, and this pointer to the char type.
2, fun is a function pointer, the function parameter is an int, the return value is Void,signal is a function, one parameter is an int, another parameter is fun, return another pointer to the function, the function argument is int, return void (actually is fun)
How to understand complex type declarations for C and C + +