Pointer decryption
(Li Jun)
In fact, the pointer is so mysterious. It is just that people get it more mysterious. In some C or C books, they always refer to it clearly or not deep enough, I wrote this article to help you quickly master the pointer. The essence, this article assumes that you are not a pointer, and compare the basic use of pointers.
Understand the basic pointer concept:
The type of pointer is the address. This should understand that it can only store the address, ok! Let's first understand the three extremely important concepts:
1, the value of the pointer variable (the memory unit where the pointer variable)
2, the address of the pointer variable (the memory unit address of the pointer variable)
3, the value of the value of the pointer variable (address) (that is, the number of internal memory points to the pointer to people)
( figure 1)
Address: 0x6FE3 address: 0x23ef
The above picture is already very clear, and the pointer variable is saved 0x23ef, and it is a data 2343 in 0x23ef;
The following uses a few conceptual practical examples to deepen understanding: (very representative is often confused)
* Note: For clarity, all the addresses in all examples are the integrity of the deck (such as: char * pc = 0x201e), everyone
Don't do this when you actually write code, because it will cause a paragraph error.
( example 1)
MAIN () {
Char * a = 0x0005, * b = a;
* b = 'a';
* b = 'b'; / * first put the address of the B fingers 1, then attach the 'b' to the unit of this new address, namely: * 0x0006 = 'b' * /
Printf ("A =% D, B =% D, * a =% C, * B =% C / N", A, B, * A, * B);
* B = 'c'; / * first attach the 'c' to 0x0006, 1 in the address, and its b point to this address * /
Printf ("A =% D, B =% D, * a =% C, * B =% C / N", A, B, * (A 1), * b);
Getch ();
}
Output: a = 5, b = 6, * a = a, * b = B
A = 5, b = 7, * a = c, * b = r
Interpretation: From the above example we found that the B itself change, it will not be related, until B wants to change A or A will change when the memory will refer, this is why I want to print (A 1) this address value The reason, in fact, this address is 0x0006 because the sentence is to attach this address 'c' after the pointer 1, OK, plus 1, actually points to 0x0007 this address, this memory The thing stored is uncertain because we have not included any value for it, so the last * b prints out is 'r'.
(Example 2)
TEST (Char * TA) {
* ta = 'b';
}
MAIN () {
Char * a = 0x0005;
* a = 'a';
Printf ("A =% D, * a =% C / N", A, * A);
Test (a);
Printf ("A =% D, * a =% C / N", A, * A);
Getch ();
}
Output: a = 5, * a = a
A = 5, * a = a
Comment: Is it very unexpected? In fact, this example is similar to one of the above examples, but there is a knowledge point, in fact, when passing the number of parameters, it will give the commission in a function (ginseng) Therefore, the code above can be imagined as: main () {
Char * a = 0x0005;
Char * ta;
* a = 'a';
Printf ("A =% D, * a =% C / N", A, * A);
TA = a;
* ta = 'b'; / * test (a) * /
Printf ("A =% D, * a =% C / N", A, * A);
Getch ();
}
It is easy to understand, you can imagine the partial variable of the method, and call the local variable when calling the value.
Now there is a deeper understanding of the pointer; let's see some complex examples! In fact, the complexity of the pointer is not written,
And what you have done for memory understanding and compilers.
(Example 3)
Testa (char ** pc) { * pc;}
TestB (char * pc) { * pc;}
MAIN () {
Char * c = 0x0004, ** PC = & C;
Printf ("Testa_f =% I / N", C);
TESTA (PC);
Printf ("Testa_a =% I / N", C);
Testb (& C);
Printf ("Testb_a =% I / N", C);
Getch ();
}
Output: Testa_f = 5
TESTA_A = 6
Testb_a = 7
Interpretation: This example is a bit complicated, want to explain where it is necessary to use the pointer to the pointer and how to use it. Most of the pointers of the pointer are used after the calling method, the value is also changed. Actually It is not difficult to understand it, you only need to point the pointer to the pointer to a normal variable is OK, (for example: char c = 'c', * pc = & c, ** pcc = & pc; you think PC imagination It is easy to understand like a common variable) so that the * PCC actually takes the value of the PC (ie: the address of the variable C), and the ** PCC actually takes C value (Ie: Character 'C'), now look very simple!!
(Special case, do not imitation)
(Small case 1)
Main ()
{
INT I = 45, * P = 45;
* P = 345;
Printf ("% i", * (int *) i);
Getch ();
}
(Small case 2)
INT * RT_32 [3];
Main ()
{
INT * P = 45;
* P = 345;
* RT_32 [1] = 45;
Printf ("% i", ** (int **) RT_32 [1]);
Getch ();
}
The output results are: 345
This application is very advanced, I am found when I write a VM, this feature is very strong, that is, it can implement the value of a integer variable as an address to take the value in the memory cell of this address, this Applications are generally different in VC, TC2.0 can, but also pay attention to this application is very dangerous, you must first know what number of this integer is in, but also knows this number as an address. What is the value is. It is recommended not to use this method.
Arranges and pointers:
Arranges and pointers are the topic of the most controversy in C language. Now let's analyze what the array and pointers are different.
(Difference 1)
Document 1:
INT test [100];
Document 2:
Extern Int * test;
The above is the compilation that cannot be passed, from which the array and pointer are distinguished. (Difference 2)
Arrays must give the size when declaring, and pointers theory can be dynamically increased. And more flexible operations are more flexible.
(Difference 3)
For example, CHAR A [4] = "abcd"; char * p;
a [2];
Value of array: 1, the compiler replaces the A symbol with address 9980.
2. Step 1 of the runtime: Take the value of the subscript 2, add it to 9980.
3. Step 2: Take the content of the address (9980 2).
* (p 2)
Pointer Value Operation: 1, the compiler replaces the P compliant with address 4624.
2. Step 1: Take the content of address 4624 (such as 5081).
3. Step 2: Remove the contents of (5081 1).
It is clear that there is a more addressed address operation, first find the address of the P address, then find the address stored in the P address, and finally find the address content of this address 2.
See the difference in the compiler:
Char a [4]; translated into 9980; actual action: * (9980 2)
Char * p; compiled into 4624; actual action: * (* (4624) 2)
Then let's study when you are defined as a pointer, but what happens in an array method.
Such as: char * p = "abcd";
Value operation: 1, the compiler replaces the P in accordance with address 4624.
2. Step 1: Take the content of address 4624 (such as 5081).
3, the runtime step 2: The subscript value of 2 is taken, and its content is added to 5081.
4. Step 3: Take the content of address 5081 2.
In fact, the fundamental difference between arrays and pointers is that the pointer is indirect access data, first obtains the contents of the pointer, treat it as an address, then taking data from this address, and the array is directly accessing data, A [i], just simple in A i is the address. The pointer is typically used with the dynamic data structure, and the array is generally used with the same elements as the fixed number and data types.
Understanding function calls:
OK, I believe that people who have learned or understand the principle of compilation know that when the function call is used to save temporary variables, their life cycle is released after the function is returned, and we use a small Code proves.
(Example 4):
Void * vp;
Testa () {
CHAR * C = 10;
(char *) VP = & C; / * Real VP points [SP 2] -> vp * /
}
Testb () {
CHAR * C = 20; / * VP refers to the units of this changed * /
}
MAIN () {
Testa ();
Printf ("VPA =% I / N", * (Char *) VP);
Testb ();
Printf ("VPB =% I / N", * (Char *) VP);
Getch ();
}
Output result: 10
20
This code proves the existence of the stack segment.
The destruction of the stack segment and the code segment are very simple, see a small code.
(Example 5):
(* pf) ();
Void * ps;
f ()
{
CHAR C = 40;
(char *) PS = & C;
Printf ("f =% I / n", c);
}
Main ()
{
PF = PS;
f ();
PS = PF;
f ();
PF ();
Getch ();
}
Function pointer (advanced)
Maybe everyone will decide, I will complicate this example below, but you must understand it to understand the following example.
The following example describes the transformation call of the function pointer, it can be said that it is overloaded in C , but in some respects, it is more than the reload, as it can make the different type of basis for the return type of the function.
(Example 6):
(* pf) ();
F1 () {
Printf ("f1 / n");
}
F2 (char C) {
Printf ("F2 =% I / N", C);
}
Char f3 (char c) {
Return C;
}
F4 (INT I, CHAR C) {
Printf ("F4 =% I,% D / N", I, C);
}
Main ()
{
PF = f1;
PF ();
PF = f2;
(void (*) (char)) PF (34);
PF = f3;
Printf ("F3 =% I / N", (char (*) (char)) PF (100));
PF = f4;
(void (*) (int, char)) PF (200, 120);
Getch ();
}
Oh! It's very powerful. Four transformations, realized 4 methods for binding.
Let's take a look at an example of implementing a function pointer array. Generally, it implements a limited state machine.
(Example 7):
#define max_test 4
Void a () {Printf ("Function A By Call! / N");
Void B () {Printf ("Function B By Call! / N");
Void c () {Printf ("Function C by Call! / N");
Void d () {Printf ("Function D By Call! / N");
Void (* test [MAX_TEST]) () = {a, b, c, d}; / * declaration and initialization function pointer array * /
Main ()
{
INT I;
For (i = 0; i TEST [I] (); Getch (); } Function pointers are fun, you can call the following mode (* test [i]) (); you can even (***** test [i]) (); Very depressed. The most important thing is not to mess with your thinking, what do you think is most in line with your understanding, how do you call it. I personally still tend to use Test [i] (); because I started from my study C, I understand the function name as the entrance address of the function. The last example is very interesting, can C in c to achieve class like C ? Use this example to be a small inspiration. No real Implementation of the object is only bound to some functions. (For reference only) (Example 8): #define new (n) n-> build = building; n-> build (myclass, add, printsum, closeclass, n) Typedef struct myclass { Int a; INT B; Void (* my) (); INT (* add) (int, int); Void (* putsum) (int); Void (* myclose) (); Void (* build) (void (* n) (int, int), void (* p) (int), void (* c) (), struct myclass *); } Class; Void myclass () { Printf ("CREATE MyClass !!! / N); } INT Add (int A, int b) { RETURN A B; } Void Printsum (INT C) { Printf ("SUM =% I / N", C); } Void CloseClass () {Printf ("Close Myclass !!! / N); } Void Building (Void (* N) (int, int), void (* p) (int), void (* c) (), Class * MC) { MC-> my = n; (* mc) .add = ad; (* mc) .putsum = p; (* mc) .myClose = C; } void main () { Int sum; Class * myobj; NEW (myobj); MyObj-> my (); Sum = myobj-> add (myobj-> a = 5, myobj-> b = 10); MYOBJ-> Putsum (SUM); Myobj-> myclose (); Free (myObj); Getch (); } Let's take a look at the characteristics of analog inheritance. (Example 9) #define new (n) n-> build = building; n-> build (myclass, add, printsum, closeclass, n) #define subnew (n) n-> build = subbuilding; n-> build (div, n) Typedef struct myclass { Int a; INT B; Void (* my) (); INT (* add) (int, int); Void (* putsum) (int); Void (* myclose) (); Void (* build) (void (* n) (int, int), void (* p) (int), void (* c) (), struct myclass *); } Class; Typedef struct submyclass { Class * BaseClass; INT (* DIV) (INT); Void (* build) (int (* d) (int), struct submyclass * sc); Subclass; Void myclass () { Printf ("CREATE MyClass !!! / N); } INT Add (int A, int b) { RETURN A B; } Void Printsum (INT C) { Printf ("SUM =% I / N", C); } Void closeclass () { Printf ("Close Myclass !!! / N); } Void Building (Void (* N) (int, int), void (* p) (int), void (* c) (), Class * MC) { MC-> my = n; (* mc) .add = ad; (* mc) .putsum = p; (* mc) .myClose = C; } Int Div (INT A) { Return (A / 2); } Void Subbuilding (int), Subclass * SC) { Building (Myclass, Add, Printsum, CloseClass, SC-> BaseClass); (* SC) .div = D; } void main () { Int sum; Class * myobj; Subclass * sobj; NEW (myobj); MyObj-> my (); SUM = myobj-> add (myobj-> a = 6, myobj-> b = 10); Myobj-> Putsum (SUM); myobj-> myclose (); Subnew (SOBJ); Printf ("DIV =% I / N", SOBJ-> DIV (SUM); Getch (); }