Deep understanding of C language pointer

Time:2022-1-2

A pointer is a data type
Pointer is also a variable that occupies memory space and is used to save memory address
Pointer is to tell the compiler to open up 4 bytes of storage space (32-bit system). No matter how many levels of pointers are the same

*P operation memory

When declaring a pointer, * indicates that the declared variable is a pointer
When the pointer is used, the * sign indicates the value in the memory space pointed to by the operation pointer
*P is equivalent to finding a piece of memory through the address (the value of the P variable); Then manipulate the memory
*P is assigned to the left of the equal sign (assigned to memory)
*P is put to the right of the equal sign to get the value (get the value from memory)

Pointer variable and the memory block it points to are two different concepts

  1. Assign P = 0x1111; Only the pointer variable value will be changed, and the indicated content will not be changed; p = p +1;“ p++
  2. Assign * p * P =’a ‘; It does not change the value of the pointer variable, but only the value of the memory block
  3. * P on the left of the equal sign indicates the assignment to the memory, and * P on the right of the equal sign indicates the value, which has completely different meanings
  4. Char * P on the left of the equal sign (handle the string, the pointer points to the first address of the string: char * P = buf; P + +;)
  5. Ensure that the memory block can be modified, that is, there are no wild pointers, pointing to the system memory area and modifying the data in the constant area

A pointer is a data type that refers to the data type of the memory space it points to

The pointer step size (P + +) is determined according to the data type of the resulting memory space

p++ = (unsigned char )p + sizeof(a);

Conclusion: the step size of the pointer is determined according to the type of memory space

Changing the value of a variable through * P / * P + + is the greatest significance of the existence of a pointer

Pointer variable and the memory block variable it points to
This is totally different

When a pointer points to a variable, it means that the address of a variable is not given to the pointer
The pointer actually records the address

*Conditions for indirect assignment of P

Three conditions need to be met

  1. 2 variables (usually one argument and one formal parameter)
  2. Establish a relationship, and assign the address of the argument to the formal parameter pointer
  3. *P parameter to modify the value of the argument indirectly
int num = 0; // Argument
int *p = NULL;
p = #
num = 1;
*p = 2; // Indirectly change the value of the argument through the * formal parameter

Application scenario of indirect assignment

Within a function:

*p1++ = *p2++;

Function call:

int getStr(int *a)
{
···
}

When the argument (n-1) of the function is called, the value of the pointer (n) changes

There are two ways to change the value of level 0 pointer (e.g. int num = 1)
There are two ways to change the value of level 1 pointer (e.g. char * P = 0x1111)
There are two ways to change the value of level 2 pointer (e.g. char * * PP = 0x1111)
When calling a function, the formal parameter is passed to the actual parameter, the address is taken with the actual parameter and passed to the formal parameter. In the called function, * P is used to change the actual parameter and pass out the operation result
Inference of indirect assignment = = > pointer as function parameter
The essence of pointers as function parameters

  • Change the value of level 0 pointer (argument) with level 1 pointer (formal parameter) (indirectly modify the in value of argument through * P)
  • Change the value of level 1 pointer (argument) with level 2 pointer (formal parameter) (indirectly modify the in value of argument through * P)
  • Change the value of level 2 pointer (argument) with level 3 pointer (formal parameter) (indirectly modify the in value of argument through * P)
  • Use N-level pointer (formal parameter) to change the value of n-1-level pointer (argument) (indirectly modify the in value of argument through * P)

In depth understanding of the pointer must be combined with the concept of four memory areas, and pay attention to the input and output characteristics of the pointer

####Main function and called function

  1. The calling function can transfer the heap area, stack area and global data memory address to the called function
  2. The called function can only return heap and global data

Memory allocation method

Pointers as function parameters have input and output characteristics

Application pointer must be combined with function call (pointer as function parameter)

Serial number Pointer stack Main function parameters Adjusted function parameters remarks
1 Level 1 pointer (for input) heap distribution use General disable
    Stack distribution use Commonly used
2 Level 1 pointer (output) Stack use Outgoing results Commonly used
3 Level 2 pointer (for input) heap distribution use General disable
    Stack distribution use Commonly used
4 Level 2 pointer (for output) heap use distribution Commonly used, not recommended, generally converted to 2
5 Level 3 pointer (for output) heap use distribution Not commonly used

Level 1 pointer for input

int showbuf(char *p);
int showArray(int *p; int num);

Level 1 pointer for output

int getLen(char *pFileName, int *pFileLen);

Level 2 pointer for input

int main(int argc, char *args[]);// Pointer array
int shouMatrix(int [3][4], int len);// 2D array string

Level 2 pointer for output

int getData(char **data, int *dataLen);
int getData_Free(void *data);
int getData_ Free(void **data);// Avoid wild pointers

Level 3 pointer for output

int getFileAllLine(char ***content, int *pLine);
int getFileAllLine_Free(cahr ***content, int *pLine);

Let’s go on with some dry goods

Complex type description

To understand pointers, there will be more or less complex types, so let me first introduce how to fully understand a complex type. It is actually very simple to understand a complex type. There will be many operators in a type. They also have priority like ordinary expressions, and their priority is the same as the operation priority. Therefore, I summarized the principle: start from the variable name, Analyze step by step according to operator priority combination Let’s start with simple types:

int p; // This is an ordinary integer variable
int *p; // First, start at P and combine it with * first, so p is a pointer, and then combine it with int, indicating that the type of content pointed to by the pointer is int So p is a pointer that returns integer data
int p[3]; // First, start at P, first combine with [], indicating that P is an array, and then combine with int, indicating that the elements in the array are integer, so p is an array composed of integer data
int *p[3]; // First, start from P and combine with []. Because its priority is higher than *, P is an array, and then combined with *, indicating that the elements in the array are pointer types, and then combined with int, indicating that the type of content pointed to by the pointer is integer, so p is an array composed of pointers that return integer data
int (*p)[3]; // First, start at P and combine it with *, indicating that P is a pointer, and then combine it with [] (with “()” can be ignored, just to change the priority), indicating that the content pointed to by the pointer is an array, and then combine it with int, indicating that the elements in the array are integer So p is a pointer to an array of integer data
int **p; // Start with P, first combine with * to say that P is a pointer, then combine with * to indicate that the element pointed to by the pointer is a pointer, and then combine with int to indicate that the element pointed to by the pointer is integer data Since secondary pointers and higher-level pointers are rarely used in complex types, we will not consider multi-level pointers for later more complex types, but only one-level pointers at most
int p(int); // Starting from P, first combine it with (), indicating that P is a function, and then enter () for analysis, indicating that the function has an integer variable parameter, and then combine it with the external int, indicating that the return value of the function is an integer data
Int (*p)(int); // Starting from P, first combine it with the pointer, indicating that P is a pointer, then with (), indicating that the pointer points to a function, and then combined with int in (), indicating that the function has an int parameter, and then combined with the outermost int, indicating that the return type of the function is an integer, so p is a pointer to a function with an integer parameter and the return type is an integer
int *(*p(int))[3]; // You can skip it first, regardless of this type. It is too complex. Start with P, combine it with (), indicating that P is a function, and then enter () and combine it with int, indicating that the function has an integer variable parameter, and then combine it with the external * to indicate that the function returns a pointer, and then go to the outermost layer, combine it with [] to indicate that the returned pointer points to an array, and then combine it with *, Indicates that the elements in the array are pointers, and then combined with int, indicating that the contents pointed to by the pointer are integer data So p is a function whose parameter is an integer data and returns a pointer variable pointing to an array of integer pointer variables

That’s about it. We have so many tasks. After understanding these types, other types are also a piece of cake for us. However, we generally don’t use too complex types, which will greatly reduce the readability of the program. Please use them with caution. These types are enough for us

1、 Elaborate pointer

A pointer is a special variable. The value stored in it is interpreted as an address in memory. To understand a pointer, we need to understand the four aspects of the pointer: the type of the pointer, the type pointed to by the pointer, the value of the pointer, or the memory area pointed to by the pointer, and the memory area occupied by the pointer itself. Let’s explain separately.

First declare several pointers and put them as examples:

Example 1:


(1)int*ptr; 
(2)char*ptr; 
(3)int**ptr; 
(4)int(*ptr)[3]; 
(5)int*(*ptr)[4];

1. Type of pointer

From a syntactic point of view, you just remove the pointer name from the pointer declaration statement, and the rest is the type of the pointer. This is the type of the pointer itself. Let’s take a look at the types of each pointer in example 1:
(1)int*ptr;// The type of pointer is int*
(2)char*ptr;// The type of pointer is char*
(3)int**ptr;// The type of pointer is int**
(4)int(*ptr)[3];// The type of pointer is int (*) [3]
(5)int*(*ptr)[4];// The type of pointer is int * (*) [4]
What about? Is it easy to find out the type of pointer?

2. Type pointed by the pointer

When you access the memory area pointed to by the pointer, the type pointed to by the pointer determines what the compiler will treat the contents of that memory area.
Grammatically, you only need to remove the pointer name in the pointer declaration statement and the pointer declarator * to the left of the name, and the rest is the type pointed to by the pointer. For example:
(1)int*ptr; // The type pointed to by the pointer is int
(2)char*ptr; // The type pointed to by the pointer is char
(3)int**ptr; // The type pointed to by the pointer is int*
(4)int(*ptr)[3]; // The type pointed to by the pointer is int() [3]
(5)int*(*ptr)[4]; // The type pointed to by the pointer is int * () [4]

In the arithmetic operation of pointer, the type pointed to by pointer plays a great role.
The type of pointer (that is, the type of pointer itself) and the type pointed to by the pointer are two concepts. When you become more and more familiar with C, you will find that dividing the concept of “type” mixed with pointer into two concepts of “type of pointer” and “type pointed to by pointer” is one of the key points to master pointer. I read a lot of books and found that in some poorly written books, the two concepts of pointer were mixed together. Therefore, when I read the books, I was contradictory and became more and more confused.

3. The value of the pointer — or the memory area or address pointed to by the pointer

The value of the pointer is the value stored in the pointer itself. This value will be regarded by the compiler as an address rather than a general value. In 32-bit programs, the value of all types of pointers is a 32-bit integer, because the memory addresses in 32-bit programs are all 32 bits long. The memory area pointed to by the pointer is a memory area with a length of Si zeof (the type pointed to by the pointer), starting from the memory address represented by the value of the pointer. Later, when we say that the value of a pointer is XX, it is equivalent to saying that the pointer points to a memory area with XX as the first address; When we say that a pointer points to a memory area, we mean that the value of the pointer is the first address of the memory area. The memory area pointed to by the pointer and the type pointed to by the pointer are two completely different concepts. In example 1, the type pointed to by the pointer already exists, but the memory area pointed to by the pointer does not exist or is meaningless because the pointer has not been initialized.
In the future, whenever you encounter a pointer, you should ask: what is the type of this pointer? What type does the pointer refer to? Where does the pointer point? (key points)

4 the memory area occupied by the pointer itself

How much memory does the pointer itself occupy? You just need to test it with the function sizeof (pointer type). On 32-bit platforms, the pointer itself occupies a length of 4 bytes. The concept of memory occupied by the pointer itself is very useful in judging whether a pointer expression (which will be explained later) is an lvalue.

2、 Arithmetic operation of pointer

The pointer can add or subtract an integer. The meaning of this operation of the pointer is different from that of the usual addition and subtraction of numerical values, which is in units. For example:
Example 2:

char a[20]; 
 int *ptr=(int *)a; // Casting does not change the type of A 
 ptr++;

In the above example, the type of pointer PTR is int *, the type it points to is int, and it is initialized to point to integer variable a. In the next third sentence, the pointer PTR is added with 1. The compiler handles this as follows: it adds sizeof (int) to the value of pointer PTR, and 4 to 32-bit programs, because int occupies 4 bytes in 32-bit programs. Since the address is in bytes, the address pointed by PTR is increased by 4 bytes from the address of the original variable a to the high address. Since the length of char type is one byte, the original PTR points to the four bytes starting from unit 0 of array A. at this time, it points to the four bytes starting from unit 4 of array a. We can traverse an array with a pointer and a loop. See the example:

Example 3:


 int array[20]={0}; 
  int *ptr=array; 
  for(i=0;i<20;i++) 
  { 
    (*ptr)++; 
    ptr++; 
  } 

This example adds 1 to the value of each cell in an integer array. Since the pointer PTR is added by one cell in each loop, each loop can access the next cell of the array.

Take another example:

Example 4:


char a[20]="You_are_a_girl"; 
int *ptr=(int *)a; 
ptr+=5; 

In this example, PTR is added with 5. The compiler handles this as follows: add 5 times sizeof (int) to the value of pointer PTR, and 5 times 4 = 20 in 32-bit programs. Since the unit of address is byte, the address pointed to by the current PTR moves 20 bytes to the high address direction compared with the address pointed to by the PTR after adding 5.
In this example, the PTR before adding 5 points to the first four bytes of unit 0 of array A. after adding 5, the PTR has pointed outside the legal range of array a. Although this situation will cause problems in application, it is grammatically acceptable. This also shows the flexibility of the pointer. If PTR is subtracted by 5 in the above example, the processing process is similar, except that the value of PTR is subtracted by 5 times sizeof (int), and the address pointed to by the new PTR will move 20 bytes lower than the address pointed to by the original PTR.
Allow me another example

Example 5:


#include<stdio.h> 
  int main() 
  { 
    char a[20]=" You_are_a_girl"; 
    char *p=a; 
    char **ptr=&p; 
    //printf("p=%d\n",p); 
    //printf("ptr=%d\n",ptr); 
    //printf("*ptr=%d\n",*ptr); 
    printf("**ptr=%c\n",**ptr); 
    ptr++; 
    //printf("ptr=%d\n",ptr); 
    //printf("*ptr=%d\n",*ptr); 
    printf("**ptr=%c\n",**ptr); 
  } 

Myth 1: the output answers are y and o

Misunderstanding: PTR is a secondary pointer to char when PTR + + is executed; It will add a sizeof (char) to the pointer, so the above result is output. This may only be the result of a few people
Myth 2: the output answers are y and A. misunderstanding: PTR points to a char * type when PTR + + is executed; When, the pointer will be added with a sizeof (char *) (some people may think that this value is 1, and then they will get the answer of misunderstanding 1. This value should be 4. Refer to the previous content), that is & P + 4; Doesn’t a value operation point to the fifth element in the array? Isn’t the output the fifth element in the array? The answer is No
Positive solution: the type of PTR is char *, the type pointed to is a char * type, and the address pointed to is the address of P (& P). When PTR + + is executed; The pointer will be added with a sizeof (char *), i.e. & P + 4; Where does * (& P + 4) point? Ask God, or will he tell you where it is? So the final output will be a random value, perhaps an illegal operation

To sum up:

After a pointer ptrold adds (subtracts) an integer n, the result is a new pointer ptrnew. The type of ptrnew is the same as that of ptrold, and the type pointed to by ptrnew is the same as that pointed to by ptrold. The value of ptrnew will increase (decrease) by N times sizeof (the type ptrold points to) bytes than the value of ptrold. That is, the memory area pointed to by ptrnew moves n times sizeof (the type pointed to by ptrold) bytes higher (lower) than the memory area pointed to by ptrold. Pointer and pointer addition and subtraction: two pointers cannot be added, which is illegal, because after addition, the result points to an unknown place and is meaningless. Two pointers can be subtracted, but they must be of the same type. They are generally used in arrays. I won’t say more.

3、 Operators & and*

Here & is the address operator and * is the indirect operator.
&The operation result of a is a pointer. The type of the pointer is the type of a plus a *, the type pointed to by the pointer is the type of a, and the address pointed to by the pointer is the address of A.
*The results of P are diverse. In short, the result of * P is what P points to. This thing has these characteristics: its type is the type pointed to by P, and the address it occupies is the address pointed to by P.

Example 6:

int a=12; int b; int *p; int **ptr; 
p=&a; //& The result of a is a pointer, the type is int *, and the type pointed to is 
//Int, the address pointed to is the address of A. 
*p=24; //* The result of P, where its type is int and its address is 
//The address pointed to by P, obviously, * P is the variable a. 
ptr=&p; //& The result of P is a pointer whose type is the type of P Plus a *, 
//Here is int * *. The type pointed to by the pointer is the type of P, which 
//Inside is int *. The address pointed to by the pointer is the address of the pointer P itself. 
*ptr=&b; //* PTR is a pointer, the result of & B is also a pointer, and these two pointers 
//The type of is the same as the type pointed to, so use & B to assign * PTR 
//Value is no problem. 
**ptr=34; //* The result of PTR is what PTR points to, which is a pointer here, 
//Do another * operation on this pointer, and the result is a variable of type int.

4、 Pointer expression

If the result of an expression is a pointer, the expression is called a pointer expression.
Here are some examples of pointer expressions:
Example 7:

int a,b; 
int array[10]; 
int *pa; 
pa=&a; //& A is a pointer expression. 
Int **ptr=&pa; //& PA is also a pointer expression. 
*ptr=&b; //* PTR and &b are pointer expressions. 
pa=array; 
pa++; // This is also a pointer expression.

Example 8:

char *arr[20]; 
char **parr=arr; // If you think of 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

Since the result of the pointer expression is a pointer, the pointer expression also has four elements of the pointer: the type of the pointer, the type pointed to by the pointer, the memory area pointed to by the pointer, and the memory occupied by the pointer itself.
Well, when the result pointer of a pointer expression clearly has the memory occupied by the pointer itself, the pointer expression is an lvalue, otherwise it is not an lvalue. In Example 7, & A is not an lvalue because it does not occupy explicit memory* PTR is an lvalue, because the pointer * PTR has occupied memory. In fact, * PTR is the pointer Pa. since PA has its own position in memory, of course, * PTR also has its own position.

5、 Relationship between array and pointer

The array name of an array can actually be regarded as a pointer. See the following example:
Example 9:

int array[10]={0,1,2,3,4,5,6,7,8,9},value; 
value=array[0]; // It can also be written as: value = * array; 
value=array[3]; // It can also be written as: value = * (array + 3); 
value=array[4]; // It can also be written as: value = * (array + 4);

In the above example, generally speaking, the array name array represents the array itself and the type is int [10], but if array is regarded as a pointer, it points to the 0th cell of the array, the type is int * and the type pointed to is the type of array cell, that is, int. Therefore, it is not surprising that * array is equal to 0. Similarly, array + 3 is a pointer to the third cell of the array, so * (array + 3) is equal to 3. Others, and so on.
Example 10:

char *str[3]={ 
  "Hello,thisisasample!", 
  "Hi,goodmorning.", 
  "Helloworld" 
}; 
char s[80]; 
strcpy(s,str[0]); // It can also be written as strcpy (s, * STR); 
strcpy(s,str[1]); // It can also be written as strcpy (s, * (STR + 1)); 
strcpy(s,str[2]); // It can also be written as strcpy (s, * (STR + 2));

In the above example, STR is a three cell array. Each cell of the array is a pointer, and these pointers point to a string. If the pointer array name STR is taken as a pointer, it points to cell 0 of the array, its type is char * *, and its type is char *.
*STR is also a pointer. Its type is char *, the type it points to is char, and the address it points to is the string “Hello, this is a sample!” The address of the first character of, that is, the address of ‘H’. Note: the string is equivalent to an array, which is stored in the form of an array in memory, but the string is an array constant, the content cannot be changed, and can only be an R-value If it is regarded as a pointer, it is both a constant pointer and a pointer constant
STR + 1 is also a pointer. It points to cell 1 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 *, the type it points to is char, and it points to “Hi, GoodMorning.” First character of ‘H’

The following is a summary of the array name of the array (the array is also stored in the array):

If an array type array [n] is declared, the array name array has two meanings:
First, it represents the entire array, and its type is type [n];
Second, it is a constant pointer. The type of the pointer is type *. The type pointed to by the pointer is type, that is, the type of array unit. The memory area pointed to by the pointer is unit 0 of the array. The pointer occupies a separate memory area. Note that it is different from the memory area occupied by unit 0 of the array. The value of the pointer cannot be modified, that is, an expression similar to array + + is wrong. The 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 measures the size of the entire array.
In the expression * array, array acts as a pointer, so the result of this expression is the value of cell 0 of the array. Sizeof (* array) measures the size of an array cell.
Expression array + n (where n = 0, 1, 2,…) In, array acts as a pointer, so the result of array + n is a pointer, its type is type *, the type it points to is type, and it points to cell n of the array. Therefore, sizeof (array + n) measures the size of the pointer type. In a 32-bit program, the result is 4
Example 11:


int array[10]; 
int (*ptr)[10]; 
ptr=&array;

In the above example, PTR is a pointer. Its type is int (*) [10], and the type it points to is int [10]. We initialize it with the first address of the whole array. In the statement PTR = & array, array represents the array itself.
The function sizeof () is mentioned in this section. Let me ask whether sizeof (pointer name) measures the size of the pointer’s own type or the size of the type pointed to by the pointer?
The answer is the former. For example:

int(*ptr)[10];
Then in the 32-bit program, there are:
sizeof(int(*)[10])==4
sizeof(int[10])==40
sizeof(ptr)==4

In fact, sizeof measures the size of the object’s own type, not any other type.

6、 Relationship between pointer and structure type

You can declare a pointer to a structure type object.
Example 12:

struct MyStruct 
  { 
    int a; 
    int b; 
    int c; 
  }; 
  struct MyStruct ss={20,30,40}; 
  //The structure object SS is declared, and the members of SS are initialized to 20, 30 and 40. 
  struct MyStruct *ptr=&ss; 
  //A pointer to the structure object SS is declared. Its type is 
  //Mystruct *, the type it points to is mystruct. 
  int *pstr=(int*)&ss; 
  //A pointer to the structure object SS is declared. But PSTR and 
  //It is pointed to a different type PTR.

How do I access the three member variables of SS through the pointer PTR?
answer:

ptr->a; // Point to an operator, or you can use these (* PTR) a. The former is recommended
ptr->b;
ptr->c;

How can I access the three member variables of SS through the pointer PSTR?
answer:

*pstr; // Visited member a of SS.
*(pstr+1); // Visited member B of SS.
*(PSTR + 2) / / accessed member C of SS.

Although I raised the above code in my MSVC + + 6.0, you should know that it is not normal to use PSTR to access structure members. In order to explain why it is not normal, let’s see how to access each unit of the array through pointers: (replace the structure with an array)

Example 13:

int array[3]={35,56,37}; 
int *pa=array; 
//The method to access the three cells of the array through the pointer PA is as follows: 
*pa; // Unit 0 accessed 
*(pa+1); // Visited unit 1 
*(pa+2); // Visited unit 2

In terms of format, it is the same as that of informal methods that access structure members through pointers.
When arranging array cells, all C / C + + compilers always store each array cell in a continuous storage area, and there is no gap between cells. However, when storing each member of the structure object, in a certain compilation environment, word alignment, double word alignment or other alignment may be required. Several “fill bytes” need to be added between two adjacent members, resulting in several byte gaps between each member.
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) can access the structure member B. Because there may be some 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 filled bytes between structure members, hey, this is a good way.
However, the correct way for pointers to access structure members should be to use pointer PTR as in example 12.

7、 Relationship between pointer and function

You can declare a pointer as a pointer to a function.

int fun1(char *,int);
int (*pfun1)(char *,int);
pfun1=fun1;
int a=(*pfun1)(“abcdefg”,7); // Call a function through a function pointer.

You can take a pointer as a formal parameter of a function. In function call statements, pointer expressions can be used as arguments.
Example 14:


int array[20]={0}; 
  int *ptr=array; 
  for(i=0;i<20;i++) 
  { 
    (*ptr)++; 
    ptr++; 
  } 

The function fun in this example counts the sum of ASCII code values of each character in a string. As mentioned earlier, the name of an array is also a pointer. In a function call, when STR is passed as an argument to the formal parameter s, the value of STR is actually passed to S. the address pointed to by s is consistent with the address pointed to by STR, but STR and s occupy their own storage space. Adding 1 to s in the function body does not mean adding 1 to STR at the same time.

8、 Pointer type conversion

When we initialize a pointer or assign a value to a pointer, there is a pointer to the left of the assignment number and a pointer expression to the right of the assignment number. In our previous examples, in most cases, the type of pointer is the same as that of pointer expression, and the type pointed to by pointer is the same as that pointed to by pointer expression.
Fifteen cases:


float f=12.3; 
float *fptr=&f; 
int *p;

In the above example, what should we do if we want the pointer p to point to the real number f?
Do you use the following statement?
p=&f;
incorrect. Because the type of pointer P is int *, the type it points to is int. The result of the expression &f is a pointer, the type of the pointer is float *, and the type it points to is float.
If the two are inconsistent, the direct assignment method will not work. At least on my MSVC + + 6.0, the assignment statement of the pointer requires that the types on both sides of the assignment number are the same, and the types pointed to are the same. I haven’t tried on other compilers, so you can try. To achieve our goal, we need to cast:
p=(int*)&f;
If there is a pointer P, we need to change its type and the type it points to to tyep * type. Then the syntax format is: (type *) p;
The result of this forced type conversion is a new pointer. The type of the new pointer is type *, the type it points to is type, and the address it points to is the address pointed to by the original pointer.
All properties of the original pointer P have not been modified. (remember)
If a function uses a pointer as a formal parameter, the type must be consistent during the combination of the arguments and formal parameters of the function call statement, otherwise it needs to be cast
Example 16:


 void fun(char*); 
  int a=125,b; 
  fun((char*)&a); 
  void fun(char*s) 
  { 
    charc; 
    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 int type takes up four bytes and char type takes up one byte. The function fun reverses the order of the four bytes of an integer. Did you notice? In the function call statement, the result of the argument &a is a pointer, its type is int *, and the type it points to is int. The type of formal parameter pointer is char *, and the type it points to is char. Thus, during the combination of arguments and formal parameters, we must convert from int * type to char * type.

Combined with this example, we can do this

Imagine the compiler’s conversion process: the compiler first 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: 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.
We already know that the value of the pointer is the address pointed to by the pointer. In 32-bit programs, the value of the pointer is actually a 32-bit integer.
Can an integer be directly assigned to the pointer as the value of the pointer? Like the following statement:

unsigned int a; 
  TYPE *ptr; // Type is int, char or structure type, etc. 
  a=20345686; 
  ptr=20345686; // Our purpose is to make the pointer PTR point to address 20345686 
   
  ptr=a; // Our purpose is to make the pointer PTR point to address 20345686 
  //Compile it. It turns out that the last two statements are all wrong. So our goal can't be achieved? No, there are other ways: 
  unsigned int a; 
  TYPE *ptr; // Type is int, char or structure type, etc. 
  A = n // N must represent a legal address; 
  ptr=(TYPE*)a; // Hehe, that's all right.

The type in type * is not exactly the same as that in type *. Here (type *) means to treat the value of the unsigned integer a as an address. The above emphasizes that the value of a must represent a legal address, otherwise, illegal operation errors will occur when you use PTR. Think about whether you can take the address pointed to by the pointer, that is, the value of the pointer, as an integer. Absolutely. The following example demonstrates taking the value of a pointer as an integer, and then assigning the integer as an address to a pointer:
Example 17:

int a=123,b; 
int *ptr=&a; 
char *str; 
b=(int)ptr; // Take the value of pointer PTR as an integer. 
str=(char*)b; // Assign the value of this integer to the pointer STR as an address

Now we know that we can take the value of the pointer as an integer, or assign an integer value as an address to a pointer.

9、 Pointer security

Take the following example:
Example 18:


char s='a'; 
int *ptr; 
ptr=(int *)&s; 
*ptr=1298;

The pointer PTR is a pointer of type int * and the type it points to is int. The address it points to is the first address of S. In 32-bit programs, s takes up one byte and int type takes up four bytes. The last statement not only changes one byte occupied by s, but also changes three bytes in the high address direction adjacent to s. What are these three bytes for? Only the compiler knows, and the person who writes the program is unlikely to know. Maybe these three bytes store very important data, maybe these three bytes are just a piece of code of the program, and because of your careless application of the pointer, the value of these three bytes has been changed! This can cause a crash error.
Let’s take another example:
Example 19:


char a; 
int *ptr=&a; 
ptr++; 
*ptr=115;

The example can be compiled and executed. But see? In the third sentence, after the pointer PTR is added by 1, 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 may be a very important data, or even a piece of code.
And the fourth sentence actually writes a data into this storage area! This is a serious mistake. So when using pointers, programmers must be very clear: where does my pointer point. When accessing an array with a pointer, be careful not to exceed the low-end and high-end boundaries of the array, otherwise similar errors will be caused.
In the pointer cast: 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 storage area pointed to by ptr2. If sizeof (type of ptr2) is less than sizeof (type of PTR1), it is not safe to use the pointer PTR1 to access the storage area pointed to by ptr2. As for why, the reader will understand if he thinks about it in combination with example 18.