The first chapter. The concept of pointers
A pointer is a special variable that is stored in a value that is interpreted as an address in memory. To figure out a pointer needs to figure out four aspects of the pointer: the type of the pointer, the type the pointer is pointing to, the value of the pointer, the memory area that the pointer points to, and the memory area occupied by the pointer itself. Let's explain separately.
Let's declare a few pointers to do the example:
Example one:
(1) int *ptr;
(2) Char *ptr;
(3) int **ptr;
(4) int (*PTR) [3];
(5) int * (*PTR) [4];
If you don't understand the last few examples, please refer to the articles I posted earlier << how to understand C and C
+ + Complex Type declaration >>.
1. The type of the pointer.
From a grammatical point of view, you simply remove the pointer name from the pointer declaration statement, and the rest is the type of pointer. This is the type that the pointer itself has. Let's look at the types of each pointer in example one:
(1) int *ptr; The type of the pointer is int *
(2) Char *ptr; The type of the pointer is char *
(3) int **ptr; The type of the pointer is int * *
(4) int (*PTR) [3]; The type of the pointer is int (*) [3]
(5) int * (*PTR) [4]; The type of the pointer is int * (*) [4]
What do you think? How easy is it to find the type of pointer?
2. The type that the pointer points to.
When you access the memory area that the pointer points to by using the pointer, the type that the pointer points to determines what the compiler treats the contents of that memory area as.
Syntactically, you simply remove the pointer's name from the pointer declaration statement and the pointer to the left of the name, and the rest is the type that the pointer points to. For example:
(1) int *ptr; The type that the pointer points to is int
(2) Char *ptr; The type that the pointer points to is Char
(3) int **ptr; The type that the pointer points to is int *
(4) int (*PTR) [3]; The type that the pointer is pointing to is int () [3]
(5) int * (*PTR) [4]; The type that the pointer is pointing to IS int * () [4]
In the arithmetic operation of a pointer, the type that the pointer points to has a significant effect.
The type of the pointer (that is, the type of the pointer itself) and the type to which the pointer points are two concepts. As you become more and more familiar with C, you will find that the concept of "type", which is mixed with pointers, is divided into "type of pointer" and "type of pointer", which is one of the key points in mastering pointers. I read a lot of books, found that some poorly written books, the two concepts of the pointer stirred together, so look at the book to contradictions, the more the more confused.
3. The value of the pointer, or the memory area or address that the pointer points to.
The value of a pointer is a numeric value stored by the pointer itself, which is treated as an address by the compiler, not as a generic value. In a 32-bit program, the value of all types of pointers is a 32-bit integer, because the memory address in the 32-bit program is all 32 bits long.
The memory area that the pointer points to is the memory area that begins with the memory address represented by the value of the pointer, and the length of the sizeof (the type to which the pointer points). Later, we say that the value of a pointer is XX, it is equivalent to say that the pointer to a piece of memory in the address of XX; we say a pointer to a block of memory is equivalent to saying that the value of the pointer is the first address of the area of memory.
The memory area pointed to by the pointer and the type pointed to by the pointer are two completely different concepts. In example one, the type that the pointer points to is already there, but because the pointer has not yet been initialized, the memory area it points to does not exist, or is meaningless.
Later, every time you encounter a pointer, you should ask: What is the type of the pointer? What type does the pointer point to? Where does the pointer point to?
4. The memory area occupied by the pointer itself.
How much memory does the pointer itself account for? You just use the function sizeof (the type of the pointer) to find out. In a 32-bit platform, the pointer itself occupies a length of 4 bytes.
The concept of memory occupied by the pointer itself is useful in determining whether a pointer expression is a left value.
Chapter Two. Arithmetic operations on pointers
The pointer can add or subtract an integer. The meaning of this operation of pointers is not the same as the addition and subtraction of the usual numerical values. For example:
Case TWO:
Copy Code code as follows:
1. Char a[20];
2. int *ptr=a;
...
...
3. ptr++;
In the example above, the type of pointer ptr is int*, which points to an int, which is initialized to point to reshape variable a. In the next 3rd sentence, pointer ptr is added 1, which is handled by the compiler: it adds the value of the pointer ptr to sizeof (int), and in the 32-bit program, it is added to 4. Because the address is in bytes, the address that PTR points to is increased by 4 bytes from the address of the original variable A to the high address direction.
Since the length of the char type is a byte, the original PTR is four bytes beginning with the unit No. 0 of array A, which points to four bytes starting with unit 4th in array A.
We can iterate over an array with a pointer and a loop, and see examples:
Example three:
Copy Code code as follows:
int array[20];
int *ptr=array;
...
The code that assigns values to an integer array is omitted here.
...
for (i=0;i<20;i++)
{
(*ptr) + +;
ptr++;
}
This example adds the value of each cell in an integer array to 1. Because each loop adds pointer ptr 1, each loop accesses the next cell of the array. Look again at the example:
Example four:
Copy Code code as follows:
1. Char a[20];
2. int *ptr=a;
...
...
3. ptr+=5;
In this example, the PTR is added with 5, and the compiler does this by adding the value of the pointer ptr to 5 by sizeof (int), and the 32-bit program adds 5 times 4=20. Because the unit of the address is byte, the current PTR points to an address that moves 20 bytes to the high address direction than the address pointed to by the 5 ptr. In this example, the PTR before 5 points to the four bytes starting at Unit No. 0 of array A, plus 5, and PTR already points beyond the legitimate range of array A. Although this situation will be problematic in application, it is grammatically acceptable. This also shows the flexibility of the pointer.
If, in the example above, PTR is subtracted by 5, the process is much the same, except that the value of PTR is subtracted from 5 by sizeof (int), and the new PTR points to an address that moves 20 bytes to the lower address direction than the address pointed to by the original PTR.
To sum up , after a pointer ptrold plus an integer n, the result is that a new pointer ptrnew,ptrnew the same type as the Ptrold, and the type that the ptrnew points to is the same type as the Ptrold. The Ptrnew value increases the byte of n by sizeof (the type to which ptrold points) than the Ptrold value. That is, the memory area that the ptrnew points to will move the n by sizeof (the type that the Ptrold points to) to a higher address direction than the memory point that ptrold points to. A pointer ptrold minus an integer n, the result is a new pointer ptrnew,ptrnew the same type as the Ptrold, and the type that the ptrnew points to is the same type as the Ptrold. The value of the ptrnew reduces the byte of n by sizeof (the type that the Ptrold points to) than the Ptrold value, that is, the memory area that the ptrnew points to will move the N times ptrold (the type that the sizeof points to) than the memory area to which the ptrold points to the lower address direction Bytes.
Chapter Three. Operators & and *
Here & is to take the address operator, * is ... The book is called an "indirect operator". The result of the &a operation is a pointer, the type of the pointer is the type of a *, the type of the pointer is the type of a, the address to which the pointer points, and that is the address of a. The results of *p's operations are all the same. In short, the result of *p is what p points to, something that has these characteristics: its type is the type that P points to, and the address it occupies is the address that P points to.
Example five:
Copy Code code as follows:
int a=12;
int b;
int *p;
int **ptr;
The result of the p=&a;//&a is a pointer, the type is int*, the type that points to is int, and the address that points to is the address of a.
The result of *p=24;//*p, where its type is int, the address it occupies is the address that P points to, and obviously *p is the variable A.
The result of the ptr=&p;//&p is a pointer, and the type of the pointer is the type of P plus a *, here is the int**. The type that the pointer points to is the type of P, which is int*. The address that the pointer points to is the address of the pointer P itself.
*ptr=&b;//*ptr is a pointer, and the result of the &b is also a pointer, and the two pointers are of the same type as the type they point to, so it's no problem to amp;b to give *ptr a value.
The result of the **ptr=34;//*ptr is the thing that PTR points to, here is a pointer, a second * operation on the pointer, and the result is a variable of type int.
Fourth chapter. An expression of the pointer.
The final result of an expression if it is a pointer, then the expression is called a pointer expression. Here are some examples of pointer expressions:
Example SIX:
Copy Code code as follows:
int a,b;
int array[10];
int *pa;
Pa=&a;//&a is a pointer expression.
int **PTR=&PA;//&PA is also a pointer expression.
Both *ptr=&b;//*ptr and &b are pointer expressions.
Pa=array;
pa++;//This is also a pointer expression.
Example Seven:
Copy Code code as follows:
Char *arr[20];
Char **parr=arr;//if arr as a pointer, arr is also a pointer expression
Char *str;
Str=*parr;//*parr is a pointer expression
str=* (parr+1);//* (parr+1) is a pointer expression
str=* (parr+2);//* (parr+2) is a pointer expression
Because the result of a pointer expression is a pointer, the pointer expression also has four elements that the pointer has: the type of the pointer, the type the pointer points to, the memory area the pointer points to, and the memory the pointer itself occupies.
Well, when a pointer expression's result pointer has explicitly had the memory occupied by the pointer itself, the pointer expression is a left value, otherwise it is not a left value. In Example seven, &a is not a left value because it does not yet occupy a clear memory. *ptr is a left value, because *ptr this pointer has occupied the memory, in fact, *ptr is the pointer pa, since the PA has its own position in memory, then *ptr certainly have its own position.
Fifth chapter. The relationship between arrays and pointers
If you don't quite understand the statement that declares the array, see the articles I posted earlier << how to understand complex type declarations >> of C and C + +. The array name of an array can actually be viewed as a pointer. Look at the following example:
Example eight:
Copy Code code as follows:
int array[10]={0,1,2,3,4,5,6,7,8,9},value;
...
...
value=array[0];//can also be written as: Value=*array;
value=array[3];//can also be written as: value=* (array+3);
value=array[4];//can also be written as: value=* (array+4);
In the example above, the array name array, in general, represents the array itself, the type is int [10], but if you think of an array as a pointer, it points to the No. 0 cell of the array, the type is int *, and the type of the array cell is the type of int. So it's not surprising that *array equals 0. Similarly, array+3 is a pointer to the 3rd cell of the array, so * (array+3) equals 3. Others, and so forth.
Example nine:
Copy Code code as follows:
Char *str[3]={
"Hello,this is a sample!",
"Hi,good morning."
"Hello World"
};
Char s[80];
strcpy (s,str[0]);//may also be written as strcpy (S,*STR);
strcpy (s,str[1]);//may also be written as strcpy (s,* (str+1));
strcpy (s,str[2]);//may also be written as strcpy (s,* (str+2));
In the example above, STR is an array of three cells, each of which is a pointer to a string. Referring to the pointer array named STR as a pointer, it points to unit No. 0 of the array, its type is char**, and the type it points to is char *.
*STR is also a pointer, its type is char*, the type it points to is char, and it points to an address that is the string "Hello,this is a sample!" The address of the first character, that is, the address of ' H '. Str+1 is also a pointer to unit 1th of the array, its type is char**, and the type it points to is char *.
* (str+1) is also a pointer, its type is char*, and the type it points to is Char, which points to "Hi,good morning." The first character ' H ', and so on.
Here's a summary of the array name problem. declares an array type array[n], the array name array has two meanings: first, it represents the entire array, its type is kind [n]; second, it is a pointer, the type of the pointer is type*, and the pointer is type. That is, the type of the array cell, the memory area that the pointer points to is the array number No. 0, which occupies a separate memory area, noting that it is different from the memory area occupied by unit No. 0. The value of the pointer cannot be modified, that is, an expression similar to array++ is wrong.
Array name array can play different roles in different expressions.
In the expression sizeof (array), the array name array represents the array itself, so the sizeof function then measured the size of the entire array.
In the expression *array, the array acts as a pointer, so the result of this expression is the value of the array number No. 0. sizeof (*array) measured the size of the array cell.
Expression array+n (where n=0,1,2, .....) , the array acts as a pointer, so the result of the array+n is a pointer, its type is type*, and it points to the type, which points to the array nth unit. So sizeof (ARRAY+N) is measured by the size of the pointer type.
Example Ten:
Copy Code code as follows:
int array[10];
int (*ptr) [10];
ptr=&array;
In the example above, PTR is a pointer whose type is int (*) [10], and the type that he points to is int [10], and we initialize it with the first address of the entire array. In the statement Ptr=&array, the array represents the arrays themselves.
The function sizeof () is mentioned in this section, so let me ask, does the sizeof (pointer name) measure the size of the pointer itself or the type the pointer is pointing to? The answer is the former. For example:
int (*ptr) [10];
In the 32-bit program, there are:
Copy Code code as follows:
sizeof (int (*) [10]) ==4
sizeof (int [10]) ==40
sizeof (PTR) ==4
In fact, sizeof (objects) measure the size of the object itself, not the size of the other type.
Sixth chapter. Relationship of pointer and struct type
You can declare a pointer to a struct-type object.
Example 11:
Copy Code code as follows:
struct MYSTRUCT
{
int A;
int b;
int C;
}
MyStruct ss={20,30,40};//declares the structure object SS and initializes the three members of the SS to 20,30 and 40.
MyStruct *ptr=&ss;//declares a pointer to the structure object SS. The type of it is
mystruct*, the type it points to is mystruct.
The int *pstr= (int*) &ss;//declares a pointer to the structure object SS. But its type is different from the type it points to and the PTR.
How can I access the three member variables of SS through pointer ptr?
Answer:
ptr->a;
ptr->b;
ptr->c;
And how can I access the three member variables of SS through the pointer pstr?
Answer:
*pstr;//visited member a of the SS.
* (pstr+1);//access to member B of the SS.
* (PSTR+2)//access to the SS member C.
Oh, although I have raised the above code in my msvc++6.0, but you know, this use of pstr to access the structure of members is not normal, in order to explain why not formal, let's see how to access the array of cells through the pointer:
Example 12:
int array[3]={35,56,37};
int *pa=array;
The method of accessing the three cells of array arrays via pointer PA is:
*pa;//visited unit No. 0,
* (PA+1)//access to Unit 1th
* (PA+2)//access to Unit 2nd
The format is the same as that of an irregular method that accesses a struct member through a pointer.
When all of the C + + compilers arrange array cells, they always store each array unit in a contiguous storage area, and there is no gap between the unit and the unit. However, when you store individual members of a struct object, in some kind of compilation environment, it may be necessary to add a number of "padding bytes" between the adjacent two members, which might require a word alignment or two-word alignment or something, which could result in several bytes of space between the members.
Therefore, in example 12, even if *PSTR accesses the first member variable A of the structure object SS, it is not guaranteed that * (PSTR+1) will be able to access struct member B. Because there may be a number of padding bytes between member A and member B, maybe * (pstr+1) Just accesses these padding bytes. This also proves the flexibility of the pointer. If your goal is to see if there are any padding bytes between the members of the structure, hey, that's a good way to go.
The correct way to access a struct member through a pointer should be a method using pointer ptr in Example 12.
Seventh chapter. The relationship between pointers and functions
You can declare a pointer as a pointer to a function.
Copy Code code as follows:
int fun1 (char*,int);
Int (*PFUN1) (char*,int);
PFUN1=FUN1;
....
....
int a= (*PFUN1) ("ABCDEFG", 7);//Call function via function pointer.
You can use pointers as parameters for functions. In a function call statement, you can use a pointer expression as an argument.
Example 13:
Copy Code code as follows:
int fun (char*);
int A;
Char str[]= "ABCDEFGHIJKLMN";
A=fun (str);
...
...
int Fun (char*s)
{
int num=0;
for (int i=0;i<strlen (s); i++)
{
num+=*s;s++;
}
return num;
}
The function fun in this example counts the sum of the ASCII values of each character in a string. As I said before, the name of the array is also a pointer. In a function call, when you pass Str as an argument to the formal parameter s, you actually pass the value of STR to the address that s,s points to, but the STR and s each occupy their respective storage space. The addition of 1 to s in a function does not mean that STR is added to the 1 operation at the same time.
Eighth chapter. Pointer type conversions
When we initialize a pointer or assign a value to a pointer, the left side of the assignment number is a pointer, and the right side of the assignment number is a pointer expression. In the example we cited earlier, in most cases the type of the pointer and the type of the pointer expression are the same, and the type that the pointer points to is the same type as the pointer expression.
Example 14:
Copy Code code as follows:
1. float f=12.3;
2. Float *fptr=&f;
3. int *p;
In the example above, what should we do if we want the pointer p to point to the real f? Do you use the following statement?
p=&f;
Wrong. Because the type of the pointer p is int*, it points to a type of int. The result of an expression &f is a pointer, the type of the pointer is float*, and the type it points to is float. The two are inconsistent, the direct assignment method is not. At least on my msvc++6.0, the assignment statement of the pointer requires the type of the assignment number to be the same, and the type is the same, and I haven't tried it on the other compilers, so let's try it. In order to achieve our goal, you need to do "force type conversions":
p= (int*) &f;
If there is a pointer p, we need to change its type and point to tyep* and type, then the syntax format is:
(type*) p;
The result of this coercion type conversion is a new pointer, the type of which is type*, the type it points to, the address to which the original pointer points. All the attributes of the original pointer p have not been modified.
If a function uses a pointer as a formal parameter, a pointer type conversion will also occur during the combination of the argument and the formal parameter of the function call statement.
Example 15:
Copy Code code as follows:
void Fun (char*);
int a=125,b;
Fun ((char*) &a);
...
...
void Fun (char*s)
{
char c;
c=* (s+3); * (s+3) =* (s+0); * (s+0) =c;
c=* (s+2); * (s+2) =* (s+1); * (s+1) =c;
}
Note that this is a 32-bit program, so the int type takes up four bytes and the char type is one byte. The function fun is to invert the order of four bytes of an integer. Have you noticed? In the function call statement, the result of the real amp;a is a pointer, which is of type int *, and it points to the type int. The type of the parameter's pointer is char*, which points to a type that is char. In this way, in the combination of the argument and the formal parameter, we must do a conversion from the int* type to the char* type. With this example, we can imagine the compiler's conversion process: The compiler constructs a temporary pointer char*temp, then executes temp= (char*) &a, and finally passes the value of temp to S. So the final result is that the type of S is char*, the type it points to is char, and the address it points to is the first address of a.
As we already know, the value of a pointer is the address that the pointer points to, and in a 32-bit program, the value of the pointer is actually a 32-bit integer. Is it possible to assign an integer to the pointer directly as the value of the pointer? Just like the following statement:
Copy Code code as follows:
unsigned int A;
Type *ptr;//type is a int,char or struct type, and so on.
...
...
a=20345686;
ptr=20345686;//Our aim is to make pointer ptr point to address 20345686 (decimal)
ptr=a;//Our aim is to make pointer ptr point to address 20345686 (decimal)
Compile it. It turns out that the following two statements are all wrong. So our purpose is not achieved? No, there is another way:
Copy Code code as follows:
unsigned int A;
Type *ptr;//type is a int,char or struct type, and so on.
...
...
A= a certain number, this number must represent a valid address;
Ptr= (type*) a;//hehe, this is OK.
Strictly speaking (type*) and pointer type conversion (TYPE*) is not the same. The meaning of this (type*) is to treat the value of unsigned integer a as an address.
The above emphasizes that the value of a must represent a valid address, otherwise, if you use PTR, there will be an illegal operation error.
Think about whether you can, in turn, take the address of the pointer to the value of the pointer as an integer. It's perfectly OK. The following example demonstrates taking a pointer's value as an integer and then assigning the integer as an address to a pointer:
Example 16:
Copy Code code as follows:
int a=123,b;
int *ptr=&a;
Char *str;
b= (int) ptr;//takes the value of the pointer ptr as an integer.
Str= (char*) b;//assigns the value of this integer to pointer str as an address.
Well, now that we know, you can take the value of a pointer out as an integer, or you can assign an integer value to a pointer as an address.
Nineth Chapter. Security issues with pointers
Look at the following example:
Example 17:
Copy Code code as follows:
Char s= ' a ';
int *ptr;
Ptr= (int*) &s;
*ptr=1298;
Pointer ptr is a pointer to a int* type that points to an int. The address it points to is the first address of S. In a 32-bit program, S takes up one byte, and the int type is four bytes. The last statement not only changes the byte of S, but also changes the three bytes in the high address direction of the S phase. What are these three bytes for? Only the compiler knows, and the person who writes the program is less likely to know. Maybe these three bytes store very important data, perhaps these three bytes is just a code of the program, and due to your sloppy application of the pointer, the value of these three bytes has been changed! This can cause a crash error. Let's look at one more example:
Example 18:
Copy Code code as follows:
1. Char A;
2. int *ptr=&a;
...
...
3. ptr++;
4. *ptr=115;
This example is fully compiled and can be executed. But did you see that? In the 3rd sentence, after adding 1 to the pointer ptr, PTR points to a storage area in the high address direction adjacent to the shaping variable A. What's in this storage area? We don't know. It's possible that it's a very important piece of data, maybe even a code. And the 4th sentence actually writes a data to this piece of storage area! This is a serious mistake. So when using pointers, the programmer must be very clear in mind: Where does my pointer point to.
When you use pointers to access arrays, you should also be careful not to go beyond the low-end and high-end bounds of the array, or else it will cause a similar error.
In coercion type conversion of pointers: ptr1= (type*) ptr2, if sizeof (type of PTR2) is greater than sizeof (type of PTR1), it is safe to use pointer ptr1 to access the store that the ptr2 points to. If the sizeof (PTR2 type) is less than the sizeof (PTR1 type), it is not safe to use pointer ptr1 to access the store to which the ptr2 points. As for why, the reader combines example Shilai think about, should understand.
Please write out the results of the following program:
Copy Code code as follows:
#include <stdio.h>
int *p;
PP (int a,int *b);
Main ()
{
int a=1,b=2,c=3;
p=&b;
PP (a+c,&b);
printf ("(1)%d%d%dn", a,b,*p);
}
PP (int a,int *b)
{int c=4;
*p=*b+c;
A=*p-c;
printf ("(2)%d%d%dn", a,*b,*p);
}