Exploring the mysteries of C/C ++ arrays and pointers: pointer and const
The term const literally comes from the constant. The const object has different resolutions in C/C ++. As described in Chapter 2, constant expressions in C must be in the compilation phase, it is not a constant expression at runtime, so const in C is not a constant expression. But in C ++, it is a constant expression because it removes the limitation during compilation.
For a pointer to const t pointing to a const object, since we regard const as a constant expression, we often have the following two ideas:
1. This is a pointer to a constant;
2. The content pointed to by this pointer cannot be changed.
This is a rough understanding. Although the pointer type is pointer to const t, it does not mean that the object it points to is really a constant or cannot be changed, for example:
Int I = 10; </P> <p> const int * P = & I; </P> <p> I = 20;
The object I pointed to by P is obviously not a constant. Although P points to I, the I value can still be changed. The C ++ standard has a clear description of this phenomenon:
7.1.5.1 the CV-qualifiers
A pointer or reference to a CV-qualified type need not actually point or refer to a CV-qualified object, but it is treated as if it does;
Among them, CV refers to const and volatile, const and volatile are called type qualifier, and type limiters. Const T is only a type assumption, not indicating what the object is. This object may be limited by const, maybe not. Since the above two views are inappropriate, what should pointer to const t look? A better understanding is to regard it as an access path. There are many methods for performing value or modification operations on an object. Each method is equivalent to a path that can access the object, for example:
Int I = 10, K; </P> <p> const int * P = & I; </P> <p> int * q = & I; </P> <p> I = 20; </P> <p> * q = 30; </P> <p> K = * P;
You can access the integer Objects represented by I through * q, * P, and identifier I. They can be considered as three paths. I and * Q can modify the value of this integer object, these two paths are writable and readable, but * P cannot be written, because the object to which P points is assumed to be const. From the perspective of P, * P is read-only, you cannot use P to modify the object to which it points. Therefore, the exact meaning of a pointer to const t pointer is not that it points to a constant or the object to which it points cannot be changed, but that it cannot be used to modify the object it points, whether the object is const or not, it only specifies one read-only path to the object, but other paths can be used to modify the object. This understanding is justified in the standards:
7.1.5.1 the CV-qualifiers
A const-qualified access path cannot be used to modify an object even if the object referenced is a non-const object and can be modified through some other access path.
The above terms provide a clear description of the access path.
A pointer of the pointer to T type can be assigned to a pointer of the pointer to const type. This is a well-known syntax rule. I once thought that the reason why the two values can be assigned is based on the compatibility principle of pointers and thought they are compatible. Later I read the C/C ++ standards, this interpretation is actually incorrect. In terms of compatibility principle, the two are just incompatible. The compatibility of pointers in the C standard is as follows:
6.7.5.1 pointer declarators
For two pointer types to be compatible, both shall be identically qualified and both shall be pointers to compatible types.
Two compatible pointers must have the same qualified modifier and the type to which it points must be compatible. The two compatible types must comply with the following requirements:
6.2.7 compatible type and composite type
Two types have compatible type if their types are the same.
If the two types are the same, are the two types of CONT and t the same? Let's look at the following terms:
6.2.5 types
The qualified or unqualified versions of a type are distinct types that belong to the same type category and have the same representation and alignment requirements.
The limitation and Non-limitation editions of a type are different types with the same expression range and alignment requirements of the same type. This means that the const T and T are not of the same type and they are incompatible. Therefore, although pointer to const T and pointer to t have the same qualified modifier (no qualified word ), however, the object type pointed to is not a compatible type, so pointer to const T and pointer to t are incompatible pointer types.
Since the two are incompatible, why can they assign values? Check the provisions of the C standard on the Value assignment operator and find that there are such clauses:
6.5.16.1 simple assignment
Constraints
One of the following shall hold:
.........
-Both operands are pointers to qualified or unqualified versions of compatible types,
And the type pointed to by the Left has all the qualifiers of the type pointed to by
Right;
Oh, the reason is here! The Type pointed to by the left operand must contain all the qualified words of the type pointed to by the right operand. Pointer to const T has one more const than pointer to T. Therefore, you can assign pointer to t to pointer to const t, but not vice versa. In other words, the left operand is stricter than the right operand. The rules in C ++ are a little different from those in C ++. The C ++ standard removes this clause, replacing it with the concept of more CV-qualified, a pointer from pointer to cv1 T, to convert a pointer to cv2 t, the condition is that cv2 is more CV-qualified than cv1.
Note that the rules of this assignment operator only apply to pointer to qualified or unqualified type and cannot extend to pointer to qualified or unqualified type or higher level pointer types. For example:
Int I = 10; </P> <p> const int * P = & I;/* a */</P> <p> int * q = & I; </P> <p> const int ** p1 = & Q;/* B */
A is legal, but B is illegal. Although P1 and & Q are both unqualified, the object type pointed to by P1 is pointer to const int, And the type pointed to by & Q is pointer to int, as described earlier, the two are incompatible types and do not comply with the rules that the two operands must point to compatible types. Therefore, the value assignment is invalid.
According to the above rules, a pointer to const t cannot be assigned to pointer to T, but a const pointer can assign non-const pointer, for example:
Int I; </P> <p> int * const P = & I; </P> <p> int * q; </P> <p> q = P; /* */
A is valid. In this case, it is not within the rules of the value assignment operator. It follows another clause: Left value conversion. For a qualified left value, after the left value conversion, the right value has an unqualified type of the Left value:
6.3.2 other operands
6.3.2.1 lvalues, arrays, and function designators
When t when it is the operand of the sizeof operator, The unary & operator, the ++ operator, the -- operator, or the left operand of. operator or an assignment operator, an lvalue that does not have array type is converted to the value stored in the designated object (and is no longer an lvalue ). if the lvalue has qualified type, the value has the unqualified version of the type of the lvalue; otherwise, the value has the type of the lvalue.
The value of P has an unlimitedly modified type int * of P, which is compatible with the q type. Therefore, the value assignment is valid. For C ++, it is basically the same as C, but there is an exception, that is, the right value class object, because the right value class object is still an object, c ++ requires that the right-value class object has the same qualified modifier as the left value.
The combination of pointer and const can produce some complicated statements, such:
Const int * const *** const ** const P;
This is a complex combination of pointer declarative operators and const qualified modifiers. the declarative operators are nested six times with two const in the middle. How can we identify which level is const, which level is not? Once you understand the principles, it is actually very simple. First and last const are familiar to everyone. There is a very simple principle for the const hidden in a pile of * numbers: the number of * numbers between the const and the last declaration operator on the left is const. For example, if the second const starts from the right and there are 4 * numbers between the const and the int, the level 4 of P is const, and the following value assignment expression is invalid:
** P = (int * const ***) 10;
However, the following values are allowed:
* ** P = (int * const **) 10;
The second const starts from the number on the left. There is one * between the const and the int, so the first level of P is const, that is, * P = (int * const *) 10; is invalid.
Original article: http://blog.csdn.net/supermegaboy/archive/2009/11/23/4854974.aspx.