Chapter 7th the singular human affairs of the C + + world
In the martial arts novels, the first into the martial arts of the head of the boy is always to meet a few odd people, a few different things, after the expert's guidance, experience a temper, can martial arts, from the novice growth as a master. In the C + + world, there are many other strange things. In the C + + world of learning, we are also looking forward to meet a few strange people, experience a few different things, and then from a C + + novice to grow into a C + + master it?
Martial arts in the strange people can meet and not to beg, but the C + + world in the strange people can be one by one introductions to you.
7.1 All hands are paper tigers: a thorough understanding of the pointer
What's the hardest in the C + + world? Pointer! What is the strongest in the C + + world? Pointer!
Pointers act as a special way to access data in the C + + world because of the flexibility of its use, which makes it powerful in the C + + world, but also because of its flexibility, making it the most difficult C + + skill for beginners. It is like an eye-catching white "big Tiger", although powerful but difficult to master control, good to be able to easily and efficiently solve the problem, but if the use of improper but it is likely to bring disastrous consequences for the program. Come today and bring down the pointer. This "paper tiger", thoroughly grasp the control pointer.
7.1.1 The operation of the pointer
In essence, pointers are a kind of data, but this kind of data is a bit special. The data we usually see is a variety of numeric data, such as literal data, and the pointer represents the memory address data. Since it is data, then nature involves the operation of the data. Like normal data, pointers can also participate in some operations, including arithmetic operations, relational operations, and assignment operations, and the arithmetic plus and minus operations of pointers are most commonly used.
If the value of a pointer is the address value of a memory location, then we say that the pointer points to this memory location. The addition and subtraction of pointers, in effect, is to deflect the pointer, pointing to another memory location. With this pointer deflection, you have the flexibility to access the memory near the start of the pointer. If the offset is continuous within a range, you can access the data to a contiguous area of memory through a pointer. For example, in section 3.6, the array name is actually the first address of the memory region where the array data is located, representing the starting position of the array in memory. You can traverse the entire array by assigning the first address to the pointer and then adding and subtraction the pointer, so that the pointer is deflected toward the other elements in the array. For example:
intnarray[3] = {1,2,3};//define an arrayint* Pindex = NArray;//assigns the starting address of the array to the pointer pindexcout<<"the address pointed to by the pointer is:"<<pIndex<<endl;//address to which the output pointer is pointingcout<<"The value of the data pointed to by the pointer is:"<<*pIndex<<endl;//output data at this locationPindex++;//adds a pointer to the next value in the arraycout<<"the address pointed to by the pointer is:"<<pIndex<<endl;//address to which the output pointer is pointingcout<<"The value of the data pointed to by the pointer is:"<<*pIndex<<endl;//Output Data
After this program executes, you can get the output like this:
The address pointed to by the pointer is: 0016fa38
The value of the data pointed to by the pointer is: 1
The address pointed to by the pointer is: 0016FA3C
The value of the data pointed to by the pointer is: 2
As you can see from the output, the Pindex pointer initially points to an address of 0016fa38, which is the first address of the Narray array. In other words, pindex points to the first data in the array, so the value of the output "*pindex" is 1. After adding 1 to the pointer, the pointer to the address becomes 0016fa3c, which offsets the direction of the address increment by 4 bytes, points to the second data in the array, and the value of the output "*pindex" naturally becomes 2.
It's very strange here that the pointer is a 1-plus operation, but how does the pointer-pointing address increase by 4 units? This is because the subtraction of the pointer is related to the true data type of the data it points to, and the pointer adds 1 or minus 1, which increases the address of the pointer or decreases the number of bytes of a corresponding data type. For example, the Pindex pointer in the above code, which can point to an int type of data, so its Add 1 operation will increase the address by 4 bytes, that is, the number of bytes of an int type. Similarly, for char* type pointers that can point to char type data, plus 1 offsets the pointer by 1 bytes, and with a double* type pointer that can point to a double type of data, plus 2 offsets the pointer by 16 (8*2) bytes. The pointer deflection flow is shown in 7-1.
Figure 7-1 Pointer 10:43:4010:43:41 deflection due to pointer operation
In addition to the subtraction arithmetic operations of pointers, there are also the relational operations of pointers. A pointer's relational operation usually uses "= =" or "! =" to determine whether two pointers of the same type are equal, that is, to determine whether they point to the same data on the same address, as a condition judgment statement in a condition or loop structure. For example:
intnarray[3] = {1,2,3};//define an arrayint* Pindex = NArray;//assigns the starting address of the array to the pointer pindexint* PEnd = NArray +3;//computes the end address of an array and assigns a value to Pend while(Pindex! = pEnd)//determines whether two pointers are equal in a while condition statement,//This is to determine if the current pointer has been deflected to the end address{cout<<*pIndex<<endl;//outputs the data that the current pointer points to//add 1 to the pointer,//offsets it to the next memory location, pointing to the next data in the array++Pindex; }
In the above code, the pointer pindex representing the current position of the array is compared with the pointer pend representing the end position, if not equal, meaning that Pindex has not been offset to the end of the array, the loop can continue to add 1 to the Pindex. Offset to the next position in the array, or, if equal, means that the pindex is exactly offset to the end of the array, and the while loop has traversed the entire array, and the loop can end.
In addition, pointer variables are often compared with the NULLPTR keyword to determine if the pointer has been first identified and pointed to the correct memory location, that is, to determine whether the pointer is valid. While we encourage the initialization of a pointer while defining it, sometimes there is no appropriate initial value to assign to the pointer when it is defined, but if it is kept at the very beginning of the random value, it can produce unpredictable results. In this case, we will assign this pointer to nullptr while defining the pointer, indicating that the pointer has not been initialized and is in an unusable state. The value of the pointer is no longer nullptr, and it means that the pointer is in a usable state when it is appropriate to assign a value to it that is really meaningful to the initialization of the pointer. Therefore, comparing nullptr with a pointer is a common means of judging whether the pointer is available. The following is a typical example:
int * PINT; // defines a pointer, at which point the pointer is a random value, pointing to a random memory address // assigns a pointer to nullptr, indicating that the pointer does not have an appropriate value, is in an unusable state pInt = // ... int narray[10 ] = {0 ";p int = NArray; // if (nullptr! = pInt) // Determine if the pointer has completed initialization is in the available state { pointer available , start using the pointer to access the data it points to }
Because the memory that it points to is directly accessible through a pointer, access to a pointer that has not yet been initialized can have very serious consequences. By comparing pointers with nullptr, you can effectively avoid illegal access to pointers. While this is not necessary in business logic, it can make our programs more robust, so this is also a very good programming experience.
7.1.2 flexible void type and void type pointers
C + + is a strongly typed language in which variables have their own data types and hold data of the corresponding type. For example, a variable of type int can hold a value of 1 and cannot hold a value of 1.1, it needs a variable of the corresponding double type to be saved. A variable of the corresponding data type holds the corresponding data, which would have been peaceful and well. However, in the C + + world There is a heterogeneous, that is the void type. In essence, the void type is not a true data type, and we cannot define a variable of type void. Void is more of an abstraction, and in programs, the void type is more used for "retouching" and "restricting" a function. For example, if a function has no return value, void can be used as the return value type of the function instead of the specific return value data type; If a function has no formal argument list, void is also used as its formal parameter, indicating that the function does not require any arguments.
Unlike the void type's "cosmetic" function, the void type pointer acts as a pointer to the abstract data, which can be a bridge between two pointers of a specific type. It is well known that when you assign a pointer to another pointer, if the two pointers are of the same type, you can assign them directly between the two pointers, and if the two pointers are of different types, you must convert the pointer type on the right of the assignment operator to the pointer type on the left by using the coercion type conversion, and then you can assign the value. For example:
int* PINT; // pointer to integer number float* pfloat; // pointer to floating- point number pInt = Pfloat; // Direct Assignment generates a compilation error PInt = (int*) pfloat; // to assign a value after casting a type
However, when you use the void type pointer, there is no problem with type conversions. The void type pointer appears slick, and any other type of pointer can be assigned directly to a void type pointer, for example:
void* pVoid; // void type pointer pVoid = PINT; // any other type of pointer can be assigned directly to the void type pointer pVoid = pfloat;
Although any type of pointer can be assigned directly to a void type pointer, this does not mean that the void type pointer can also be assigned directly to other types of pointers. To complete this assignment, you must undergo a forced type conversion so that "untyped" becomes "typed". For example:
PInt = (int// converts a void type pointer to an int type pointer by forcing type conversion pfloat = (float// Convert a void type pointer to a float type pointer by forcing a type conversion
Although a type of void pointer can be cast freely between other types of pointers by forcing a cast, the conversion should follow certain rules, and the other type that the void type pointer is converted to must match the true type of the data it points to. For example, to assign the int type pointer to the void type pointer, the void type pointer points to the INT type data, and if the void type pointer is cast to a double type pointer and accesses the data it points to, it is likely to get the wrong result. Because the void type pointer is not required for the memory data type it points to, it can be used to represent any type of pointer, and if the function can accept any type of pointer, its arguments should be declared as void type pointers. For example, a memory copy function:
void* memcpy (voidconstvoid* src, size_t len);
Here, any type of pointer can be passed into the memcpy () function as a parameter, which also truly embodies the meaning of the memory manipulation function, because it operates on only one piece of memory, regardless of the data type of the data on this piece of memory. If the parameter type of the memcpy () function is not a void type pointer, but is a char type pointer or other type pointer, then when you call the memcpy () function as a parameter with a different type of pointer, you need to convert the pointer type to accommodate its requirement for the parameter type. Entangled in specific data types, such a memcpy () function is clearly not a "pure, out-of-the-box" memory copy function.
Best practice: 11:06:42 Conversion of pointer types
While the conversion of pointer types may cause some unforeseen inconvenience, in some special cases, for example, a pointer needs to be converted to a pointer type required by a function parameter to achieve the purpose of invoking the function, the conversion of the pointer type becomes necessary.
In C + +, you can use C-style coercion type conversions for pointer-type conversions. The form is very simple, so you can change the pointer to a new type simply by indicating the new pointer type in the parentheses in front of the pointer. For example:
int* PINT; // int* Type pointer float* pfloat = (float// Force type converted to float* type pointer
Here, we cast it to a float type pointer by adding "(float*)" before the int type pointer pint. Although this type of coercion is more straightforward, it seems very rude. Because it allows us to convert between any type, regardless of whether the conversion is reasonable. In addition, this approach is difficult to identify in program statements, and code readers may ignore the type conversion statements.
To overcome these drawbacks of C-style type conversion, C + + introduces a new type conversion operator, static_cast. In the C-style type conversion, we use the following method for type conversion:
(type descriptor) expression
Now, using static_cast should be written like this:
static_cast< type descriptor > (expression)
Where the expression is the data of an existing old data type, and the type specifier is the new data type to be converted to. In use, the usage of static_cast is similar to that of the C-style type conversion. For example, when a variable of two int types is divided, in order for the result to be a more accurate decimal form, we need to convert one of the variables to a double type using a type conversion. If you convert in C-style type, you can write this:
int 2 ; int 3 ; double fRes = (double) nVal1)/nval2;
If you are using static_cast for type conversion, you should write this:
double fRes = static_cast<double
Use C + + style type conversions, which are easy to identify both for code readers and programs. We should try to avoid type conversions in our code, but if the type conversions are unavoidable, then using C + + style conversion to some extent can both increase the readability of the code and compensate for the loss of the type conversion.
Hello, C + + (40) 7.1 All hands are paper tigers: a thorough understanding of the pointer