C++之指针总结
C++之指针
1 指针基础
在C++中,指针是至关重要的组成部分。它是C++语言最强大的功能之一,也是最棘手的功能之一。
指针具有强大的能力,其本质是协助程序员完成内存的直接操纵

1.1 指针的声明和赋值

声明:变量类型 * 指针变量名;
赋值:指针变量名 = 内存地址值;
int p;:声明整型变量,变量为pint num =10:声明p为指针变量,p存放的为内存地址为什么为int?指针p存放num变量的地址,num本身为int变量。
int * p;
变量类型(如上int)表示,指针(内存地址)指向的内存区域,存放的是整型数据p=#:&:获取num的内存地址,提供给pcout << p;输出num变量地址cout << *p;输出10

1.2 指针解释

1.3 案例
#include"iostream"usingnamespace std;intmain(){system("chcp 65001");{int num =10;//标准的int类型变量,存放int值 10int*p;//声明了一个p指针变量,这个指针变量中记录的地址存的是int类型//指针变量,只能用来记录内存地址 p =#//将num变量的地址,赋予了p指针变量 cout <<"指针变量p中记录的地址是: "<< p << endl;//内存地址 cout <<"&num取地址为: "<<&num << endl;// cout <<"取指针变量记录地址中存放的数值为: "<<*p << endl;//10//直接展示对内存的操纵*p =20;//等同于num=20 cout <<"*p赋值后结果为:"<<*p << endl; cout <<"num结果为:"<< num << endl;return0;}}指针变量p中记录的地址是:0x16443ffc04&num取地址为:0x16443ffc04 取指针变量记录地址中存放的数值为:10*p赋值后结果为:20 num结果为:202 野指针和空指针
野指针:被声明但未初始化(赋值)的指针。这个指针会指向随机的内存空间,可能导致未知问题。

普通变量是对数值进行操作,不会有安全问题,所以没有"野变量"一说。
指针对内存直接操作,所以一旦声明但未赋值,就是"野指针",一旦使用,后果不可预料。

为避免野指针,应养成良好的变成习惯,及时初始化,或将指针置为空指针更为安全。

2.1 案例
#include"iostream"usingnamespace std;intmain(){system("chcp 65001");{int*p;//声明指针变量(p被分配了8个字节的空间) cout << p << endl; cout <<"hello"<< endl;return0;}}
2.2 案例
#include"iostream"usingnamespace std;intmain(){system("chcp 65001");{// int *p; //声明指针变量(p被分配了8个字节的空间)int*p =NULL;//将指针标记为空,无安全隐患int*p1 =nullptr;//将指针标记为空,无安全隐患*p =10;*p1 =10; cout <<"hello"<< endl;return0;}}2.3 总结
声明会立刻分配内存,分配的内存不一定是干净的(比如其它程序残留)。
使用普通变量影响不大,但是指针不一样,会导致安全问题。
1.野指针:仅声明未赋值的指针。不可应用,因为其指向的内存区域是随机的、未知的。
2.空指针:将指针赋值为"空":NULL、nullptr,避免指向具体内存,更加安全。
3.空指针也不是正常的指针,只是过渡,指针最终要给与具体值,否则就不要用指针。
3 指针运算
尽管指针变量内记录的是内存地址,但仍可以进行基础的数学计算。
指针运算是对指针的基础型操作,非常适合操纵数组并配合做动态内存分配。


3.1 案例
#include"iostream"usingnamespace std;intmain(){system("chcp 65001");{int num =10;int*p =# cout <<"指针变量p记录的地址是: "<< p << endl; p++; cout <<"指针变量p进行加1操作,记录的地址是: "<< p << endl;double num1 =10;//double占用8个字节double*p1 =&num1; cout <<"指针变量p1记录的地址是: "<< p1 << endl; p1++; cout <<"指针变量p1进行加1操作,记录的地址是: "<< p1 << endl; p1 +=4; cout <<"指针变量p1进行加4操作,记录的地址是: "<< p1 << endl;int v[]={1,2,3,4,5};//v变量记录的就是数组地址,内存连续排列,每个元素的地址差值就是4个字节int*vp = v;//指针中记录了数组0下标元素的内存地址 cout <<"数组的第一个元素是: "<<*vp << endl; cout <<"数组的第一个元素是: "<< v[0]<< endl; cout <<"数组的第2个元素是: "<<*(vp +1)<< endl;//内存地址正好+4字节,正好是下一个元素的地址 cout <<"数组的第2个元素是: "<< v[1]<< endl;*(vp +2)=33; cout <<"数组的第3个元素是: "<<*(vp +2)<< endl; cout <<"数组的第3个元素是: "<< v[2]<< endl;int v2[]={1,2,3,4,5,6,7};int*p2 = v2;for(int i =0; i <sizeof(v2)/sizeof(v2[0]); i++){ cout <<*(p2 + i);}return0;}}指针变量p记录的地址是:0x2b4d7ff6f4 指针变量p进行加1操作,记录的地址是:0x2b4d7ff6f8 指针变量p1记录的地址是:0x2b4d7ff6e8 指针变量p1进行加1操作,记录的地址是:0x2b4d7ff6f0 指针变量p1进行加4操作,记录的地址是:0x2b4d7ff710 数组的第一个元素是:1 数组的第一个元素是:1 数组的第2个元素是:2 数组的第2个元素是:2 数组的第3个元素是:33 数组的第3个元素是:3312345673.2 练习
有数组:int v1[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
for循环遍历数组,使用指针取出每一个元素并打印输出。
#include"iostream"usingnamespace std;intmain(){system("chcp 65001");{int v2[]={1,2,3,4,5,6,7};int*p2 = v2;for(int i =0; i <sizeof(v2)/sizeof(v2[0]); i++){ cout <<*(p2 + i)<< endl;}return0;}}4 内存动态分配
动态内存分配:即由程序员手动的进行内存空间的分配、内存空间的释放等内存管理操作。

C++代码中,变量、数组等对象的创建,是由C++自动分配内存的为,称之为(自动)静态内存分配。
(自动)静态内存管理,是不会进行内存空间的自动清理的。(无垃圾回收机制)
我们需要手动的管理内存,即手动分配,用完清理。

4.1 案例
#include"iostream"usingnamespace std;intmain(){system("chcp 65001");{int*p =newint;//将new int对象的地址传给变量p*p =10; cout <<"new申请的4字节空间内,存放的是:"<<*p << endl;delete p;//释放内存int*p_arr =newint[5];//申请5元素存放int类型的数组空间// p_arr的地址,就是数组空间的内存区域的开头(第一个元素的位置) p_arr[0]=10;//等同于 *p_arr =10; p_arr[1]=20;//等同于 *(p_arr+1)=20; p_arr[2]=30;//等同于 *(p_arr+1)=20; p_arr[3]=40;//等同于 *(p_arr+1)=20; p_arr[4]=50;//等同于 *(p_arr+1)=20; cout <<"数组的第1个元素是: "<< p_arr[0]<< endl; cout <<"数组的第2个元素是: "<< p_arr[1]<< endl; cout <<"数组的第3个元素是: "<< p_arr[2]<< endl; cout <<"数组的第4个元素是: "<< p_arr[3]<< endl; cout <<"数组的第5个元素是: "<< p_arr[4]<< endl;*(p_arr)=0;*(p_arr +1)=1;*(p_arr +2)=2;*(p_arr +3)=3;*(p_arr +4)=4; cout <<"数组的第1个元素是: "<<*(p_arr)<< endl; cout <<"数组的第2个元素是: "<<*(p_arr +1)<< endl; cout <<"数组的第3个元素是: "<<*(p_arr +2)<< endl; cout <<"数组的第4个元素是: "<<*(p_arr +3)<< endl; cout <<"数组的第5个元素是: "<<*(p_arr +4)<< endl;delete[] p_arr;return0;}}
5 静态内存管理和手动管理方式区别
传统方式创建普通变量或数组,其内存由C++自动管理,称之为:
静态内存管理
- 静态内存管理:不会清理用不到的内存空间
- 动态内存管理:程序员手动管理内存空间
手动管理方式:
- new运算符申请空间,提供该空间的指针(地址)
- delete运算符申请的空间,仅用于new申请的空间
建议:写完new后,立刻写delete,然后再写业务逻辑代码。

优势:
手动控制内存,避免内存空间浪费
劣势:
考验程序员水平,用的好效率高,用不好有反效果
5.1 练习
数组的内存控制
1.通过new运算符,申请10个int元素的数组内存空间并完成赋值。
2.通过for循环,基于指针形式取出数组元素并打印输出。
3.通过delete运算符,清理申请的内存空间。
#include"iostream"usingnamespace std;intmain(){system("chcp 65001");{int*p_arr1 =newint[10];for(int i =0; i <10; i++){*(p_arr1 + i)= i +1;}for(int i =0; i <10;++i){ cout <<*(p_arr1 + i)<< endl;}delete[] p_arr1;return0;}}6 数组元素的移除
C++内置并未提供对数组元素进行增加(插入)、移除的功能,需要手动实现(vector容器提供,后续学习)。
6.1 思路

6.2 案例
#include"iostream"usingnamespace std;intmain(){system("chcp 65001");{// 示例数组int*pArr =newint[5]{1,2,3,4,5};//创建一个新数组,将需要保留的复制到新数组中int*pNewArr =newint[4];//循环去遍历老数组。将需要的元素放入新数组中(不要的要跳过)for(int i =0; i <5; i++){if(i ==2){continue;}if(i >2){ pNewArr[i -1]= pArr[i];}else{ pNewArr[i]= pArr[i];}}delete[] pArr; pArr = pNewArr;//将老数组的指针指向新数组的内存空间for(int i =0; i <4; i++){ cout <<"新数组的元素是: "<< pNewArr[i]<< endl;}return0;}}新数组的元素是:1 新数组的元素是:2 新数组的元素是:4 新数组的元素是:57 数组元素的插入
7.1 思路

7.2 案例
#include"iostream"usingnamespace std;//在下标1和3位置插入数字11和66intmain(){system("chcp 65001");{// 示例数组int*pArr =newint[5]{1,2,3,4,5};//创建一个新数组,将需要保留的复制到新数组中int*pNewArr =newint[7];int offset =0;//循环新数组,挨个进行元素填充(非插入的位置,填充老数组,插入位置填充新数组)for(int i =0; i <7; i++){if(i ==1){ pNewArr[i]=11; offset++;continue;}elseif(i ==3){ pNewArr[i]=66; offset++;continue;}//公式“老数组元素下标 + offset =新数组元素下标 pNewArr[i]= pArr[i - offset];}delete[] pArr; pArr = pNewArr;return0;}}8 指针悬挂
指针指向区域已经被回收(delete),这种问题称之为:指针悬挂。。


所以,总结出两点经验:
1.不要轻易进行指针之间相互赋值
2.delete回收空间前,确保此空间100%不再被使用
9 常量指针
9.1 指向const的指针
指向const的指针:表示指向区域的数据,是不变的,但可以更换指向。

9.1.1 案例
#include"iostream"usingnamespace std;//在下标1和3位置插入数字11和66intmain(){system("chcp 65001");{int num1 =10;int num2 =100;//1.指向const的指针,指向可变。数据不可变constint*p =&num1; cout <<"指针p当前指向的数据是: "<<*p << endl;// *p = 20; p =&num2; cout <<"指针p当前指向的数据是: "<<*p << endl;return0;}}
9.2 const指针
const指针:表示指针本身不可更改,但指向的数据可以更改。

9.2.1 案例
#include"iostream"usingnamespace std;intmain(){system("chcp 65001");{int num1 =10;int num2 =100;// 2. const指针,指向不可变,数据可变int*const p =&num1; cout <<"指针p当前指向的数据是: "<<*p << endl;*p=20; cout <<"指针p当前指向的数据是: "<<*p << endl;// p= &num2;return0;}}
9.3 指向const的const指针
指向const的const指针:指针和指向区域的值,都不可更改。

9.3.1 案例
#include"iostream"usingnamespace std;//在下标1和3位置插入数字11和66intmain(){system("chcp 65001");{int num1 =10;int num2 =100;// 3.指向const的const的指针constint*const p =&num1; cout <<"指针p当前指向的数据是: "<<*p << endl;// p=&num2;// *p = 20;return0;}}
9.4 总结
