指针笔记

001什么是指针

指针描述了数据在内存中的位置,标示了一个占据存储空间的实体,在这一段空间起始位置的相对距离值。在 C/C++语言中,指针一般被认为是指针变量,指针变量的内容存储的是其指向的对象的首地址,指向的对象可以是变量(指针变量也是变量),数组,函数等占据存储空间的实体。

 

 

002指针与指针变量

 

 1 #include <iostream>
 2 
 3 using namespace  std;
 4 
 5  
 6 
 7  
 8 
 9 int main()
10 
11 {
12 
13     int a=0x123;
14 
15     //输出变量a的地址
16 
17     printf("a的地址=%p \n",&a);//0061fecc
18 
19     //定义指针变量,存储变量a的地址
20 
21     int *p=&a;
22 
23     printf("p的值是=%p \n",p);//0061fecc
24 
25     //通过指针输出变量a的值
26 
27     printf("a = %d \n",*p);//0x123
28 
29     //输出指针变量p的地址
30 
31     printf("p的地址=%p\n",&p);//0061fec8
32 
33     return 0;
34 
35 }
36 
37 /*
38 
39     001指针和指针变量
40 
41 */
42 
43  

 

 

 

 

 

003指针变量的空间大小

 1 #include <iostream>
 2 
 3 using namespace  std;
 4 
 5 int main()
 6 
 7 {
 8 
 9  
10 
11     int *p1=NULL;
12 
13     int **p2=NULL;
14 
15     int ***p3=NULL;
16 
17     int ****p4=NULL;
18 
19     char*p5=NULL;
20 
21     float*p6=NULL;
22 
23     double* p7=NULL;
24 
25  
26 
27     printf("sizeof(p1)=%d \n",sizeof(p1));
28 
29     printf("sizeof(p2)=%d \n",sizeof(p2));
30 
31     printf("sizeof(p3)=%d \n",sizeof(p3));
32 
33     printf("sizeof(p4)=%d \n",sizeof(p4));
34 
35     printf("sizeof(p5)=%d \n",sizeof(p5));
36 
37     printf("sizeof(p6)=%d \n",sizeof(p6));
38 
39     printf("sizeof(p7)=%d \n",sizeof(p7));
40 
41  
42 
43     return 0;
44 
45 }
46 
47 /*
48 
49  * 结论:指针变量的空间大小是固定值,与指向的数据类型无关,只跟编译平台有关。
50 
51  * 32位机器占有4个字节,64位机器占有8字节。
52 
53 sizeof(p1)=4
54 
55 sizeof(p2)=4
56 
57 sizeof(p3)=4
58 
59 sizeof(p4)=4
60 
61 sizeof(p5)=4
62 
63 sizeof(p6)=4
64 
65 sizeof(p7)=4
66 
67 */
68 
69  

 


 

004指针变量的步长(宽度)

 

  1 #include <iostream>
  2 
  3 using namespace  std;
  4 
  5 int main()
  6 
  7 {
  8 
  9     int a=0x123;
 10 
 11     int *p1=&a;
 12 
 13     printf("p1  =%p \n",p1);
 14 
 15     printf("p1+1=%p \n",p1+1);
 16 
 17  
 18 
 19     char c='b';
 20 
 21     char*p2=&c;
 22 
 23     printf("p2  =%p \n",p2);
 24 
 25     printf("p2+1=%p \n",p2+1);
 26 
 27  
 28 
 29     double d=12.343;
 30 
 31     double *p3=&d;
 32 
 33     printf("p3  =%p \n",p3);
 34 
 35     printf("p3+1=%p \n",p3+1);
 36 
 37  
 38 
 39  
 40 
 41  
 42 
 43     int array[3]={1,2,3};
 44 
 45     printf("array    =%p \n",array);
 46 
 47     printf("&array   =%p \n",&array);
 48 
 49     printf("array+1  =%p \n",array+1);
 50 
 51     printf("&array+1 =%p \n",&array+1);
 52 
 53     printf("&array[0]=%p \n",&array[0]);
 54 
 55     printf("&array[1]=%p \n",&array[1]);
 56 
 57     printf("&array[2]=%p \n",&array[2]);
 58 
 59  
 60 
 61     return 0;
 62 
 63 }
 64 
 65 /*
 66 
 67  * 结论:(1)整形变量的步长是4个字节,字符类型的步长是1个字节,双精度浮点类型是8个字节
 68 
 69  * (2)数组名是数组首个元素的地址,加1是加一个元素的长度,&数组名是数组的首地址,加1是整个数组的长度
 70 
 71  * (3)指针的步长是指向的变量类型占有的内存空间的大小。本质是指向下一个变量。
 72 
 73  *
 74 
 75  *
 76 
 77 p1  =0061fec0
 78 
 79 p1+1=0061fec4
 80 
 81  
 82 
 83 p2  =0061febf
 84 
 85 p2+1=0061fec0
 86 
 87  
 88 
 89 p3  =0061feb0
 90 
 91 p3+1=0061feb8
 92 
 93  
 94 
 95 array    =0061fea4
 96 
 97 &array   =0061fea4
 98 
 99  
100 
101 array+1  =0061fea8  +4 一个元素的值,
102 
103 &array+1 =0061feb0  +12 整个数组的值
104 
105  
106 
107 &array[0]=0061fea4
108 
109 &array[1]=0061fea8
110 
111 &array[2]=0061feac
112 
113  *
114 
115 */

 

 

005野指针

    野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)指针变量在定义时如果未初始化,其值是随机的,指针变量的值是别的变量的地址,意味着指针指向了一个地址是不确定的变量,此时去解引用就是去访问了一个不确定的地址,所以结果是不可知的。

 

 1 #include <iostream>
 2 
 3 using namespace  std;
 4 
 5  
 6 
 7 int*myFunction()
 8 
 9 {
10 
11     int a=10;
12 
13     return &a;
14 
15 }
16 
17  
18 
19 int main()
20 
21 {
22 
23     //情形1
24 
25     int a;
26 
27     printf("a  =%d \n",a);//17503780  a的值每次都是随机的
28 
29  
30 
31     int *p;
32 
33     printf("p= %p \n",p);//00000068
34 
35     //printf("*p=%d \n",*p);//有的编译器会报错
36 
37  
38 
39     //情形2
40 
41     int array[3]={1,2,3};
42 
43     for(int i=0;i<5;i++)//数组越界
44 
45     {
46 
47         printf("a[i]=%d \n",*(&array[i]));//只是读取,正常
48 
49     }
50 
51     /*
52 
53         a[i]=1
54 
55         a[i]=2
56 
57         a[i]=3
58 
59         a[i]=0
60 
61         a[i]=104
62 
63     */
64 
65     //情形3:
66 
67     int*p1=myFunction();
68 
69     printf("*p1=%d \n",*p1);//error,不会有输出
70 
71     return 0;
72 
73 }
74 
75 /*
76 
77  * 结论:局部变量,如果定义之后没有初始化,其值是随机值。
78 
79  * 情形1:使用了未初始化的指针变量
80 
81  * 情形2:数组下表越界
82 
83  * 情形3:函数返回局部变量的地址—使用了已经销毁的内存
84 
85  *
86 
87 */

 

 

006空指针

 1 #include <iostream>
 2 
 3 using namespace  std;
 4 
 5  
 6 
 7 int main()
 8 
 9 {
10 
11     int a=0x123;
12 
13     int *p;
14 
15     printf("p =%p \n",p);
16 
17     //*p=123;//error
18 
19     //printf("*p=%d \n",*p);//error
20 
21  
22 
23     //建议定义时候初始化为空指针
24 
25     int *p1=NULL;//0x00000000内存地址
26 
27     //能不能把0x00000000读取出来?不能读取,也不能赋值,系统保留的地址
28 
29     //printf("0x00000000=%d \n",*p1);//error
30 
31  
32 
33     //c++11 使用nullptr
34 
35     int *p2=nullptr;
36 
37     //使用方法
38 
39     if(p1==NULL)
40 
41     {
42 
43         //给p1指针变量赋值
44 
45  
46 
47         printf("p1是空指针 \n");
48 
49     }
50 
51     p1=NULL;
52 
53  
54 
55     return 0;
56 
57 }
58 
59 /*
60 
61  * 结论:定义指针变量时候,如果目前不知道指向哪里,指向NULL.
62 
63  * 指针使用完毕一定要赋值为NULL.
64 
65  *
66 
67 */
68 
69  

 


 

007void指针—万能指针类型

 1 #include <iostream>
 2 
 3 using namespace  std;
 4 
 5  
 6 
 7 int main()
 8 
 9 {
10 
11     int a=0x123;
12 
13     char c='c';
14 
15  
16 
17     int *p1=&a;
18 
19     char*p2=&c;
20 
21  
22 
23     printf("p1= %d \n",p1);//根据p1指向int类型,从首地址开始读取4个字节
24 
25     printf("p2= %d \n",p2);//根据p2指向char类型,从首地址读取1个字节
26 
27  
28 
29     printf("*p1= %d \n",*p1);
30 
31     printf("*p2= %d \n",*p2);
32 
33  
34 
35     void*p3=p2;//ok
36 
37     //printf("*p3= %d \n",*p3);//error--不知道读取多少个字节
38 
39     printf("*p3= %d \n",*(char*)p3);//c  99
40 
41     return 0;
42 
43 }
44 
45 /*
46 
47  * 结论:void类型指针可以用来接收所有的指针类型,但是因为不知道指向哪里,所以没办法解引用。
48 
49  * 解引用必须强制类型转换。
50 
51  *
52 
53 */
54 
55  

 


 

 

008const指针

 1 #include <iostream>
 2 
 3 using namespace  std;
 4 
 5  
 6 
 7  
 8 
 9  
10 
11 int main()
12 
13 {
14 
15     //const用来修饰常量
16 
17     const int a=0x123;
18 
19     printf("a=%d \n",a);
20 
21     //a=456;
22 
23  
24 
25     const int*p=&a;//修饰内存空间
26 
27     //*p=456;//error,const指针变量不能解引用修改原来地址空间的值
28 
29     printf("*p=%d \n",*p);
30 
31  
32 
33     //修改指针本身,不能指向其他内存空间
34 
35     int b=0x123;
36 
37     int *const p2=&b;//指向不能修改,可以更改内存空间的值,解引用正常
38 
39     *p2=0x456;
40 
41     printf("*p2=%d \n",*p2);//0x456
42 
43     int c=0x456;
44 
45     //p2=&c;//error read only
46 
47  
48 
49     //(3)指向和内存空间都不能修改
50 
51     const int*const p3=&a;
52 
53     printf("*p3=%d \n",*p3);
54 
55  
56 
57     return 0;
58 
59 }
60 
61 /*
62 
63  * 结论:
64 
65  * (1)const int*p=&a;//修饰内存空间
66 
67  * (2)int *const p2=&b;//指向不能修改,可以更改内存空间的值,解引用正常
68 
69  * (3)指向和内存空间都不能修改
70 
71  * const int*const p3=&a;
72 
73  *
74 
75 */

 

 

009多级指针—指针的指针

 1 #include <stdio.h>
 2 
 3  
 4 
 5 int main(int argc, char* argv[])
 6 
 7 {
 8 
 9     int a = 0x123;
10 
11     //p1是变量名,p1的类型是存储整形变量的内存地址的类型
12 
13     int* p1 = &a;//定义p1存储a的地址
14 
15     printf("&a=%p \n", &a);
16 
17     printf("p1=%p \n", p1);
18 
19  
20 
21     //定义p2存储p1的地址
22 
23     //p2是变量名字,p2的类型是指向 存储整形变量内存地址的类型
24 
25     int** p2 = &p1;
26 
27     printf("p2=%p \n", p2);
28 
29  
30 
31     //定义p3存储p2的地址
32 
33     int*** p3 = &p2;
34 
35     printf("p3=%p \n", p3);
36 
37  
38 
39     //解引用输出
40 
41     printf("a=%d \n", a);
42 
43     printf("*p1=%d \n", *p1);
44 
45     printf("**p2=%d \n", **p2);
46 
47     printf("***p3=%d \n", ***p3);
48 
49     return 0;
50 
51 }
52 
53 /*
54 
55 * 指针有数据类型,指针的数据类型就是地址类型+它指向的数据类型
56 
57 *
58 
59 &a=00000099B1CFF6C4
60 
61 p1=00000099B1CFF6C4
62 
63 p2=00000099B1CFF6E8
64 
65 p3=00000099B1CFF708
66 
67 a=291
68 
69 *p1=291
70 
71 **p2=291
72 
73 ***p3=291
74 
75  
76 
77 */
78 
79  

 


 

010 用指针操作数组

 1 #include <stdio.h>
 2 
 3  
 4 
 5 int main(int argc, char* argv[])
 6 
 7 {
 8 
 9     int a[3] = { 11,22,33 };
10 
11     printf("a    =%p \n", a);//数组名,就是数组首个元素的地址,等价于&a[0]
12 
13     printf("&a   =%p \n", &a);//整个数组的指针,+1跳过整个数组
14 
15     printf("&a[0]=%p \n", &a[0]);//数组首个元素的地址
16 
17  
18 
19     printf("a+1    =%p \n", a+1);
20 
21     printf("&a+1   =%p \n", &a+1);
22 
23     printf("&a[0]+1=%p \n", &a[0]+1);
24 
25  
26 
27     //数组名就是数组首元素的地址
28 
29     printf("sizeof(a)=%d \n", sizeof(a));//12,整个数组大小
30 
31     printf("sizeof(&a)=%d \n", sizeof(&a));//8 指针的大小
32 
33     int* p = a;
34 
35     printf("sizeof(p)=%d \n", sizeof(p));//64位占有8个字节,地址类型
36 
37  
38 
39  
40 
41     //用指针操作数组
42 
43     for (int i = 0; i < 3; i++)
44 
45     {
46 
47         printf("数组元素地址=%p,a[%d]=%d \n", &a[i], i, a[i]);
48 
49         //printf("数组元素地址=%p,a[%d]=%d \n", &a[i], i, *(&a[i]));//ok
50 
51     }
52 
53  
54 
55  
56 
57     return 0;
58 
59 }
60 
61  
62 
63 /*
64 
65 a    =000000E4B697FAA8
66 
67 &a   =000000E4B697FAA8
68 
69 &a[0]=000000E4B697FAA8
70 
71  
72 
73 a+1    =000000E4B697FAAC  //+4
74 
75 &a+1   =000000E4B697FAB4  //+12
76 
77 &a[0]+1=000000E4B697FAAC  //+4
78 
79 sizeof(a)=12
80 
81 sizeof(&a)=8
82 
83 sizeof(p)=8
84 
85  
86 
87 数组元素地址=000000E4B697FAA8,a[0]=11
88 
89 数组元素地址=000000E4B697FAAC,a[1]=22
90 
91 数组元素地址=000000E4B697FAB0,a[2]=33
92 
93  
94 
95  
96 
97 */
98 
99  

 


 

 

011用指针操作数组—多维数组

 

  1 #include <stdio.h>
  2 
  3  
  4 
  5 int main(int argc, char* argv[])
  6 
  7 {
  8 
  9     int a[2][3] = { {1,2,3},{4,5,6} };
 10 
 11    
 12 
 13     printf("a       =%p \n", a);//等价于&a[0]
 14 
 15     printf("&a      =%p \n", &a);//整个数组的指针,
 16 
 17     printf("a[0]    =%p \n", a[0]);//数组中首个元素a[0][0]的地址
 18 
 19     printf("&a[0]   =%p \n",&a[0]);//数组中首个元素a[0][0]的地址
 20 
 21     printf("&a[0][0]=%p \n", &a[0][0]);//数组中首个元素a[0][0]的地址
 22 
 23  
 24 
 25     printf("sizeof(a)=%d \n", sizeof(a));//整个数组  24
 26 
 27     printf("sizeof(a[0])=%d \n", sizeof(a[0]));//一维度12
 28 
 29     printf("sizeof(a[0][0])=%d \n", sizeof(a[0][0]));//元素的长度 4
 30 
 31  
 32 
 33  
 34 
 35     printf("a+1       =%p \n", a+1);//等价于&a[0]  +12 一个维度
 36 
 37     printf("&a+1      =%p \n", &a+1);//整个数组的指针, +24,跳过整个数组
 38 
 39     printf("a[0]+1    =%p \n", a[0]+1);//数组中首个元素a[0][0]的地址 
 40 
 41     printf("&a[0]+1   =%p \n", &a[0]+1);//数组中首个元素a[0]的地址
 42 
 43     printf("&a[0][0]+1=%p \n", &a[0][0]+1);//数组中首个元素a[0][0]的地址
 44 
 45  
 46 
 47     return 0;
 48 
 49 }
 50 
 51 /*
 52 
 53 a       =0000001CEDCFFB08
 54 
 55 &a      =0000001CEDCFFB08
 56 
 57 a[0]    =0000001CEDCFFB08
 58 
 59 &a[0]   =0000001CEDCFFB08
 60 
 61 &a[0][0]=0000001CEDCFFB08
 62 
 63 sizeof(a)=24
 64 
 65 sizeof(a[0])=12
 66 
 67 sizeof(a[0][0])=4
 68 
 69 a+1       =0000001CEDCFFB14  +12
 70 
 71 &a+1      =0000001CEDCFFB20  +24   
 72 
 73 a[0]+1    =0000001CEDCFFB0C  +4
 74 
 75 &a[0]+1   =0000001CEDCFFB14  +12
 76 
 77 &a[0][0]+1=0000001CEDCFFB0C  +4
 78 
 79  
 80 
 81  
 82 
 83  规定:如果将二维数组作为参数传递给函数,那么在函数的参数声明中必须指明数组的列数,数组的行数没有太大关系,可以指定也可以不指定。因为函数调用时传递的是一个指针,它指向由行向量够成的一维数组。因此二维数组作为函数参数正确写法如下所示:
 84 
 85  
 86 
 87 void Func(int array[3][10]);
 88 
 89  
 90 
 91 void Func(int array[ ][10]);
 92 
 93  
 94 
 95 因为数组的行数无关紧要,所以还可以写成如下形式:
 96 
 97  
 98 
 99 void Func(int (*array)[10]);  注意*array需要用括号括起来。--数组指针类型
100 
101 这种形式的声明参数是一个指针,它指向具有10个元素的一维数组。因为[]的优先级比*的优先级高,故*array必须用括号括起来,否则变成了
102 
103 void Func(int *array[10]);
104 
105 这时候参数相当于是声明了一个数组,该数组有10个元素,其中每个元素都是一个指向整型对象的指针。
106 
107  
108 
109 */
110 
111  

 


 

012指针运算—指针与整数的运算

指针只能做加减运算,没有乘除运算,并且要严防指针越界。

 

 1 #include<stdio.h>
 2 
 3  
 4 
 5 int main(void)
 6 
 7 {
 8 
 9     int a[4] = { 11,22,33,44 };
10 
11     printf("a[%d]=%d,address =%p \n", 0, a[0], a);
12 
13     printf("a[%d]=%d,address =%p \n", 1, a[1], a + 1);
14 
15     printf("a[%d]=%d,address =%p \n", 2, a[2], a + 2);
16 
17     printf("a[%d]=%d,address =%p \n", 3, a[3], a + 3);
18 
19  
20 
21     printf("=======================================\n");
22 
23     //指针减法
24 
25     int* p1 = &a[3];
26 
27     //这里输出的是33,先执行右侧的语句
28 
29     printf("p[%d]=%d,address =%p \n", 3, *p1, p1--);
30 
31     printf("p[%d]=%d,address =%p \n", 2, *p1, p1--);
32 
33     printf("p[%d]=%d,address =%p \n", 1, *p1, p1--);
34 
35     printf("p[%d]=%d,address =%p \n", 0, *p1, p1--);
36 
37  
38 
39  
40 
41     return 0;
42 
43 }
44 
45 /*
46 
47 结论:指针的加减是以指向的数据类型为步长的。
48 
49  
50 
51 a[0]=11,address =000000A713F6F658
52 
53 a[1]=22,address =000000A713F6F65C
54 
55 a[2]=33,address =000000A713F6F660
56 
57 a[3]=44,address =000000A713F6F664
58 
59 =======================================
60 
61 p[3]=33,address =000000A713F6F664
62 
63 p[2]=22,address =000000A713F6F660
64 
65 p[1]=11,address =000000A713F6F65C
66 
67 p[0]=-858993460,address =000000A713F6F658
68 
69 */

 

 

013指针运算-指针与指针的运算

 1 #include<stdio.h>
 2 
 3  
 4 
 5 int main(void)
 6 
 7 {
 8 
 9     int a[4] = { 11,22,33,44 };
10 
11     //(1)比较运算  指针可以判断是否相等,
12 
13     int* p1 = a;
14 
15     int* p2 = &a[0];
16 
17     int* p3 = &a[2];
18 
19     if (p1 == p2)
20 
21     {
22 
23         printf("p1==p2 \n");
24 
25     }
26 
27     if (p3 > p2)
28 
29     {
30 
31         printf("p3>p2 \n");
32 
33     }
34 
35     //printf("p1+p2=%p \n",p1+p2);
36 
37  
38 
39     return 0;
40 
41 }
42 
43 /*
44 
45 结论:
46 
47 (1)指针运算的前提:相同类型的指针进行比较
48 
49 (2)指针与指针相加编译不能通过。
50 
51 (3)指针相减求出的是两个元素在内存之间的距离。
52 
53 (4)指针运算严防指针越界,指针越界一般读取没有问题,但是写有问题。
54 
55  
56 
57 */

 

 

 

013指针数组

    数组元素都是指针类型的数据的数组。

 

  1 #include<stdio.h>
  2 
  3  
  4 
  5 int main(void)
  6 
  7 {
  8 
  9     int a[4] = { 11,22,33,44 };
 10 
 11     int *p = a;
 12 
 13     printf("sizeof(a)=%d \n", sizeof(a));//16--整个数组的长度
 14 
 15     printf("sizeof(p)=%d \n", sizeof(p));//64位系统 8
 16 
 17  
 18 
 19     printf("*p    =%d \n", *p);
 20 
 21     printf("*(p+1)=%d \n", *(p+1));
 22 
 23     printf("*(p+2)=%d \n", *(p+2));
 24 
 25     printf("*(p+3)=%d \n", *(p+3));
 26 
 27  
 28 
 29     printf("*a    =%d \n", *a);
 30 
 31     printf("*(a+1)=%d \n", *(a + 1));
 32 
 33     printf("*(a+2)=%d \n", *(a + 2));
 34 
 35     printf("*(a+3)=%d \n", *(a + 3));
 36 
 37  
 38 
 39     //例子:指针和数组的关系
 40 
 41     int number = 10;
 42 
 43     int* p1 = &number;
 44 
 45     printf("p1[0]=%d \n",p1[0]);//可以通过数组形式访问变量p1[0]等价于*(p1+0)
 46 
 47  
 48 
 49     return 0;
 50 
 51 }
 52 
 53 /*
 54 
 55 结论:(1)数组名是指向数组首元素的指针,步长是指向下一个元素.
 56 
 57  
 58 
 59 */
 60 
 61  
 62 
 63 #include<stdio.h>
 64 
 65  
 66 
 67 int main(void)
 68 
 69 {
 70 
 71     int a = 11, b = 22, c = 33;
 72 
 73     int arr[3] = { a,b,c };//数组
 74 
 75     //定义并初始化指针数组
 76 
 77     int* pArr[3] = { &a,&b,&c };
 78 
 79     //输出元素的值
 80 
 81     printf("pArr[0]=%p \n", pArr[0]);
 82 
 83     printf("pArr[1]=%p \n", pArr[1]);
 84 
 85     printf("pArr[2]=%p \n", pArr[2]);
 86 
 87  
 88 
 89     printf("pArr[0]=%p \n", *(pArr + 0));
 90 
 91     printf("pArr[1]=%p \n", *(pArr + 1));
 92 
 93     printf("pArr[2]=%p \n", *(pArr + 2));
 94 
 95  
 96 
 97    
 98 
 99     return 0;
100 
101 }
102 
103 /*
104 
105 结论:(1)指针数组的定义,数组元素都是指针(地址)
106 
107  
108 
109 */
110 
111  
112 
113 #include<stdio.h>
114 
115  
116 
117 int main(void)
118 
119 {
120 
121     int a = 11, b = 22, c = 33;
122 
123     int arr[3] = { a,b,c };//数组
124 
125     //定义并初始化指针数组
126 
127     int* pArr[3] = { &a,&b,&c };
128 
129     //输出元素的值
130 
131     printf("pArr[0]=%p,*pArr[0]=%d  \n", pArr[0],*pArr[0]);
132 
133     printf("pArr[1]=%p,*pArr[1]=%d  \n", pArr[1],*pArr[1]);
134 
135     printf("pArr[2]=%p,*pArr[2]=%d  \n", pArr[2],*pArr[2]);
136 
137  
138 
139     int** p1 = pArr;
140 
141     printf("*p1=%p,**p1=%d  \n", *p1, **p1);
142 
143     p1++;
144 
145     printf("*p1=%p,**p1=%d  \n", *p1, **p1);
146 
147     p1++;
148 
149     printf("*p1=%p,**p1=%d  \n", *p1, **p1);
150 
151  
152 
153     return 0;
154 
155 }
156 
157 /*
158 
159 结论:(1)指针数组的数组名是一个二级指针,可以通过二级指针来访问指针数组的元素。
160 
161  
162 
163 */

 

 

 

014指针作为函数参数

 1 #include<stdio.h>
 2 
 3 void Swap(int *a, int *b)
 4 
 5 {
 6 
 7     int c = *b;
 8 
 9     *b = *a;
10 
11     *a = c;
12 
13 }
14 
15  
16 
17 int main(void)
18 
19 {
20 
21     int a = 11;
22 
23     int b = 22;
24 
25     Swap(&a, &b);
26 
27     printf("a=%d \n", a);
28 
29     printf("b=%d \n", b);
30 
31  
32 
33     return 0;
34 
35 }

 

 

015一维数组作为函数参数

 1 #include<stdio.h>
 2 
 3  
 4 
 5 //void myFunc(int* p, int len)//ok
 6 
 7 void myFunc(int p[3], int len)
 8 
 9 {
10 
11     //printf("数组首地址=%p,数组的长度=%d \n", p, sizeof(p) / sizeof(p[0]));//这里的p已经退化为一个指针
12 
13     for (int i = 0; i < len; i++)
14 
15     {
16 
17         printf("p[%d]=%d \n", i, p[i]);
18 
19     }
20 
21  
22 
23 }
24 
25  
26 
27 int main(void)
28 
29 {
30 
31     int a[3] = { 11,22,33 };
32 
33     //这里使用sizeof(a)获取的是整个数组的长度
34 
35     printf("数组首地址=%p,数组的长度=%d \n", a, sizeof(a) / sizeof(a[0]));
36 
37  
38 
39     myFunc(a, sizeof(a) / sizeof(a[0]));
40 
41  
42 
43  
44 
45     return 0;
46 
47 }
48 
49 /*
50 
51 结论:
52 
53 数组首地址=000000E4FECFF8B8,数组的长度=3
54 
55 数组首地址=000000E4FECFF8B8,数组的长度=2
56 
57  
58 
59 数组名作为函数参数,已经退化为一个指针,sizeof(数组名)得到的是指针的长度
60 
61  
62 
63 */
64 
65  

 


 

 

016指针作为函数的返回值

 

 1 #include<stdio.h>
 2 
 3  
 4 
 5 /*
 6 
 7 (1)函数执行完毕,a的内存控件就释放了
 8 
 9 解决办法:(1)将a定义为全局变量。
10 
11 (2)使用malloc分配内存空间
12 
13 */
14 
15 int* myFunc()
16 
17 {
18 
19     int a = 123;
20 
21     return &a;
22 
23 }
24 
25  
26 
27 int main(void)
28 
29 {
30 
31     int* p = myFunc();
32 
33     printf("*p=%d \n", *p);
34 
35  
36 
37     return 0;
38 
39 }
40 
41 /*
42 
43 结论:如果使用指针作为函数返回值,要确保函数调用结束指针空间不会被销毁,否则会变成野指针。
44 
45  
46 
47  
48 
49 */

 

 

017字符数组指针

 

 1 #include<stdio.h>
 2 
 3 #include<string.h>
 4 
 5  
 6 
 7 int main(void)
 8 
 9 {
10 
11     char c = 'a';
12 
13     char* p1 = &c;
14 
15     printf("*p1=%c \n", *p1);
16 
17  
18 
19     //定义字符数组
20 
21     char arr[] = { 'a','b','c','d' };
22 
23     char arr02[] = "abcd";//这里会自动添加 \0结束标志
24 
25     char* p2 = arr;
26 
27     printf("%c %s \n",*p2,p2);//a abcd烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫赭瘹W
28 
29  
30 
31     //写操作
32 
33     *p2='A';
34 
35     printf("%s \n",p2);//Abcd烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫豇o憹
36 
37  
38 
39     char* p3 = arr02;
40 
41     printf("%s \n", p3);//abcd
42 
43  
44 
45     printf("arr=%d,arr02=%d \n", strlen(arr), strlen(arr02)); //36, p3 = 4
46 
47     printf("arr=%d,arr02=%d \n", sizeof(arr), sizeof(arr02));//p2=4,p3=5
48 
49  
50 
51     return 0;
52 
53 }
54 
55 /*
56 
57 结论:
58 
59 (1)c语言没有字符串,用字符数组模拟字符串,当出现\0,表示字符串结束
60 
61 (2)strlen计算的是有效的字符个数,sizeof计算的是占有的内存字节数,包含\0
62 
63  
64 
65 */
66 
67  
68 
69     const char* p = "abc";
70 
71     printf("p=%s \n", p);
72 
73     /*
74 
75     (1)在栈区定义一个char*类型的变量p
76 
77     (2)在常量区开辟一个空间,存储字符串“abc”
78 
79     (3)将常量区“abc”对应的地址赋值给p,可以修改p的指向,但是不能修改p指向的值
80 
81     */

 

 

 

018字符指针数组

 1 #include<stdio.h>
 2 
 3 #include<string.h>
 4 
 5  
 6 
 7 int main(void)
 8 
 9 {
10 
11     char a[] = "abc";//每一个
12 
13     char b[] = "def";
14 
15     char c[] = "xyz";
16 
17  
18 
19     char* p[3] = { a,b,c };
20 
21     printf("sizeof(p)=%d \n", sizeof(p));//24 元素类型是char*类型
22 
23  
24 
25     for (int i = 0; i < 3; i++)
26 
27     {
28 
29         printf("p[%d]=%p \n", i, p[i]);
30 
31     }
32 
33     /*
34 
35         p[0]=000000FD022FF974
36 
37         p[1]=000000FD022FF994
38 
39         p[2]=000000FD022FF9B4
40 
41     */
42 
43     //指针数组可以通过二维指针来访问
44 
45     char** pp = p;
46 
47     printf("sizeof(pp)=%d \n", sizeof(pp));//64位系统占有8位
48 
49  
50 
51     for (int i = 0; i < 3; i++)
52 
53     {
54 
55         //通过二级指针输出内存的值
56 
57         printf("值=%s \n", *(pp++));
58 
59         //printf("值=%s \n", pp[i]);//ok
60 
61     }
62 
63  
64 
65  
66 
67  
68 
69     return 0;
70 
71 }
72 
73  

 


 

 

019字符指针数组初始化过程

  1 #include<stdio.h>
  2 
  3  
  4 
  5 int main(void)
  6 
  7 {
  8 
  9     char a = 'a';
 10 
 11     char b = 'b';
 12 
 13     char* p = &a;//字符指针类型变量
 14 
 15     char c[] = { a,b,'c' };
 16 
 17     //字符类型数组,此处的a,b与上面的a,b无关,只是做了数据的拷贝,内存空间是独立的
 18 
 19  
 20 
 21     printf("%p,%p,%c,%c \n", &a, &b, a, b);
 22 
 23     printf("%p,%p,%c,%c \n", &c[0], &c[1], c[0], c[1]);
 24 
 25  
 26 
 27     //字符指针类型的数组
 28 
 29     char* p2[] = { &a,p,c };
 30 
 31     //p2[0]与 p2[1] 的值是相等的,解引用后也是相等的a
 32 
 33     //p2[2]的值是不一样的,但是解引用之后也是一样的a
 34 
 35  
 36 
 37     for (int i = 0; i < 3; i++)
 38 
 39     {
 40 
 41         printf("%p,%p,%c \n", &p2[i], p2[i], *p2[i]);
 42 
 43     }
 44 
 45  
 46 
 47     return 0;
 48 
 49 }
 50 
 51 /*
 52 
 53 结论:使用数组,和指针变量初始化字符指针数组
 54 
 55  
 56 
 57 00000099FAB4F8A4,00000099FAB4F8C4,a,b
 58 
 59 00000099FAB4F904,00000099FAB4F905,a,b
 60 
 61  
 62 
 63 00000099FAB4F928,00000099FAB4F8A4,a
 64 
 65 00000099FAB4F930,00000099FAB4F8A4,a
 66 
 67 00000099FAB4F938,00000099FAB4F904,a
 68 
 69  
 70 
 71 */
 72 
 73  
 74 
 75 //字符常量初始化字符指针数组
 76 
 77 #include<stdio.h>
 78 
 79  
 80 
 81 int main(void)
 82 
 83 {
 84 
 85     //局部变量放在栈区
 86 
 87     //常量是放在常量区
 88 
 89     //有双引号的,称之为字符串常量,所以,双引号里面的内容,一定会在常量区有一份
 90 
 91  
 92 
 93     char c[] = "abc"; //字符类型数组,定义
 94 
 95     //初始化过程
 96 
 97     //1 先在栈区定定义一个 char 数组的变量,并分配空间
 98 
 99     //2 去常量区找,有没有 abc\0,如果没有,就在常量区写一份,然后再往栈区拷贝一份,
100 
101     //如果常量区有,就直接拷贝回来
102 
103  
104 
105     //d[]="def";//数组不能这样赋值
106 
107     //d[0]="d";//双引号后面有\0结尾  //char x[2]="ab";//长度不够
108 
109     //d[0]='d';//正确
110 
111  
112 
113     const char* p1 = "abc";
114 
115     const char* p2 = "abc";
116 
117     const char* p3 = "def";
118 
119     //1 先在栈区定定义一个 char *的变量,并分配空间
120 
121     //2 去常量区找,有没有 abc\0,如果没有,就在常量区写一份,
122 
123     //并将常量区对应的指针地址给到栈区的变量,如果有,直接拿常量区指针地址
124 
125     printf("p1=%p \n", p1);
126 
127     printf("p2=%p \n", p2);
128 
129     printf("p3=%p \n", p3);
130 
131     /*
132 
133         p1=00007FF652B39CA4
134 
135         p2=00007FF652B39CA4
136 
137         p3=00007FF652B39CA8
138 
139         结论:p1==p2
140 
141     */
142 
143     //数组就会拷贝,指针地址不同(分配了内存空间,将数据拷贝进去)
144 
145     char x[] = "abc";
146 
147     char y[] = "abc";
148 
149     printf("x=%p \n", x);
150 
151     printf("y=%p \n", y);
152 
153     /*
154 
155         x=000000D83ED2F784
156 
157         y=000000D83ED2F7A4
158 
159     */
160 
161  
162 
163     return 0;
164 
165 }
166 
167  
168 
169 #include<stdio.h>
170 
171  
172 
173 int main(void)
174 
175 {
176 
177     //只要字符串在常量区存在,则新的指针变量指向该字符串的地址时,都是使用同一个常量区的地址
178 
179     const char* p1 = "abc";
180 
181     const char* p2[] = { "abc","abc",p1 };
182 
183  
184 
185     for (int i = 0; i < 3; i++)
186 
187     {
188 
189         printf("p2[%d]=%p \n", i, p2[i]);
190 
191         /*
192 
193             p2[0]=00007FF6FC579CA4
194 
195             p2[1]=00007FF6FC579CA4
196 
197             p2[2]=00007FF6FC579CA4
198 
199         */
200 
201     }
202 
203  
204 
205     char c2[] = "abc";
206 
207     const char* p3[] = { c2,"abc","abc",p1 };
208 
209  
210 
211     for (int i = 0; i < 4; i++)
212 
213     {
214 
215         printf("p3[%d]=%p \n", i, p3[i]);
216 
217         /*
218 
219             p3[0]=000000C0FFAFF7C4  //值不同
220 
221             p3[1]=00007FF6700C9CA4
222 
223             p3[2]=00007FF6700C9CA4
224 
225             p3[3]=00007FF6700C9CA4 
226 
227         */
228 
229     }
230 
231  
232 
233     return 0;
234 
235 }

 

 

020指针数组和数组指针

  1 #include<stdio.h>
  2 
  3  
  4 
  5 int main(void)
  6 
  7 {
  8 
  9     char a = 'a';
 10 
 11     char b = 'b';
 12 
 13     char* p = &a;
 14 
 15     char c[] = { a,b,'c' };
 16 
 17     char* p2[] = { &a,p,c };//字符指针类型的数组 指针数组
 18 
 19  
 20 
 21     //数组指针
 22 
 23     char(*p1)[3] = &c;//p1是数组指针,指向的是一个有着3个元素的char类型的指针
 24 
 25     printf("c=%p,p1=%p \n", c, p1);
 26 
 27     printf("c+1=%p,p1+1=%p \n", c+1, p1+1);
 28 
 29     /*
 30 
 31         c=00000072D46FF824,p1=00000072D46FF824
 32 
 33         c+1=00000072D46FF825,p1+1=00000072D46FF827
 34 
 35     */
 36 
 37  
 38 
 39     for (int i = 0; i < 3; i++)
 40 
 41     {
 42 
 43         printf("%p--%c \n", &((*p1)[i]), (*p1)[i]);//*p1==>c
 44 
 45  
 46 
 47         /*
 48 
 49             00000072D46FF824--a
 50 
 51             00000072D46FF825--b
 52 
 53             00000072D46FF826--c
 54 
 55         */
 56 
 57     }
 58 
 59  
 60 
 61     char* p3 = c;//字符指针类型变量,其指向的是数组第一个元素,相当于&c[0]
 62 
 63     for (int i = 0; i < 3; i++)
 64 
 65     {
 66 
 67         printf("%p--%c \n", (p3 + i), *(p3 + i));
 68 
 69  
 70 
 71         /*
 72 
 73             00000072D46FF824--a
 74 
 75             00000072D46FF825--b
 76 
 77             00000072D46FF826--c
 78 
 79         */
 80 
 81  
 82 
 83     }
 84 
 85  
 86 
 87     return 0;
 88 
 89 }
 90 
 91 /*
 92 
 93 结论:数组是一种数据类型,数据类型可以定义
 94 
 95 char(*p1)[3] = &c
 96 
 97  
 98 
 99 c=00000072D46FF824,p1=00000072D46FF824
100 
101 c+1=00000072D46FF825,p1+1=00000072D46FF827
102 
103  
104 
105 00000072D46FF824--a
106 
107 00000072D46FF825--b
108 
109 00000072D46FF826--c
110 
111  
112 
113 00000072D46FF824--a
114 
115 00000072D46FF825--b
116 
117 00000072D46FF826--c
118 
119  
120 
121 */
122 
123  

 


 

021函数指针

 

 1 #include<stdio.h>
 2 
 3  
 4 
 5 void myFunc()
 6 
 7 {
 8 
 9     printf("hello world \n");
10 
11 }
12 
13 //有参数
14 
15 int myAdd(int number01, int number02)
16 
17 {
18 
19     return number01 + number02;
20 
21 }
22 
23  
24 
25 int main(void)
26 
27 {
28 
29     //获取函数指针
30 
31     void (*pFunc)() = &myFunc;
32 
33     //&myFunc=00007FF7D45C1163,pFunc=00007FF7D45C1163
34 
35     printf("&myFunc=%p,pFunc=%p \n", &myFunc, pFunc);
36 
37  
38 
39     //用指针函数调用函数--解引用
40 
41     (*pFunc)();
42 
43  
44 
45     //有参函数
46 
47     int (*pMyAdd)(int, int) = &myAdd;
48 
49     //int sum = pMyAdd(11, 22);//ok
50 
51     int sum = (*pMyAdd)(11, 22);
52 
53     printf("sum=%d \n", sum);
54 
55  
56 
57     return 0;
58 
59 }
60 
61 /*
62 
63 结论:函数也有数据类型,所有函数指针也可以定义变量。
64 
65  
66 
67 函数指针定义形式:
68 
69 函数返回值类型(*指针变量名)(函数参数列表)
70 
71 调用方法:(*指针变量名)(参数列表)
72 
73  
74 
75 */
76 
77  

 


 

022函数指针数组

本质上是数组,里面的元素都是函数指针

函数指针数组={函数指针,函数指针,函数指针};

 

 1 #include<stdio.h>
 2 
 3  
 4 
 5 int myFunc01(int a, int b) { return a + b; };
 6 
 7 int myFunc02(int a, int b) { return a - b; };
 8 
 9 int myFunc03(int a, int b) { return a * b; };
10 
11 int myFunc04(int a, int b) { return a / b; };
12 
13  
14 
15 int main(void)
16 
17 {
18 
19     int a = 22;
20 
21     int b = 11;
22 
23     int (*p1)(int, int) = &myFunc01;
24 
25     int (*p2)(int, int) = &myFunc02;
26 
27     int (*p3)(int, int) = &myFunc03;
28 
29     int (*p4)(int, int) = &myFunc04;
30 
31  
32 
33     //定义函数指针数组
34 
35     int (*pArr[4])(int, int) = { p1,p2,p3,p4 };
36 
37     for (int i = 0; i < 4; i++)
38 
39     {
40 
41         printf("(*pArr[i])(a, b)=%d \n", (*pArr[i])(a, b));
42 
43     }
44 
45     return 0;
46 
47 }
48 
49 /*
50 
51 结论:定义函数指针数组方法
52 
53 */
54 
55  

 


 

023函数指针底层原理解析

 

 1 #include<stdio.h>
 2 
 3  
 4 
 5 void myFunc()
 6 
 7 {
 8 
 9     printf("hello world \n");
10 
11 }
12 
13  
14 
15 int main(void)
16 
17 {
18 
19     void (*p1)() = &myFunc;
20 
21     void (*p2)() = &myFunc;
22 
23  
24 
25     printf("p1==p2 %d \n", p1 == p2);//1
26 
27     printf("&myFunc==myFunc %d \n", &myFunc == myFunc);//1
28 
29  
30 
31     myFunc();//每次调用函数是把代码拷贝到这里执行还是跳转过去执行??
32 
33     //下面的写法能调用,不推荐写
34 
35     (*myFunc)();//ok
36 
37     (&myFunc)();//ok
38 
39     (*p1)();//ok
40 
41     (**p1)();//ok
42 
43     (***p1)();//ok
44 
45     (****p1)();//ok
46 
47     return 0;
48 
49 }
50 
51 /*
52 
53 * 问题:怎么找到函数的代码块执行的?
54 
55 * 根据函数地址定位到内存地址,()表示执行对应的代码块。
56 
57 结论:函数名就是一个隐式的指针,函数名在程序里面,就是指针地址的别名。
58 
59  
60 
61 */
62 
63  

 


 

024main函数参数和回调函数

 1 #include<stdio.h>
 2 
 3  
 4 
 5 int myFunc1(int a, int b) { return a + b; }
 6 
 7 int myFunc2(int a, int b) { return a - b; }
 8 
 9  
10 
11 //测试函数指针类型的函数--函数指针来实现
12 
13 int testFunc(int (*pFunc)(int, int),int a,int b)
14 
15 {
16 
17     return (*pFunc)(a, b);
18 
19 }
20 
21  
22 
23 int main(int argc,char *argv[])
24 
25 {
26 
27     //第一个参数是程序的文件名,省下的参数是程序需要传递的参数
28 
29     printf("argc=%d \n", argc);
30 
31     printf("argv[0]=%s \n", argv[0]);
32 
33  
34 
35     //回调函数
36 
37     int a = 11;
38 
39     int b = 22;
40 
41     printf("通过回调函数调用=%d \n", testFunc(myFunc1, a, b));
42 
43     printf("通过回调函数调用=%d \n", testFunc(myFunc2, a, b));
44 
45  
46 
47     return 0;
48 
49 }
50 
51 /*
52 
53 结论:
54 
55 (1)main函数参数第一个是传递的参数个数,第二个是一个字符指针数组
56 
57 (2)回调函数需要通过函数指针来实现
58 
59 解耦合--让函数开发者和函数使用者可以分开实现。
60 
61 2023年5月6日 09:26:19
62 
63 */

 

 

025结构体内存对齐

 1 #include<stdio.h>
 2 
 3 struct T1
 4 
 5 {
 6 
 7     int a;
 8 
 9     int* p;
10 
11     char c;
12 
13 };
14 
15  
16 
17 struct T2
18 
19 {
20 
21     char a;
22 
23 };
24 
25  
26 
27 struct  T3
28 
29 {
30 
31     int* a;
32 
33 };
34 
35  
36 
37 int main(void)
38 
39 {
40 
41     printf("sizeof(T1)=%d \n", sizeof(T1));//24
42 
43     printf("sizeof(T2)=%d \n", sizeof(T2));//1
44 
45     printf("sizeof(T3)=%d \n", sizeof(T3));//8
46 
47  
48 
49     return 0;
50 
51 }
52 
53 /*
54 
55 结论:结构体一般默认是4K对齐
56 
57 结构体整体大小与所有成员的大小有关,但是并不是简单的相加。这种现象我们称为内存对齐。
58 
59  
60 
61 1 结构体变量的 起始地址 要能被其最大的成员整除
62 
63 2 结构体变量的 总体大小 要能被其最大的成员整除
64 
65 3 结构体变量的 每个成员 相对于开始地址的偏移量,要被其自身大小整除,如果长度不够,则在前一个成员后面补
66 
67 */
68 
69  

 


 

026结构体指针

 1 #include<stdio.h>
 2 
 3 #include<string.h>
 4 
 5 #include<stdlib.h>
 6 
 7 struct T1
 8 
 9 {
10 
11     int a;
12 
13     char name[10];
14 
15  
16 
17 };
18 
19 int main(void)
20 
21 {
22 
23     struct T1 t;
24 
25     t.a = 11;
26 
27     strcpy_s(t.name, "aaaa");
28 
29     printf("sizeof(t)=%d \n", sizeof(t));//16
30 
31  
32 
33     //定义结构体指针,来进行访问
34 
35     struct T1* pt = &t;
36 
37     printf("pt->a=%d,pt->name=%s \n", pt->a, pt->name);
38 
39  
40 
41     //动态内存分配方式
42 
43     struct T1* pt2 = (struct T1*)malloc(sizeof(T1));
44 
45    
46 
47     free(pt2);
48 
49     return 0;
50 
51 }

 


 

027结构体多级指针

 1 #include<stdio.h>
 2 
 3 #include<string.h>
 4 
 5 #include<stdlib.h>
 6 
 7  
 8 
 9 struct T2
10 
11 {
12 
13     int c;
14 
15     char* p;
16 
17 };
18 
19 struct T1
20 
21 {
22 
23     int a;
24 
25     char *name;
26 
27     struct T2* t2;
28 
29 };
30 
31 int main(void)
32 
33 {
34 
35  
36 
37     //动态内存分配方式
38 
39     struct T1* p1 = (struct T1*)malloc(sizeof(T1));//堆区,要手动释放
40 
41     p1->a = 11;
42 
43     p1->name = (char*)malloc(128);
44 
45     strcpy_s(p1->name, strlen("aaaa")+1, "aaaa");
46 
47  
48 
49     struct T2* t2 = (struct T2*)malloc(sizeof(struct T2));
50 
51     t2->c = 22;
52 
53     t2->p = (char*)malloc(128);
54 
55     strcpy_s(t2->p,strlen("bbbbb") + 1, "bbbbb");
56 
57     printf("t2->p=%s \n", t2->p);
58 
59  
60 
61     free(p1->name);
62 
63     free(t2->p);
64 
65     free(t2);
66 
67     free(p1);
68 
69  
70 
71     return 0;
72 
73 }
74 
75 /*
76 
77 结论:
78 
79 1 指针在使用前一定要分配空间,否则就是野指针
80 
81 2 使用 malloc 分配的空间是在堆区,一定要手动释放,有多少个 malloc 就应该有多少个与其对应的 free
82 
83 3 使用 free 释放空间的时候,要从小到大,从里到外
84 
85 */
86 
87  

 


 

028calloc与realloc

 1 #include<stdio.h>
 2 
 3 #include<string.h>
 4 
 5 #include<stdlib.h>
 6 
 7  
 8 
 9 int main(void)
10 
11 {
12 
13     int* p1 = (int*)malloc(sizeof(int) * 10);//手动清0
14 
15     //memset(p1, 0, sizeof(int) * 10);
16 
17     int* p2 = (int*)calloc(10, sizeof(int));//自动清0
18 
19  
20 
21     for (int i = 0; i < 10; i++)
22 
23     {
24 
25         printf("%d==", p1[i]);//随机值
26 
27     }
28 
29     printf("\n");
30 
31     for (int i = 0; i < 10; i++)
32 
33     {
34 
35         printf("%d==", p2[i]);//0
36 
37     }
38 
39     printf("\n");
40 
41     /*
42 
43         -842150451==-842150451==-842150451==-842150451==-842150451==-842150451==
44 
45         -842150451==-842150451==-842150451==-842150451==
46 
47         0==0==0==0==0==0==0==0==0==0==
48 
49     */
50 
51  
52 
53     p1 = (int*)realloc(p1, sizeof(int) * 100);//将p1更改为100*4大小
54 
55  
56 
57     free(p1);
58 
59     free(p2);
60 
61  
62 
63     return 0;
64 
65 }
66 
67 /*
68 
69 结论:
70 
71 (1)
72 
73 函数原型:void* calloc(unsigned int num,unsigned int size);
74 
75 功能:在内存的动态存储区中分配num个长度为size的连续空间,函数返回一个指向分配起始地址的指针;
76 
77 如果分配不成功,返回NULL。
78 
79 calloc分配内存会自动清0,malloc不会自动清零。
80 
81 (2)void *realloc(void *mem_address, unsigned int newsize);
82 
83 指针名=(数据类型*)realloc(要改变内存大小的指针名,新的大小)。
84 
85 realloc 是表示将原有的指针变量的空间进行扩充,如果原指针指向的空间后面还有足够大的空间,
86 
87 就是直接在原地址扩充,
88 
89  * 如果原地址后面没有足够大的空间,则会开辟新地址,并将原来的数据拷贝到新空间
90 
91 */
92 
93  

 


 

029C和C++中动态内存管理

  1 #include<stdio.h>
  2 
  3 #include<string.h>
  4 
  5 #include<stdlib.h>
  6 
  7  
  8 
  9 int main(void)
 10 
 11 {
 12 
 13  
 14 
 15     //C语言形式
 16 
 17     int* p = NULL;
 18 
 19     p = (int*)malloc(sizeof(int));
 20 
 21     if (p != NULL)
 22 
 23     {
 24 
 25         *p = 123;
 26 
 27         printf("*p=%d \n", *p);
 28 
 29         free(p);
 30 
 31     }
 32 
 33  
 34 
 35     //C++形式
 36 
 37     int* p1 = new int;
 38 
 39     if (p1 != NULL)
 40 
 41     {
 42 
 43         *p1 = 123;
 44 
 45         printf("*p1=%d \n", *p1);
 46 
 47         delete p1;
 48 
 49     }
 50 
 51     int* p2 = new int(4);
 52 
 53     if (p2 != NULL)
 54 
 55     {
 56 
 57         *p2 = 123;
 58 
 59         printf("*p2=%d \n", *p2);
 60 
 61         delete p2;
 62 
 63     }
 64 
 65  
 66 
 67     int* p3 = new int[4];
 68 
 69     if (p3 != NULL)
 70 
 71     {
 72 
 73         *p3 = 123;
 74 
 75         *(p3 + 1) = 456;
 76 
 77         *(p3 + 2) = 789;
 78 
 79         *(p3 + 3) = 101;
 80 
 81         printf("*p3[0]=%d \n", p3[0]);
 82 
 83         printf("*p3[1]=%d \n", p3[1]);
 84 
 85         printf("*p3[2]=%d \n", p3[2]);
 86 
 87         printf("*p3[3]=%d \n", p3[3]);
 88 
 89         delete []p3;
 90 
 91     }
 92 
 93     return 0;
 94 
 95 }
 96 
 97 /*
 98 
 99 结论:
100 
101  * 栈区  局部变量,由程序自己控制,分配和销毁操作非常快,无法手动管理,但是栈区的空间是有限的,如果把非常大的一个变量放在栈区,或者是执行多次压栈的操作,有可能会爆栈
102 
103  * 堆区  手动开辟的内存空间都在这里,只要不是特别大,一般都能分配成功,一般是用 malloc/new 来开辟,用 free/delete 来释放,由开发者手动操作
104 
105  * 常量区 双引号
106 
107  * 静态区,全局变量区
108 
109  * 代码区
110 
111  *
112 
113  * malloc/free 一般在c语言中使用,是函数
114 
115  * new/delete 一般在c++中使用,是运算符,本质上也是做内存管理,但是做的事情比malloc/free 更多
116 
117  
118 
119  1 指针变量名=new 类型关键字
120 
121  2 指针变量名=new 类型关键字(初始值)
122 
123  3 指针变量名=new 类型关键字[]
124 
125 */
126 
127  

 


 

030NULL与nullptr

 1 #include<stdio.h>
 2 
 3 #include<string.h>
 4 
 5 #include<stdlib.h>
 6 
 7  
 8 
 9  
10 
11 int main(void)
12 
13 {
14 
15     int* p1 = NULL;
16 
17     int* p2 = nullptr;
18 
19     char* p3 = NULL;
20 
21     char* p4 = nullptr;
22 
23     //printf("p1==p3 %d \n", p1 == p3);//error类型不兼容
24 
25     printf("p1==p3 %d \n", p1 == p2);//1
26 
27  
28 
29     int a = NULL;
30 
31     //int b = nullptr;//error
32 
33     return 0;
34 
35 }
36 
37 /*
38 
39 结论:
40 
41  * NULL和nullptr 在表示指针类型的变量时,是相等的,都是表示空指针
42 
43  *但是两者是完全不一样的数据类型,没办法直接等于
44 
45  * NULL 在表示指针类型的变量时,是空指针,实际上是int 0
46 
47  * 在c++中,一般用nullptr 表示指针类型变量的初始值
48 
49  
50 
51 */
52 
53  

 


 

031mew和delete

 

 

  1 #include<iostream>
  2 
  3 using namespace std;
  4 
  5  
  6 
  7 class T
  8 
  9 {
 10 
 11 public:
 12 
 13     T() { cout << "T 构造函数" << endl; }
 14 
 15     ~T() { cout << "T 析构函数" << endl; }
 16 
 17 };
 18 
 19  
 20 
 21 int main(void)
 22 
 23 {
 24 
 25     int* p1 = (int*)malloc(sizeof(int));
 26 
 27     if (p1 != NULL)
 28 
 29     {
 30 
 31         free(p1);
 32 
 33     }
 34 
 35  
 36 
 37     int* p2 = new int;
 38 
 39     if (p2 != NULL)
 40 
 41     {
 42 
 43         delete p2;
 44 
 45     }
 46 
 47  
 48 
 49     //自定义数据类型
 50 
 51     T* p3 = (T*)malloc(sizeof(T));
 52 
 53     if (p3 != NULL)
 54 
 55     {
 56 
 57         free(p3);
 58 
 59     }
 60 
 61  
 62 
 63     T* p4 = new T();
 64 
 65     if (p4 != NULL)
 66 
 67     {
 68 
 69         delete p4;
 70 
 71     }
 72 
 73  
 74 
 75     int* p5 = new int[4];
 76 
 77     delete[]p5;
 78 
 79  
 80 
 81     T* p6 = new T[6];
 82 
 83     delete[]p6;
 84 
 85  
 86 
 87     return 0;
 88 
 89 }
 90 
 91 /*
 92 
 93 结论:
 94 
 95  * new 在分配空间的时候,还做了初始化操作,就是new 一个类的时候,如果有构造函数,则会调用,
 96 
 97  delete 的时候,如果有析构,也会调用,malloc 和 free 不会
 98 
 99  * 这个主要体现在自定义类里面,其它内置类型,没有构造和析构的时候,表现出来的是一样的效果
100 
101  * new [] 和  delete []一定要成对使用
102 
103  
104 
105 */

 

032智能指针介绍

 1 #include<iostream>
 2 
 3  
 4 
 5 int main(void)
 6 
 7 {
 8 
 9     //情景演示:当有多个指针指向同一个内存地址,如何释放????
10 
11     int* p1 = new int;
12 
13     int* p2 = p1;
14 
15     int* p3 = p1;
16 
17     int* p4 = p1;
18 
19     printf("p1=%p \n", p1);
20 
21     printf("p2=%p \n", p2);
22 
23     printf("p3=%p \n", p3);
24 
25     printf("p4=%p \n", p4);
26 
27  
28 
29     delete p1;
30 
31     //delete p2;
32 
33     //delete p3;
34 
35     //delete p4;
36 
37     return 0;
38 
39 }
40 
41 /*
42 
43 结论:
44 
45  *
46 
47  * malloc/free    new/delete 都必须得特别小心,特别考验技术
48 
49  *
50 
51  * 从c++98开始,就引入了一个智能指针的概念,主要是为了解决动态内存分配繁琐的问题
52 
53  * 智能指针其实是将new/delete 作了一层封装,对外提供接口,让开发者更方便的去做内存管理
54 
55  *
56 
57  * 智能指针--> new/delete --> malloc/free
58 
59  *
60 
61  * 优点就是方便进行动态内存管理,减少程序出bug的概率 (其实就是帮你进行delete 操作,保证忘记delete 或者有多个指针指向同一个内存地址而不方便释放的时候,保证程序不会出现内存泄漏)
62 
63  *
64 
65  * auto_ptr(c++98) 目前基本上不再使用,也不建议使用
66 
67  *
68 
69  * shared_ptr(c++11) 共享
70 
71  * unique_ptr(c++11) 独占【可以想像成程序里面的锁】 基本上代替了 auto_ptr
72 
73  * weak_ptr(c++11) 配合 shared_ptr 使用
74 
75  *
76 
77  *
78 
79     p1=000001F68BE83B40
80 
81     p2=000001F68BE83B40
82 
83     p3=000001F68BE83B40
84 
85     p4=000001F68BE83B40
86 
87  *
88 
89 */
90 
91  

 


 

033shared_ptr定义和初始化

 1 #include<iostream>
 2 
 3 using namespace std;
 4 
 5  
 6 
 7 //智能指针做函数返回值
 8 
 9 shared_ptr<int>myFunc(int a)
10 
11 {
12 
13     return make_shared<int>(a);
14 
15 }
16 
17  
18 
19 int main(void)
20 
21 {
22 
23     //定义
24 
25     shared_ptr<int>p1;//shared_ptr定义完成后就是一个空指针
26 
27  
28 
29     int* p2 = new int;//如果没有初始化,p2就是一个野指针
30 
31     cout <<(p1 == nullptr) << endl;//1
32 
33  
34 
35     //初始化方法1
36 
37     shared_ptr<int>p3(new int(123));
38 
39     //shared_ptr<int>p4 = new int(123);
40 
41     //无法从“int * ”转换为“std::shared_ptr<int>”
42 
43  
44 
45     shared_ptr<int>p4 = myFunc(123);
46 
47     shared_ptr<int>p5 = p3;
48 
49     shared_ptr<int>p6(p5);
50 
51  
52 
53     //用new 定义的指针变量我们称之为裸指针  0x123456
54 
55     int* p7 = new int(123);
56 
57  
58 
59     //这种写法在语法上没有任何问题,但是不能这样使用,
60 
61     //就是说,不建议裸指针来初始化智能指针,也就是说,不建议裸指针和智能指针混搭
62 
63     shared_ptr<int>p8(p7);
64 
65     //shared_ptr<int>p9 = p7;//不合法,原因同上
66 
67  
68 
69     free(p2);
70 
71     //free(p7);//已经初始化了p8,没办法释放了
72 
73     return 0;
74 
75 }
76 
77 /*
78 
79 结论:
80 
81 类模板格式定义智能指针
82 
83 shared_ptr<数据类型>指针变量名;
84 
85 */
86 
87  

 


 

034shared_ptr共享原理和引用计数

  1 #include<iostream>
  2 
  3 using namespace std;
  4 
  5  
  6 
  7 void func1(shared_ptr<int> a)
  8 
  9 {
 10 
 11     cout << a.use_count() << endl;
 12 
 13     return;
 14 
 15 }
 16 
 17  
 18 
 19 shared_ptr<int> func2(shared_ptr<int>& a)
 20 
 21 {
 22 
 23     return a;
 24 
 25 }
 26 
 27  
 28 
 29 int main(void)
 30 
 31 {
 32 
 33     shared_ptr<int>p1 = make_shared<int>(123);
 34 
 35     shared_ptr<int>p2 = p1;
 36 
 37     shared_ptr<int>p3(p2);
 38 
 39     p1.reset();//将p1的指向重置
 40 
 41     cout << p2.use_count() << "--" << p3.use_count() << endl;//2--2
 42 
 43  
 44 
 45     p2 = make_shared<int>(456);
 46 
 47     cout << p2.use_count() << "--" << p3.use_count() << endl;//1--1
 48 
 49  
 50 
 51     func1(p1);
 52 
 53     shared_ptr<int>p4= func2(p1);
 54 
 55  
 56 
 57     return 0;
 58 
 59 }
 60 
 61 /*
 62 
 63 结论:
 64 
 65  * shared_ptr 共享智能指针,所谓共享,是指有可能有其它的指针指向该块内存,同时也具有读写和销毁的权限
 66 
 67  *
 68 
 69  * 实现智能管理的原理是,每个shared_ptr 指针变量都会维护一个其指向自身指向的那个内存空间的引用计数器,并随时同步更新,以达到与其它shared_ptr同步的目的
 70 
 71  * 维护这个计数器要有额外的开销
 72 
 73  *
 74 
 75  *
 76 
 77  * 引用计数器的增加和删除
 78 
 79  * 1 新建一个新的shared_ptr 并初始化其指向,此时,该变量的引用计数器为1
 80 
 81  * 2 用上面的shared_ptr 变量初始化一个新的 shared_ptr,此时,指同同一个内存地址的shared_ptr 的引用计数器都要加1
 82 
 83  * 3 如果将shared_ptr 作为一个实参传递到一个函数里面,在函数生命周期内,函数也有操作该内存的权限,引用计数器也要加1,如果作为引用传参,计数器不会加1
 84 
 85  * 4 如果函数将一个shared_ptr 作为返回值返回,并且有用变量接收,则指向对应的内存地址的shared_ptr 引用计数器也要加1
 86 
 87  *
 88 
 89  *
 90 
 91  * 引用计数器的减小和内存空间的释放
 92 
 93  * 当指向内存空间的shared_ptr 不再指向该内存空间的时候,其它指向该空间的shared_ptr 的引用计数器都会减1
 94 
 95  * 当最后一个指向该内存空间的shared_ptr 被释放或销毁时,该内存空间就
 96 
 97  *
 98 
 99  * shared_ptr 共享智能指针,所谓共享,是指有可能有其它的指针指向该块内存,同时也具有读写和销毁的权限
100 
101  *
102 
103  * 实现智能管理的原理是,每个shared_ptr 指针变量都会维护一个其指向自身指向的那个内存空间的引用计数器,并随时同步更新,以达到与其它shared_ptr同步的目的
104 
105  * 维护这个计数器要有额外的开销
106 
107  *
108 
109  * 引用计数器的增加和删除
110 
111  * 1 新建一个新的shared_ptr 并初始化其指向,此时,该变量的引用计数器为1
112 
113  * 2 用上面的shared_ptr 变量初始化一个新的 shared_ptr,此时,指同同一个内存地址的shared_ptr 的引用计数器都要加1
114 
115  * 3 如果将shared_ptr 作为一个实参传递到一个函数里面,在函数生命周期内,函数也有操作该内存的权限,引用计数器也要加1,如果作为引用传参,计数器不会加1
116 
117  * 4 如果函数将一个shared_ptr 作为返回值返回,并且有用变量接收,则指向对应的内存地址的shared_ptr 引用计数器也要加1
118 
119  *
120 
121  *
122 
123  * 引用计数器的减小和内存空间的释放
124 
125  * 当指向内存空间的shared_ptr 不再指向该内存空间的时候,其它指向该空间的shared_ptr 的引用计数器都会减1
126 
127  * 当最后一个指向该内存空间的shared_ptr 被释放或销毁时,该内存空间就会交还给操作系统
128 
129  *
130 
131  * 参数未使用,被编译器优化了
132 
133  * 会交还给操作系统
134 
135 * 参数未使用,被编译器优化了
136 
137 */
138 
139  

 


 

035shared_ptr常用操作

 1 #include<iostream>
 2 
 3 using namespace std;
 4 
 5  
 6 
 7 int main(void)
 8 
 9 {
10 
11     shared_ptr<int>p1(make_shared<int>(123));
12 
13     cout << p1.unique() << endl;//1
14 
15     cout << "p1引用计数p1.use_count() " << p1.use_count() << endl;//1
16 
17     shared_ptr<int>p2(p1);
18 
19     cout << "p1引用计数p1.use_count() " << p1.use_count() << endl;//2
20 
21     cout << "p1引用计数p2.use_count() " << p2.use_count() << endl;//2
22 
23     cout << p1.unique() << endl;//0
24 
25     p1.reset(new int(456));
26 
27     // p1.get() = 0000022EF53E8650   p2.get() = 0000022EF53E0830
28 
29     cout << "p1.get()=" << p1.get() << "\t p2.get()=" << p2.get() << endl;
30 
31  
32 
33     shared_ptr<int>p3(make_shared<int>(789));
34 
35     cout << "*p1=" << *p1 << "\t" << "p1=" << p1 << endl;
36 
37     cout << "*p3=" << *p3 << "\t" << "p3=" << p3 << endl;
38 
39     p1.swap(p3);
40 
41     cout << "*p1=" << *p1 << "\t" << "p1=" << p1 << endl;
42 
43     cout << "*p3=" << *p3 << "\t" << "p3=" << p3 << endl;
44 
45     /*
46 
47     *p1=456 p1=00000162E2148E20
48 
49     *p3=789 p3=00000162E2140180
50 
51     *p1=789 p1=00000162E2140180
52 
53     *p3=456 p3=00000162E2148E20
54 
55     */
56 
57  
58 
59     return 0;
60 
61 }
62 
63 /*
64 
65 结论:
66 
67  * use_count()   shared_ptr 变量所指向的内存空间的引用次数
68 
69  * unique()   shared_ptr 是否是独占其指向的内存地址,如果只有一个shared_ptr 指向,那么值为true,
70 
71  *如果有其它shared_ptr指向该内存地址,则为false
72 
73  *如果是空指针,也是false
74 
75  *
76 
77  * reset()   重置,无参,如果是独占,则销毁其指向的内存空间,并将当前share_ptr变量置为空指针
78 
79  * 如果不是独占,则将其它指向该内存的shared_ptr 变量的引用计数器减1,并将当前变量置为空指针
80 
81  *
82 
83  *  有参,如果是独占,则销毁其指向的内存空间,并将当前share_ptr变量指向新地址
84 
85  *  如果不是独占,则将其它指向该内存的shared_ptr 变量的引用计数器减1,并将当前share_ptr变量指向新地址
86 
87  *
88 
89  * get()  取指针地址  是为了一些其它的需求或方法要使用地址
90 
91  *
92 
93  * swap() 交换指向
94 
95  
96 
97 */
98 
99  

 


 

036shared_ptr删除器

  1 #include<iostream>
  2 
  3 using namespace std;
  4 
  5  
  6 
  7 void myFunc01(int* p)
  8 
  9 {
 10 
 11     cout << "自定义删除器11" << endl;
 12 
 13     delete p;
 14 
 15 }
 16 
 17 void myFunc02(int* p)
 18 
 19 {
 20 
 21     cout << "自定义删除器22" << endl;
 22 
 23     delete p;
 24 
 25 }
 26 
 27  
 28 
 29 class T
 30 
 31 {
 32 
 33 public:
 34 
 35     T() { cout << "构造函数" << endl; }
 36 
 37     ~T() { cout << "析构函数" << endl; }
 38 
 39 };
 40 
 41 void myFunc03(T*p)
 42 
 43 {
 44 
 45     delete[]p;
 46 
 47 }
 48 
 49  
 50 
 51 int main(void)
 52 
 53 {
 54 
 55     T *pt = new T[4];
 56 
 57     delete[]pt;
 58 
 59  
 60 
 61     shared_ptr <T>p1(new T[3], myFunc03);//元素是数组时,必须自定义删除器
 62 
 63     shared_ptr<T>p2(new T[3], default_delete<T[]>());
 64 
 65  
 66 
 67     //c++17开始支持这种写法,就可以很好的处理数组删除的问题
 68 
 69     //shared_ptr<T[]>(new T[3]);
 70 
 71  
 72 
 73     //赋值操作也会自动赋值删除器
 74 
 75     shared_ptr<int>p3(new int(123), myFunc01);
 76 
 77     shared_ptr<int>p4(new int(123));
 78 
 79     p4 = p3;
 80 
 81  
 82 
 83     //可以使用lambda表达式实现
 84 
 85     shared_ptr<char>c1(new char('a'), [](char*p) {
 86 
 87         cout << "这里是lambda删除" << endl;
 88 
 89         delete p;
 90 
 91         });
 92 
 93  
 94 
 95     auto myLambda = [](int*p)
 96 
 97     {
 98 
 99         cout << "lambda删除器" << endl;
100 
101         delete p;
102 
103     };
104 
105     shared_ptr<int>p5(new int(123), myLambda);
106 
107  
108 
109     return 0;
110 
111 }
112 
113 /*
114 
115 结论:
116 
117  * shared_ptr 自定义删除器
118 
119  *
120 
121  * make_shared 不支持
122 
123  *
124 
125 构造函数
126 
127 构造函数
128 
129 构造函数
130 
131 构造函数
132 
133 析构函数
134 
135 析构函数
136 
137 析构函数
138 
139 析构函数
140 
141 构造函数
142 
143 构造函数
144 
145 构造函数
146 
147 构造函数
148 
149 构造函数
150 
151 构造函数
152 
153 lambda删除器
154 
155 这里是lambda删除
156 
157 自定义删除器11
158 
159 析构函数
160 
161 析构函数
162 
163 析构函数
164 
165 析构函数
166 
167 析构函数
168 
169 析构函数
170 
171  *
172 
173 */
174 
175  

 


 

037weak_ptr

 1 #include<iostream>
 2 
 3 using namespace std;
 4 
 5  
 6 
 7 int main(void)
 8 
 9 {
10 
11     shared_ptr<int>p1(new int(123));//ok
12 
13     //weak_ptr<int>p2(new int(456));//error 没有与参数匹配的构造函数
14 
15  
16 
17     //weak_ptr<int>p2(make_shared<int>(new int(456)));//ok
18 
19     //weak_ptr<int>p2 = make_shared<int>(new int(456));//ok 但是不能操作内存
20 
21     //使用shared_ptr初始化weak_ptr
22 
23     weak_ptr<int>p2(p1);//1个shared_ptr指针,一个weak_ptr
24 
25     auto p3 = p2.lock();////增加一个shared_ptr 计数器
26 
27     shared_ptr<int>p4 = p2.lock();////增加一个shared_ptr 计数器
28 
29  
30 
31     p2.reset();
32 
33     p1.reset();
34 
35     cout << p2.expired() << endl;//1 --只有强引用才有这个函数
36 
37  
38 
39     return 0;
40 
41 }
42 
43 /*
44 
45 结论:
46 
47 * shared_ptr   strong
48 
49  * weak_ptr    weak
50 
51  * weak_ptr 不能用裸指针初始化,可以用make_shared初始化,
52 
53  * 但是直接用make_shared 初始化没有任何意义,这是因为不能直接用weak_ptr 去操作对应的内存空间,必须依附于shared_ptr 来操作
54 
55  * weak_ptr 就是打辅助
56 
57  * 当一个shared_ptr 新增一个weak_ptr的时候,其weak_ptr 引用计数器会加1,当销毁一个weak_ptr的时候,其weak_ptr引用计数器会减1,
58 
59  * 但是,不能直接使用weak_ptr 去操作指向的内存
60 
61  *
62 
63  * 相反,当一个shared_ptr 销毁时,指向其的weak_ptr 将会变成expired(过期,失去生命周期)的状态*
64 
65  * lock(); 增加一个 shared_ptr 计数器(返回一个shared_ptr)
66 
67  * use_count() shared_ptr 计数器
68 
69  * expired()  是否过期,当其对应的shared_ptr 羡慕后,此处就返回true
70 
71  * reset()  减少一个weak_ptr 引用计数器
72 
73 */

 

 

038unique_ptr定义和初始化

 1 #include<iostream>
 2 
 3 using namespace std;
 4 
 5  
 6 
 7 int main(void)
 8 
 9 {
10 
11     shared_ptr<int>p1(new int(123));
12 
13     //只能有一个指针指向内存空间,所以有move语义
14 
15     unique_ptr<int>p2(new int(456));
16 
17  
18 
19     return 0;
20 
21 }
22 
23 /*
24 
25 结论:
26 
27  * shared_ptr 共享式智能指针,可以用时有多个shared_ptr 指向同一个内存空间,并且这些shared_ptr 变量都对该内存空间有操作权限,
28 
29  * 而且这些shared_ptr 间共享引用计数器
30 
31  * unique_ptr 独占式智能指针,同一时间只能有一个unique_ptr 变量指向同一个内存空间,
32 
33  * 且只有此unique_ptr 对该内存空间拥有操作权限
34 
35  *
36 
37  *
38 
39  * unique_ptr<int>p1   定义完了就是个空指针
40 
41  *
42 
43  *
44 
45  *  unique_ptr<int>p1;
46 
47     p1 = make_unique<int>(123);
48 
49     unique_ptr<int>p2(make_unique<int>(456));     make_unique  c++14之后开始引入,且不支持自定义删除器
50 
51     unique_ptr<int>p3(new int(789));
52 
53  
54 
55    unique_ptr<int>p6=move(p1);   把p1 销毁,并且将p1原来维护的内存空间的权限转移给p6
56 
57  
58 
59    p6 = make_unique<int>(321); 重新赋值,把原来维护的内存空间销毁掉
60 
61  
62 
63      不支持
64 
65     //unique_ptr<int>p4=new int(321);
66 
67     //unique_ptr<int>p4(p1);//因为只能有一个指针指向内存空间
68 
69     //unique_ptr<int>p5=p1;
70 
71 */
72 
73  

 


 

039unique_ptr常用操作

 1 #include<iostream>
 2 
 3 using namespace std;
 4 
 5  
 6 
 7 int main(void)
 8 
 9 {
10 
11     unique_ptr<int>p1 = make_unique<int>(123);
12 
13     cout << "p1.get()" << p1.get() << endl;
14 
15     unique_ptr<int>p2 = make_unique<int>(456);
16 
17     p1.swap(p2);
18 
19  
20 
21     //int* pTmp = p1.release();
22 
23     p1.reset(new int(789));
24 
25     return 0;
26 
27 }
28 
29 /*
30 
31 结论:
32 
33 * get() 返回裸指针
34 
35  * =nullptr  把 unique_ptr 指向的内存空间销毁,交还系统,并将unique_ptr 置为空指针
36 
37  * reset()  无参 把 unique_ptr 指向的内存空间销毁,交还系统,并将unique_ptr 置为空指针
38 
39  *有参 把 unique_ptr 指向的原内存空间销毁,交还系统,并将unique_ptr 指向新地址
40 
41  *
42 
43  * release()    返回裸指针,将unique_ptr 变量置为空指针,此处的内存空间不再由unique_ptr 变量维护,需要手动释放
44 
45  * reset(release())
46 
47  * swap()
48 
49  *
50 
51  
52 
53 */
54 
55  

 


 

040unique_ptr删除器

  1 #include<iostream>
  2 
  3 using namespace std;
  4 
  5 void func1(int* p)
  6 
  7 {
  8 
  9  
 10 
 11     cout << "这里是自定义删除器" << endl;
 12 
 13     delete p;
 14 
 15     p = nullptr;
 16 
 17 }
 18 
 19  
 20 
 21 int main(void)
 22 
 23 {
 24 
 25     //复习shared_ptr
 26 
 27     //shared_ptr<int>p1(new int(123), func1);
 28 
 29    
 30 
 31     //unique_ptr<数据类型,删除器类型>变量名(new 数据类型(初始值),删除器);
 32 
 33     typedef void (*pFunc)(int*);
 34 
 35     using pf = void(*)(int);
 36 
 37     unique_ptr<int, pFunc>p1(new int(123), func1);
 38 
 39  
 40 
 41     /*
 42 
 43     shared_ptr<int>p1(new int(123),[](int *p){
 44 
 45         cout<<"这里是lambda删除器"<<endl;
 46 
 47         delete p;
 48 
 49         p= nullptr;
 50 
 51     });
 52 
 53     */
 54 
 55     auto lambda = [](int* p)
 56 
 57     {
 58 
 59         cout << "这里是lambda删除器" << endl;
 60 
 61         delete p;
 62 
 63         p = nullptr;
 64 
 65     };
 66 
 67     shared_ptr<int>p2(new int(123), lambda);
 68 
 69     unique_ptr<int, decltype(lambda)>p3(new int(123), lambda);
 70 
 71    
 72 
 73  
 74 
 75     //unique_ptr 转 shared_ptr
 76 
 77     //当unique_ptr 为右值时,可转成shared_ptr
 78 
 79     //右值,等号右边的值,必须得放在运算符右边   左值 运算符 右值
 80 
 81  
 82 
 83     //0x00007fc92df04080
 84 
 85     unique_ptr<int>p4 = make_unique<int>(123);//ok
 86 
 87     shared_ptr<int>p5 = make_unique<int>(123);//ok
 88 
 89  
 90 
 91     //shared_ptr<int>p3=p1;//error
 92 
 93     shared_ptr<int>p6 = move(p1);//move 把左值转右值
 94 
 95     cout << (p6 == nullptr) << endl;//0
 96 
 97     return 0;
 98 
 99 }
100 
101  

 


 

041智能指针的sizeof

  1 #include<iostream>
  2 
  3 using namespace std;
  4 
  5  
  6 
  7  
  8 
  9 void func1(int* p)
 10 
 11 {
 12 
 13     //cout<<"这里是自定义删除器"<<endl;
 14 
 15     delete p;
 16 
 17     p = nullptr;
 18 
 19 }
 20 
 21 int main(void)
 22 
 23 {
 24 
 25     int a = 123;
 26 
 27     int* p = &a;
 28 
 29     cout << "sizeof(p)=" << sizeof(p) << endl;//8
 30 
 31  
 32 
 33     shared_ptr<int>p2(new int(a));
 34 
 35     shared_ptr<int>p3(make_shared<int>(a));
 36 
 37     shared_ptr<int>p4(p2);
 38 
 39  
 40 
 41     cout << sizeof(p2) << endl;//16
 42 
 43     cout << sizeof(p3) << endl;//16
 44 
 45     cout << sizeof(p4) << endl;//16
 46 
 47  
 48 
 49     unique_ptr<int>p6(new int(a));
 50 
 51     cout << sizeof(p6) << endl;//16
 52 
 53  
 54 
 55     unique_ptr<char>p5(new char('a'));
 56 
 57     cout << sizeof(p5) << endl;//8
 58 
 59  
 60 
 61     using pf = void(*)(int*);
 62 
 63     unique_ptr<int, pf>p7(new int(a), func1);
 64 
 65     cout << sizeof(p7) << endl;//16
 66 
 67  
 68 
 69     auto lambda = [](int* p)
 70 
 71     {
 72 
 73         delete p;
 74 
 75         p = nullptr;
 76 
 77     };
 78 
 79  
 80 
 81     unique_ptr<int, decltype(lambda)>p8(new int(789), lambda);
 82 
 83     cout << sizeof(p8) << endl;//8
 84 
 85  
 86 
 87  
 88 
 89     //delete p;
 90 
 91     return 0;
 92 
 93 }
 94 
 95 /*
 96 
 97 结论:
 98 
 99  * 64位机上,8个字节可以存一个内存地址,所以裸指针的大小是8个字节
100 
101  * shared_ptr 里面,不仅仅只存了对应的堆区的数据域的地址,还有维护额外信息,
102 
103  * 这些信息也要有空间来存储,所以,shared_ptr 里面有两个指针,就是16字节
104 
105  * 同理,weak_ptr 也是一样 是 两个裸指针大小 16字节
106 
107  *
108 
109  * unique_ptr 不需要去维护额外的数据,所以只要存储一个指向数据域的指针即可
110 
111  * 是一个裸指针大小,8字节
112 
113  * 但是,如果有使用自定义删除器,则也需要维护自定义删除器的一些信息,
114 
115  * 要再加一个指针大小的空间,此时是两个裸指针的大小 16字节
116 
117  *
118 
119  * 所以 unique_ptr 的大小是可变的
120 
121  *
122 
123  * 大家可以把智能指针想像成链表里面的一个数据节点,除了数据域之外,还有其它节点的指针域
124 
125 */

 

 

posted @ 2023-05-08 10:40  baixiaolong  阅读(58)  评论(0)    收藏  举报