Article directory
foreword
basic goal
- Why have pointers?
- What is the difference between a pointer and a pointer variable?
- Difference between pointer and array?
1. Pointer
1. Understanding of pointers
- Imagine you are in a room in a building like this
- prerequisite
- All houses have no house number
- You don't know where you are - the floor
- The building is airtight and soundproofed
- You can only stay in the house and cannot move.
- Send a message to your X friends - come and play with me!
Question: How did your X friend find you? 1
into computer memory
- As a programmer you want to modify a variable.
- If: the computer does not know where this variable is?
- The computer can only iterate through the search - extremely inefficient!
Therefore: the house number of a building is like the identification of a memory variable—the address, and the address (house number) can greatly improve the efficiency of finding variables (houses)!
Replenish
- The smallest storage unit generally used by computers - byte
- 4GB=212MB=222KB=232 byte
- 8bit = 1byte, 1bit stores 0/1
- Therefore: to distinguish each byte of 4GB requires at least 32 digits (binary) - 32bit to store, that is, 4 bytes.
Question: Do the addresses have to be stored? 2 Simple understanding: Special processing
is done in the CPU . When the variable in the specified location of the memory transmits information (electrical signal) to the CPU, the CPU will convert the electrical signal into a digital signal (this The address of the variable), and then return to the memory through the address bus .
- Why have pointers?
2. Pointers and pointer variables
Dimensions of value inquiry
- Value attribute: the content stored in the variable
- class attribute: the type of the value
- Space attribute: whether there is space for storage
Constants and Variables
- Constants only have value attributes , not space attributes .
- Variables have value attributes and also have space attributes .
Substitution: The pointer is a constant, the pointer variable is a variable, and the value stored in it is a pointer .
example:
#include<stdio.h>
int main()
{
int a = 10;
int* p = &a;
*p = 9;
p = NULL;
printf("%d\n", a);
*&a = 12;
//相当于a = 12;
int b = *p;
//等于int b = a;
printf("%d\n", a);
return 0;
}
Code Analysis Diagram:
Therefore:
- Pointer variables are not exactly equivalent to pointers
- Pointers are addresses - values
- Pointer variables are used to store addresses
- Dereferencing a pointer variable uses its content - address/pointer
- When a pointer variable (alone) is an lvalue, it uses the space of the pointer variable.
- Difference between pointer and pointer variable
3. Forced transfer of the pointer
Let's look at an interesting piece of code:
int main()
{
int* p = NULL;
p = (int*)&p;
*p = (int)p;
printf("%p %p", (int*)*p, p);
return 0;
}
- (int*)&p, take out the address of p (second-level pointer), and force it into a first-level pointer, so that the types on both sides are the same.
- *p = (int)p, convert the type of p to an integer, and assign it to *p—the type is int, and the types on both sides are the same.
- %p can only print the value of the pointer type, otherwise a warning will be reported!
Look at the same piece of code again:
#include<stddef.h>
int main()
{
float* p = NULL;
p = (float*)&p;
*p = (float)p;
printf("%p %p", (float*)*p, p);
return 0;
}
in conclusion:Report an error!
This is like:You are already in two worlds with you, and you still lie to yourself knowing that it is impossible. But the results do not deceive themselves.
The pointer essentially stores a 32-digit number (integer family), which cannot be converted into a floating-point number (floating-point family). It is impossible to convert between the two worlds!
- The pointer type cannot be forced to a floating point number!
4. void pointer
- Used to receive sibling pointers of any type
- The void pointer cannot be dereferenced (Vs2019)
- Usually used in conjunction with forced forwarding
- Mainly used in general type functions - qsort
5. Null pointer
- NULL is a macro
- The header file where it is located - stddef.h .
- NULL is also defined in the header file correct.h included in the header file stdio.h we usually use
- #define NULL ((void *)0) - cast 0 to void* type
- The void* type cannot be dereferenced! ——*(NULL) will directly report an error from the syntax
- Supplement: *((char*)0)=1; will not report a grammatical error , but the code will crash!
Normal exit:
Abnormal exit:
6. Multi-level pointer
- Pointer variables also have addresses , so pointer variables can also be modified by their higher-level pointers!
- Modify the lower-level pointer pointed to by the multi-level pointer or the content pointed to by the lower-level pointer
Read the code:
This code cannot be executed normally! We only need to understand the meaning of each code!
Think about each code:
- Is the lvalue or rvalue of the variable being used
- modified content
int main()
{
int a = 10;
int* p = &a;
int** pp = &p;
p = 100; //1
*p = 100; //2
pp = 100; //3
*pp = 100;//4
**pp = 100;//5
return 0;
}
- Lvalue, the space of a pointer variable
- Rvalue, the content pointed to by the first-level pointer variable, and the space of the integer variable .
- lvalue, space for secondary variables
- Rvalue, the content pointed to by the secondary pointer variable , the space of the primary pointer variable
- Rvalue, the content pointed to by the second-level pointer variable , the content of the first-level pointer variable, and the space of the integer variable
7. Array pointer
- To store pointers to arrays,
we first need to know what type of array is?
int main()
{
int arr[10] = {
1,2,3,4,5,6,7,8,9,10};
return 0;
}
- Remove the variable name is its type - int[10]
- &arr takes out the type of the entire element
- Pointer description: its type int[10]
- The pointer variable name follows the naming of the array
- Without knowing the grammar we should write:
int *p[10]
- But [ ] has a higher priority than * so it should be enclosed in brackets
- So the correct way to write it is:
int(*p)[10]
8. Function pointer
illustrate:Usually we only call functions, as if we have never touched function pointers.
Let's start with functions!
#include <stdio.h>
void fun()
{
printf("hello\n");
}
int main()
{
fun();//这是一个简单的调用
//这一个语句可以拆分成两部分fun和()
//fun是函数,()是函数调用操作符
//那fun呢?
fun;
//&fun呢?
&fun;
return 0;
}
- The fun here can be understood as a variable
- fun is a variable, then you can take the address
- So how to express the type of &fun?
If we want to describe a pointer type, we must first describe its uniqueness.
The uniqueness of the function:
- function return type
- function parameters
so we can write:
//void/*返回类型*/ ()/*参数*/ *p = &fun;//这样写看起来是正确的,但跟语法还差了一点
//void fun ();//如果把fun看成变量的话,那指针变量的位置也应该出现在fun处
//因此:void *p()= &fun;离目标还差一点——优先级:()的优先级高于*,要说明p为指针得
//先把p与*号集合起来
//所以正确且符合语法的规范
void (*p)()=&fun;
Actually:
fun is equivalent to &fun
Therefore: it is also correct to write
void (*p)()=fun;
What about the type of function pointer?
Remove the variable name is the pointer type.
so the type of this function pointer is:
void (*)()
How to understand:
improve:
(*(void(*)())0))() ;//如何理解此代码
Disassembly code:
(void(*)())0
This is going to0 value cast to function pointer, the function pointer type mentioned above- will
(void(*)())0
be treated as a function pointer p - Substitute into the code we want to understand:
*(*(void(*)())0))()
- Problem conversion understanding:
(* p )()
, obviously this is a function call. - Conclusion: This is to convert the 0 value into a function pointer, then dereference the function pointer, and call the function at the 0 value!
void(*signal(int,void(*)(int)))(int);//如何理解这样一段代码?
To understand such a piece of code, we must first understand how to express the function declaration of the function pointer as the return value ?
suppose
- A function (fun) takes no arguments
- The return type of the function is void(*)(int)
Due to function composition:
Following the general idea we might write:
void(*)(int)fun();
//甚至会写出函数指针当做函数声明
void(*fun)();
- The function body is a whole - the function body of the function declaration does not carry the implementation code
- Therefore: the function pointer as the return value shouldPut the function body next to the * sign of the function pointer
- So it should be written like this: void(*fun());
Then we also need to understand how to represent the function declaration with the function pointer as a parameter ?
- A function (fun2) with parameters: int and void(*)(int)
- The return type of the function is void
as we think it should be written like this:void fun2(int,void(*)(int));
That's right, that's right
Finally, we change the return type of fun2 here to: void(*)(int)
according to the idea of fun above: put the function body on the right side of * and it becomes:
void(*fun2(int,void(*)(int)))(int);
the last function name is what we need to understand The functions are exactly the same .
9. A pointer to an array of function pointers
void (*((*p)[3]))() = {
NULL };
- inside out
- P is first combined with * to indicate that it is a pointer
- Then combine it with [3] outside to explain: the pointer stores the array
- Then combine with void(*)() to explain: the type in the array is a function pointer
- The content pointed to by the function pointer is the return value is void, parameter: none
10. Wild Pointer
- pointers accessed without permission
- May or may not be accessible
- The content of the accessed space may or may not be modified.
- Wild pointers prevent access and modification to the knowledge of the operating system.
Example
cannot access:
#include<stdio.h>
int main()
{
int* p = (int*)1;
printf("%d", *p);
return 0;
}
result:
Cannot be modified:
#include<stdio.h>
int main()
{
int* p = (int*)1;
*p = 1;
return 0;
}
result:
11. Pointer operations
- The number stored in the pointer is essentially an integer-sized data that can be compared.
- Pointer data is a 32-bit data greater than or equal to 0
- Adding 1 to the pointer adds the size of the pointed type
- The pointer minus the pointer refers to the number of its adjacent elements (premise: the same type and in the array )
#include<stdio.h>
int main()
{
int arr[10] = {
0 };
int* p = arr;
int* p1 = &arr[9];
printf("%d\n", p1 - p);
return 0;
}
- p stores the address of the first element
- p1 stores the address of the 10th element
- There are 9 elements between p1 and p
- Therefore: p1-p = 9
Illustration:
2. Array
1. Array parameter passing
- The parameter passed to the array is the pointer to be reduced to its elements —for example: the parameter passed to the two-dimensional array is the address of the one-dimensional array
- The dimensionality reduction pointer is used for array parameter passing, which improves the utilization rate of space .
- Dimensionality reduction into pointers makes the use of [ ] and *() equal, reducing the difficulty of language use.
void test(int arr[])//ok
{
}
void test(int arr[10])//ok
{
}
void test(int arr[9])//ok
{
}
void test(int* arr)//ok
{
}
void test2(int* arr[20])//ok
{
}
void test2(int* arr[0])//ok
{
}
void test2(int** arr)//ok
{
}
int main()
{
int arr[10] = {
0 };
test(arr);
int* arr2[20] = {
0 };
test2(arr2);
return 0;
}
- The function parameter int arr[] here is essentially int*arr.
illustrate:The number in [] is not interpreted by the compiler, so it’s okay if you don’t write it! Write an integer greater than 0. - int arr[10]; the element is int and its pointer is int* so the parameter is int*
- int *arr[10]: its element type is int*, so pass the pointer of int*——int**
2. Multidimensional array
- Arrays are allocated contiguously in memory
- Therefore: multidimensional arrays can be regarded as one-dimensional arrays in memory.
Two-dimensional arrays prove:
#include<stdio.h>
int main()
{
char a[3][4] = {
0 };
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 4; j++)
{
printf("a[%d][%d] : %p\n", i, j, &a[i][j]);
}
}
return 0;
}
- The elements of a two-dimensional array are one-dimensional arrays, so when passing a two-dimensional array, an array pointer must be used to receive parameters .
- The array name of the two-dimensional array is used as a function parameter , which means the address of the first element of the two-dimensional array, the address of the first row.
- function parameter writeIn the form of an array, the column label cannot be omitted!
Three-dimensional array proof:
#include<stdio.h>
int main()
{
char a[3][4][5] = {
0 };
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 4; j++)
{
for (int k = 0; k < 5; k++)
{
printf("a[%d][%d][%d] : %p\n", i, j,k, &a[i][j][k]);
}
}
}
return 0;
}
- The elements of a three-dimensional array are two-dimensional arrays, so when passing a three-dimensional array, a pointer to a two-dimensional array must be used to receive it.
- The array name of the three-dimensional array is used as a function parameter, which represents the first element of the three-dimensional array, that is, the address of the first two-dimensional array of the three-dimensional array.
- Function parameters are written as an array, the first parameter can be omitted, and the second and third parameters cannot be omitted.