2. Digital colored pointer
All Kinds of Pointers
The next chapter introduces the pointer and its definition, this section continues to study a variety of different pointers and its definition methods (Note: This chapter is not discussed because the function pointer is special, this chapter does not discuss, but the word "pointer", such as non- Special instructions are all indicated by the pointer).
1) Pointer to point to the pointer
We already know that pointer variables are variables used to store specific data type addresses, if we define
INT * PINT;
So, Pint is a pointer variable pointing to integer variables. Ok, we extract the backwards of the previous sentence, that is: Pint is the variable. Since PINT is a variable, there will be address values of the corresponding storage data in memory, then theoretically, there should be a corresponding pointer to store, um, actually, we can define the variable to this Pointed pointer:
int ** pintptr;
According to the method of the previous chapter, it is very well understood: ** Pintptr is an int type, then remove a *, * Pintptr is a pointer to int, then go to a *, our final pintptr is a "pointing INT type" The pointer variable of pointer variable ", huh, it is a bit, no matter how we can write now:
Pintptr = & PINT;
Let it point to the PINT variable, and * PintPTR can retrieve the PINT variable. If Pint points to a integer variable such as A, * Pint can represent A, therefore * (* PINTPTR) can also get A more indirectly, of course, if we save parentheses, write ** Pintptr is also possible.
In this kind, we can also get int *** p "pointing to pointers pointing to pointers pointing to the INT type variable", or complex: int **** p, "pointing to pointing pointing pointing ..." 喔It is already very dizzy, but the principle is here, you can more than one.
2) Pointers and constants
C constants can be divided into two, one is "text" constant, such as 18, 3.14, 'A', etc. in our program; the other is the constant defined by keyword const. Most of the two constants can be considered equivalent, but there are still some fine differences, for example, "text" constants cannot be used directly with & find their corresponding addresses in memory, but constants defined by Consts can. In other words, we can't write & 18 expressions, but if we define
Const int classnumber = 18;
Then we can get the address of the constant classNumber through the & classNumber expression (not the address of the constant 18!). In fact, in the storage characteristics, constants are basically the same (with corresponding addresses, and there is a corresponding value on the corresponding address), we can regard constants as a "limited" variable: only readable . Since they are so similar, the variables have corresponding pointers, the constants should also have their corresponding pointers. For example, a pointer PCONSTINT pointing to INT constant is as follows:
Const int * pconstint;
It means that * PConstint is a integer constant, so PConstint is a pointer to integration constant. We can write
PCONSTINT = & classNumber;
To make PConstint points to constant classnumber. Give you three seconds, please determine that PConstint is constant or variables. 1, 2, 3! OK, if your answer is a variable, then you know that your concept of constant variables is not bad, otherwise you should flush the C book to see the contents of the Const part. Oh, since int, float, double, even the Class, which we define, can have a corresponding constant type, then the pointer should have constant. Now, how should we define a pointer constant? We usually define a constant to add const, such as const I, etc., but if you definition in front of the pointer, due to * is the right combination, the semantic computer will treat the const *p ( Const int (* p) (parentheses is to highlight the form of combined form, but not legal C syntax), ie * P is a const INT type constant, P is a pointer to Const INT constant. That is, what we add is not modified, but modified * p, how is Int const * p? Hey, this is different from const Int * p. In order to make our const can be modified to P, we must cross the 号 阻 到 到前 前, if we first define an int variable A, statement
INT * Const P = & A;
As we want to define a pointer constant p, it always represents the address A, that is, it constitutes the variable A.
Well, Summary: In the eve, we talked two pointers, one is "pointer variable" pointing to constants ", and then" pointer constants "pointing variables", the difference between them is that const modified * p or P Similarly, there will be "pointer constant" pointing to constants ", obviously, there must be two const, a modification * P, another modified P:
Const Int * const p = & classnumber;
With * as boundary, we are also very well understood: * indicates that we declare the pointer, and the previous const INT indicates that it points to a constant constant, the back constant indicates that it is a constant pointer.
For the convenience difference, many articles have introduced "from right to left" reading, where "*" reads "pointer":
const INT * P1 = & ClassNumber; // P1 is a pointer, pointing to INT type constant
INT * const p2 = & a; // p2 is a pointer constant, which points to INT type variables
Const int * const p3 = & classnumber; // p3 is a pointer constant, pointing to int type constant
Ok, when we define the constant of the pointer, we have been bonded to the * right, so that the front const modification is not p, if * can be combined with Int (just like the previous chapter "preamble "Understanding), becoming a" pointing to the type of intersection ", such as
Const (int *) P;
Const can be modified to P. However, C parentheses can only be used to change the priority of the expression and the order of the binding of the declaration statement can not be changed, can you think of another method to implement parentheses?
The answer is yes: use the keyword typedef.
One of TypeDef is to bundle multiple variables / constant modifiers as a mixed new model, for example to define a symbolic integer, we want to write const unsigned int classnumber = 18;
But we can also define "unsigned integers" into a specific type with typedef.
Typedef const unsigned int continuint
This way we only need to write
Constuint ClassNumber = 18;
The effects of the previous equivalent can be achieved.
It seems that there is no relationship with our concern. In fact, TypeDef's "bundle" is equivalent to adding parentheses, if we define:
Typedef Int * INTPTR;
what does this mean? This means that INTPTR is a "integer pointer variable" type. This is the new composite type that has not appeared in front. In fact, this is the "int *" type appreciated by the previous chapter: our original, even write
INT * P1, P2;
Although there is a space as our visual distinction, unfortunately, the compiler does not eat this set, still combined with P1, becomes
INT (* p1), p2;
So poor P2 is not to be a integer variable. But now we write
INTPTR P1, P2;
The conclusion is different: with Typedef's bundle, INTPTR has become a model of the actual integration type, so P1, P2 has become a pointer of the goods. Then we write
Const INTPTR P;
Oh, sorry, compilation error: No initialization constant P ... 咦, did you see it? The decorative under Const IntPtr has become a pointer constant (not the constant pointer to constant), oh, understand, due to Typedef's bundle, Const and Intptr are consistent with the P, is understood for:
(const) P;
Not in front
(const Int) (* P);
So don't smash Typedef, don't think about it as a simple macro. In fact, "C Primer" has been such a similar examination question, about testing you: Const INTPTR P is pointing to the pointer constituting the consT Int or pointing to the point of INT. I know that you can answer this question without hesitation.
BTW: When I saw it for the first time, I didn't hesitate, but unfortunately I had an error ^ _ ^
3. Pointer, dynamic memory, array
We have already known that the variables are in the last chapter, and the variables are actually a compilation system to allocate a memory allocated, and the compiler will correctly link the variable name to our memory to read and write. Imagine, if there is no "variable name" such a memory unit, how should we access it? Hey, if there is the address of this unit, we can also return to the corresponding variable by * operators.
Variable definitions can be seen as the implementation of two functions: 1. Assign memory; 2. Connect the memory with the variable name.
As mentioned earlier, if you know the address, you can do not need a variable name, so the upper two functions are becoming: 1. Allocate memory; 2. Save the address of the memory to the assigned;
The above functions can also be realized. In C , we can implement the second method using the New operator. The New expression will assign we allocate a proper memory and will return the first address of the memory (exactly that it should be a pointer). In the expression, the keyword NEW is usually followed by the data type to indicate the size of the allocated memory and the type of pointer, such as the NEW INT expression will allocate the memory required for us (32-bit machines For 4-byte), then the value of this expression is a constant pointer value to the memory. So we can write: int * p;
P = new int; // Assign a piece of memory for storing a integer variable, and assign the address to the pointer P
This way we can use * P to do the same operations.
We only assigned a integer storage unit in memory, we can also assign a memory that stores multiple integer values, the method is to add the number enclosed in "[]" after INT, this number is you Want to allocate the number of units. Such as:
INT * P;
P = new int [18]; // Assign a piece of memory for storing 18 integer variables, and assign the first address to the pointer P
But at this time, we can use * p to access the first one of the 18 intellectual units, how to access 17 units? Since these units are continuously stored, we only need to know the value of the first address and the space occupied by each integer variable, the start address value of other 17 units can be calculated. In C , we don't even have to "space for each plastic variable", because C can "automatically" achieve this, we only need to tell it that we intend to access relative to the current pointer value The first few units can be. This can be implemented through the pointer operation, for example, according to the previous declaration, now P has points to the first block of the 18-piece storage unit, if I want to access the second block, is the next memory that P currently refers to? Very simple, just write P 1, the result of this expression will be magically to get the address of the second memory unit, if your machine is 32-bit, then you can print the P's address value and P 1 address value, you will find that the difference between them is 4 bytes, not one, the compiler has automatically doing the work of the conversion for us: it will automatically take 1 pointer to one Memory (4 bytes) occupied by variables (integer variables). So if we want to assign a value to the second memory unit, it is only necessary to write:
* (p 1) = 3; // Note: * The priority is higher than the number, so add parentheses
Write when you want to print:
COUT << * (p 1); // Output 3
In short, these are nothing in the same way as the general variable. We can certainly assume its address value to additional pointer variables:
INT * myptr;
Myptr = p 1; // OK, now myptr is the address of the second memory unit
You can also perform your own operation:
MYPTR ; // According to the initial value above, the Myptr is the address of the third memory unit after adding.
* myptr = 18; // Now give the third memory unit to an integer value 18, it is equivalent to * (p 2) = 18
Everything is very good so far, but * (p 1) is too troublesome, C introduces a brief method, "[]" operator (I used it when I first defined): To access the second unit memory, we only need to write p [1], it is actually equivalent to * (p 1): p [1] = 3; // * (p 1) = 3;
COUT << p [15]; // cout << * (p 15);
P [0] = 6; // * (p 0) = 6; also * p = 6;
To illustrate the equivalence of "[]" and * (... ...), look at a set of strange examples:
1 [P] = 3; // * (1 P) = 3;
COUT << 15 [P]; // cout << * (15 P);
0 [P] = 6; // * (0 P) = 6; also * p = 6;
Is it very weird? In fact, this group only exchanged the plus position, the function is exactly the same as the previous group.
As we introduce a new method for allocating memory: using the New operator. In addition to the variable name included in the NEW operator, it is also an important difference with the variable allocation: The New operator is allocated in the heap (HEAP), and the usual variable definition is in the stack (STACK) allocated memory. The stacks and stacks are two parts of the program memory. It is necessary to understand that it is necessary to understand that the memory system allocated on the stack will automatically release, for example, local variables will not be completed at the end of the function. The existence is that the system automatically clears the result of the stack memory. But the memory allocated in the pile is: everything is responsible, even if you exit the function or scope of the New expression, the memory is still in use and cannot be used again. The advantage is if you want to share memory in different modules, then this is your meaning, if you don't plan to use this memory and forget to release it, then it will account for your precious memory resources until you Your program exits. How to release the number of resembals allocated by NEW? The answer is to use the Delete operator. Delete is probably one of the simplest parts of C (but it is also very easy to get crowd!), you only know how you want to release a single unit's memory, or multiple units of memory, if:
INT * p = new int; // Here, the allocation statement is put together with initialization, the effect is the same as the previous
... // Use * P
Delete P; // Release P The memory finished, that is, the memory allocated by New
If it is a plurality of units, it should be like this:
INT * p = new int [18];
... // Use
Delete [] P; // Note
// to ensure that the whole memory is released, no "[]" will only release the first memory of P fingers
Just now, we allocate continuous memory in the stack. Similarly, you can also allocate edges on the stack, for example, we must allocate the integer memory space of 18 units, and assign the first address to pointer a, defined as follows:
INT A [18];
Similar to the previous version of New, the system will allocate 18 integer memory cells on the stack, and give the first address to the pointer A, we can also pass "[]" operator or ancient "* (... ...)" To achieve access to it. It should be noted that A is a pointer constant type that cannot be assigned to other variables to other variables. Similarly, since it is allocated in the stack, it doesn't have to worry about us. Since A "looks" contains many of the same type of variable, C is called an array. From the above view, the array assignment of the stack seems to be simpler than the branch assignment, but the stack assignment has a shortcoming, that is, if I want to write a sorting program, every time I have to write Sorting elements are different, but I can't write
Int number;
CIN >> NUMBER;
INT A [Number]; // Error, Number is a variable, and the size of the array A of the fractal space on the stack must be
// decide when compiling
But I can write
Int number;
CIN >> NUMBER;
INT * a = new int [number]; // No problem, the spatial allocation can be determined when the program is running
Of course, don't forget to release it:
delete [] a;
Since the allocation of the heap memory has greater flexibility than the stack memory, the size of the allocation space can be determined in the program execution period, so it is also called dynamic memory.