Analysis of C ++/C complex statements
Posted Wednesday, 2009/09/09-09:57 by easyeagel
Summary: This is an article by the translator on codeproject.ArticleThe author gives a more appropriate and detailed description of the process of understanding complex statements in C ++/C. Complex statements in C ++/C are sometimes difficult to understand. This article also provides the famous "left and right principles". Of course, this principle should be more accurate based on a certain priority, however, the principle provided by the author can solve almost all problems. English.
Directory[Hide]
- Introduction
- Basic
- Const Modifier
- The use of typedef
- Function pointer
- "Right left rule" [important!]
Introduction
Have you ever encountered a variable declaration like int * (* FP1) (INT) [10]; that puzzles you? This article will go from easy to difficult and teach you how to understand this complicated C/C ++ statement step by step: we will start with a simple statement that we can come across every day, then add the const modifier, typedef, and function pointer. Finally, we will introduce a "right-left rule" that allows you to accurately understand any C/C ++ declaration ". It should be emphasized that the complex C/C ++ statements are not a good programming style. Here I will only teach you how to understand these statements. Note: to ensure that the data is displayed on the same lineCodeAnd related notes, this article is best to read on at least X resolution display.
Basic
Let's start with a very simple example:
Int N ;
This should be understood as "declare N as an int" (N is an int type variable ).
Next, let's take a look at the pointer variables as follows:
Int * P ;
This should be understood as "declare P as an int *" (P is an int * type variable), or P is a pointer to an int type variable. I would like to discuss it here: I think it is best to write * (OR &) before it is near the variable when declaring a pointer (or reference) type variable, instead of following the basic type. This avoids some misunderstandings, such:Int*P, q;
At first glance, it seems that p and q are both int * types, but in fact, only p is a pointer, and Q is the simplest int type variable.
Let's continue with our previous topic. Let's look at a pointer example:
Char ** Argv ;
Theoretically, there is no limit on the pointer's level. You can define the pointer's pointer to a floating point type variable...
Let's take a look at the following statement:
Int Rollnum [ 30 ] [ 4 ] ;
Int ( * P ) [ 4 ] = Rollnum ;
Int * Q [ 5 ] ;
Here, P is declared as a pointer to a 4-element (INT type) array, and Q is declared as an array containing 5 elements (INT type pointer.
In addition, we can also mix and use * and & in the same declaration, as follows:
Int ** P1 ; // P1 is 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 of the int type; P2 is a reference of the int type; P3 is a pointer of the int type reference (invalid !); P4 is a reference of the int type reference (invalid !).
Const Modifier
When you want to prevent a variable from being changed, the const keyword may be used. When you add a const modifier to a variable, you usually need to initialize it, because you will not have the opportunity to change it any time in the future. For example:
Const Int N = 5 ;
Int Const M = 10 ;
The preceding two variables N and m are of the same type -- both are const int (integer constant ). According to the C ++ standard, the const keyword is equivalent before the type or variable name. I personally prefer the first declaration method because it highlights the role of the const modifier.
Const and pointer are confusing. For example, let's take a look at the p and q statements in the pipeline:
Const Int * P ;
Int Const * Q ;
Which of them represents the const int type pointer (const directly modifies INT), and which one represents the int type const pointer (const directly modifies the pointer )? In fact, both p and q are declared as const int type pointers. The const pointer of the int type should be declared as follows:Int * ConstR= &N; // N has been declared as an int
Here, both p and q point to the const int type pointer, that is, in the futureProgram* P value cannot be changed. R is a const pointer, Which is initialized to point to the variable N (that is, r = & N;) when declared, the R value is no longer allowed to be changed (but * The R value can be changed ).
In combination with the above two const modifiers, we declare a const pointer pointing to the const int type, as follows:
Const Int * Const P = & N // N has been declared as const int
The following statements about const will help you thoroughly clarify the usage of Const. However, note that the following statements cannot be compiled because they must be initialized at the same time. For the sake of conciseness, I ignored the initialization part. Because the initialization code is added, two lines of code will be added for each declaration below.
Char ** P1 ; // Pointer to Char
Const Char ** P2 ; // Pointer to const char
Char * Const * P3 ; // Pointer to const pointer to Char
Const Char * Const * P4 ; // Pointer to const char
Char ** Const P5 ; // Const pointer to Char
Const Char ** Const P6 ; // Const pointer to const char
Char * Const * Const P7 ; // Const pointer to Char
Const Char * Const * Const P8 ; // Const pointer to const char
Note: P1 is the pointer to the char type; P2 is the pointer to the const char type; P3 is the const pointer to the char type; p4 is the const pointer to the const char type; P5 is the const pointer to the char type; P6 is the const pointer to the const pointer of the const char type; p7 is the const pointer to the const pointer of the char type; P8 is the const pointer to the const pointer of the const char type.
The use of typedef
Typedef provides you with a way to overcome the disadvantages of "* Only applicable to variables but not types. You can use typedef as follows:
Typedef char * pchar;
Pchar p, q;
Both p and q are declared as pointers. (If typedef is not used, Q will be declared as a char variable, which is inconsistent with our first glance !) The following are some declarations using typedef and explanations:
Typedef Char * A ; // A is a pointer to a char
TypedefA B(); // B is a function that returns
// A pointer to a char
TypedefB*C; // C is a pointer to a function
// That returns a pointer to a char
TypedefC d(); // D is a function returning
// A pointer to a function
// That returns a pointer to a char
TypedefD*E; // E is a pointer to a function
// Returning a pointer to
// Function that returns
// Pointer to a char
E var[10]; // VaR is an array of 10 pointers
// Functions returning pointers
// Functions returning pointers to chars.
Typedef is often used before a schema declaration, as shown below. In this way, when creating a structure variable, you are allowed not to use the keyword struct (in C, the keyword struct is required when creating the structure variable, such as struct tagpoint; in C ++, struct can be ignored, for example, tagpoint B ).
Typedef Struct Tagpoint
{
Int X ;
Int Y ;
} Point ;
Point P; /* Valid C code */
Function pointer
Function pointers are probably the most confusing statements. Function pointers are used most frequently when writing TSR programs in the DOS era. in Win32 and X-Windows, they are used when callback functions are needed. Of course, function pointers are also needed in many other places: virtual function tables, some STL templates, Win NT/2 k/XP system services, etc. Let's take a simple example of a function pointer:
Int ( * P ) ( Char ) ;
P is declared as a function pointer. This function includes a char parameter and an int type return value. In addition, a function pointer with two float type parameters and a pointer whose return value is char type can be declared as follows: char ** ( * P ) ( float , float ) ;
How should we declare a const pointer parameter with two Char Types and a function pointer without return values? Refer to the following:Void * (*A[5])(Char * Const,Char * Const);
"Right left rule" [important!]
This is a simple rule, but it allows you to understand all statements accurately. This rule uses the following code: Read the statement from the inner brackets, read the statement to the right, and then look to the left. When you encounter a bracket, you can adjust the reading direction. All content in the brackets is analyzed and out of the brackets. This continues until the entire statement is analyzed.
Make a small correction to the "left-right rule": when you first read the declaration, you must start with the variable name instead of the innermost brackets.
The following example demonstrates the use of the "right left rule.
Int * ( * ( * FP1 ) ( Int ) ) [ 10 ] ;
Reading steps:
- Starting from the variable name -------------------------------------------- FP1
- Look to the right, nothing, met), so look to the left, met a * ------ A pointer
- Jump out of the brackets and encounter (INT) ----------------------------------- a function with an int parameter.
- Look left and find a * ------------------------------------------- (function) returns a pointer.
- Jump out of the brackets and look to the right. You can see [10] ---------------------------- an array of 10 elements.
- Look left and find a * ------------------------------------------- pointer
- To the left, int ------------------------------------------------- int type is found.
Conclusion: FP1 is declared as a pointer to a function, which returns a pointer to a pointer array.
Let's look at an example:
Int * ( * ( * Arr [ 5 ] ) ( ) ) ( ) ;
Reading steps:
- Starting from the variable name -------------------------------------------- arr
- To the right, it is an array ------------------------------------ an array of 5 elements.
- Look left and find a * ------------------------------------------- pointer
- Jump out of the brackets and look to the right. () ------------------------------ the function without Parameters
- To the left, * ----------------------------------------------- (function) returns a pointer.
- Jump out of the brackets and find () ------------------------------------ a function without Parameters
- To the left, we found that * ----------------------------------------- (function) returns a pointer.
- Continue to the left and find int ----------------------------------------- int type
Conclusion :??
There are more examples:
Float ( * ( * B ( ) ) [ ] ) ( ) ; // B is a function that returns
// Pointer to an array of pointers
// To functions returning floats.
Void * ( * C ) ( Char , Int ( * ) ( ) ) ; // C is a pointer to a function that takes
// Two parameters:
// A char and a pointer to
// 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
// Two parameters:
// A reference to an int and a pointer
// To a function that takes two 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 void
float ( * ( * E [ 10 ] )
( int & ) ) [ 5 ] ; // E is an array of 10 pointers to
// functions that take a single
// reference to an int as an argument
// and return pointers to
// an array of 5 floats.