前言:今天来梳理一下c++的指针吧,哎,我还是更喜欢c#多一点,奈何用c#的太少了,哎。
本文的内容均摘自 primer c++第五版,如果有错的地方那就是我抄错了。
1、指针基础
1.1 基本概念
指针是指向另外一种类型的复合类型。指针专门用来存放地址的。变量的指针就是变量的地址,用来存在变量地址的变量就是指针变量。
指针本身是一个对象,允许对指针赋值和拷贝;指针无需在定义的时候赋值。
除了两种特殊情况,其他的所有指针的类型都要和他指向的对象匹配
int *p1, *p2; //定义两个指向int类型的指针
double *dp1, *dp2; //定义两个指向double类型的指针
定义指针变量的时候注意:
(1)在定义指针变量的时候必须制定基类型
(2)不能用一个整数个一个指针变量赋值
(3)一个指针变量只能指向用一类型的变量
1.2 指针操作
获取对象地址,并通过*p访问对象
int ival=42;
int *p= &ival;
cout<<*p<<endl; //42
cout<<p<<endl; //0x28ff08
复制,此时p2和p存的都是变量ival的地址
int *p2= p;
cout<<*p2<<endl; //42
cout<<p2<<endl; //0x28ff08
改变*p的值
*p=0;
cout<<ival<<endl; //0
cout<<*p<<endl; //0
cout<<p<<endl; //0x28ff08
cout<<*p2<<endl; //0
cout<<p2<<endl; //0x28ff08
1.3 使用* &
//(1)当指针在声明的时候初始化
int i=2;
int *p=&i; //合法,p中存储的是变量i的地址,*p是对p中存放的地址取值,&是对变量i取地址;
int *p = i; //不合法
//(2)先声明,再赋值
int *p;
p=&i; //也合法
*p=i; //语法合法,但是对*p进行操作之前一定要对p进行赋值(初始化)
*p=&i; //不合法
p=i;//不合法
(3)关于引用
int &r=i; //r是一个引用也是i的别名,改变r也能改变i,改变i也能改变r
int &r=*p; //也是合法的,可以简单理解为,*对地址取值,&对变量取地址
&r = j; //不合法,引用绑定之后再无法绑定其他对象
cout<<r<<endl; //4
cout<<&r<<endl; //0x28ff08
1.4 空指针
空指针不指向任何对象,在试图使用一个指针之前可以检查它是否为空,可以通过以下方式生成空指针
int *p=nullptr ; //等价于 int *p=0;
int *p2=0;
//需要首先#include cstdlib
int *p3=NULL; 等价于int *p3=0;
//注意:将int变量赋值给指针是错误的行为,即使变量等于0
int zero=0;
p=zero; //报错
//也可以先声明再赋值
int *p1;
p1=0; //注意此处p1=0和*p1=0的区别
if(p1==0){
cout<<"p1被赋值为空指针"<<endl;
}
int *p1;
*p1=0;
if(p1==0){
cout<<"p1被赋值为空指针"<<endl;
}else{
cout<<"p1不是空指针"<<endl;
}
//打印:p1不是空指针
1.5 赋值和指针
可以给指针重新赋值使指针指向一个新的地址,从而指向一个新的对象
int i=42;
int *p1=0; //p1被初始化一个空指针
int *p2=&i; //p2指向i
int *p3;
p3=p2; //p3也指向i
p2=0; //p2称为一个空指针,不指向任何对象
cout<<*p3<<endl; 42
cout<<p2<<endl; 0
*p3=0; //将地址指向的变量的值变为0
cout<<i<<endl; //0
cout<<*p3<<endl; //0
1.6 指向指针的指针和指向指针的引用
一般来说声明中修饰符的个数并没有限制。当有多个修饰符的时候,按照逻辑关系解释即可,一般从右边向左边阅读变量的定义,离变量名最近的那个符号对变量的类型是最直接的影响。
(1)指向指针的指针
以指针为例,指针是内存中的对象,像其他对象也有地址,因此允许把指针的地址再存放到另一个指针当中。
通过*的个数可以区分指针的级别,**是指向指针的指针,*** 是指向指针的指针的指针
int i=1024;
int *p=&i; //p指向一个int型的数
int **pp=&p; //pp指向一个int型的指针
cout<<i<<endl; //1024
cout<<*p<<endl; //1024
cout<<**p<<endl; //1024
(2)指向指针的引用
int i = 4;
int *p; //p是一个int型指针
int *&r=p; //r是一个对指针p的引用
r=&i; // 等价于p指向i
*r=0; //p指向的对象的值变为0,也就是i的值变为0
1.7 常量指针–指向常量的指针、常指针
(1)常量指针
指向常量的指针不能改变其所指对象的值,想要存放常量对象的地址,只能使用指向常量的指针。
const double pi=3.14; //声明一个常量,不能改变
double *dp=π //不合法,必须采用常量指针指向常量
const double *dp=π //合法
*dp=43; //不合法不可以改变值,但是可以改变dp的指向,使其指向别的double类型的对象
(2)常指针
指定指针变量的值是常量,即指针变量的指向不能改变。(感觉不太对啊)
int a=0;
int b=1;
int const *p=&a;
p=&b; //不合法
2. 指针和函数
函数的参数不仅仅可以是整型、浮点型、字符型,还可以是指针类型,它的作用是将一个变量的地址传给被调用的函数的形参。
栗子:(对输入的两个整数按大小输出)
#include<iostream>
using namespace std;
int main(){
void swap(int *p1, int *p2);
int a,b,*p1,*p2;
cin>>a>>b;
p1=&a;
p2=&b;
if(a<b) swap(p1,p2);
cout<<"max="<<a<<"min="<<b<<endl;
return 0;
}
void swap(int *p1, int *p2){ //函数的作用是将*p1和*p2的值交换
int temp; //temp是整型变量而不是指针变量,如果此时定义的*temp,下一句对*temp赋值使危险的。
temp=*p1;
*p1=*p2;
*p2=temp;
}
3、数组和指针
首先来区分一下指针数组和数组指针。
(1)指针数组:是指一个数组里面装着指针,也即指针数组是一个数组
int *a[10]; //a是含有10个整型指针的数组,也就是数组的元素均为指针,即由指针构成的数组--指针数组

(2)数组指针:是指一个指向数组的指针,它其实还是一个指针,只不过是指向数组而已(数组元素的地址);
int (*pArr1)[10]=&arr; //pArr1指向一个含有10个整数的数组,pArr1是一个指针,指向一个十个元素的int数组,叫数组指针。
当然 ,对修饰符的数量并没有特殊限制
int *(&array)[10]=ptrs; //arry是数组的引用,该数组中含有10个指针
指针与数组
string nums[]={"one","two","three"};
string *p=&nums[0];//p指向nums的第一个元素
string *p2=nums; //等价于p2=&nums[0]
cout<<*p<<endl;//---------------one
cout<<p<<endl; //----------------0x28fecc
++p; //p指向nums[1];
cout<<*p<<endl;//---------------two
cout<<p<<endl;//---------------0x28fed0
指针运算
给指针加上(减去)某整数的值,结果仍然是指针,新指针指向的元素与原来的指针相比前进(后退了)该整数值个位置。
int arr[5]={1,2,3,4,5};
int *ps=arr;
int *pi=ps+3; //指向arr[4]
int *pend=&arr[4];
int count=pend-ps;
cout<<count<<endl; //4
下标和指针
int arr[5]={1,2,3,4,5};
int *ps=arr;
int i;
i=*(ps+2); //相当于i=arr[2];
cout<< i <<endl;
栗子:输出数组的10个元素,三种方法
(1)下标法
#include<iostream>
using namespace std;
int main(){
int a[10];
for(int i=0;i<10;i++){
cin>>a[i];
}
cout<<endl;
for(int j=0;j<10;j++){
cout<<a[j]<<endl;
}
return 0;
}
(2)指针法
把上文中的 cout<<a[j]<<endl; 改成 cout<< *(a+j)<<endl;
(3)指针变量指向数组元素
#include<iostream>
using namespace std;
int main(){
int a[10];
int *p;
p=&a;
for(int i=0;i<10;i++){
cin>>*(p+i);
}
cout<<endl;
for(p=a;p<(a+10);p++){
cout<<*p<<endl; //p先后指向数组中的10个元素
}
return 0;
}
4、字符串和指针
在c++中可以用3种方法访问一个字符串
- 用字符数组存放一个字符串
#include<iostream>
using namespace std;
int main(){
char str[]="I Love China";
cout<<str<<endl;
cout<<str[0]<<endl;
return 0;
}
/*输出:I Love China
I
*/
//str是字符数组名,它代表字符数组的首元素的地址,输出时从str指向的字符开始,逐个输出,直到遇到‘\0’
- 用字符串变量存放字符串
#include<iostream>
#include<string>
using namespace std;
int main(){
string str="I Love China";
cout<<str<<endl;
cout<<str[0]<<endl;
return 0;
}
/*输出:I Love China
I
*/
- 用字符指针指向一个字符串
#include <iostream>
using namespace std;
int main()
{
char *str2="I Love China!";
cout<<str2<<endl;
cout<<*(str2)<<endl;
return 0;
}
利用指针复制字符串
int main()
{
//复制字符串
char strA[]="I Love LGJ";
char strB[20], *p1, *p2;
p1=strA;
p2=strB;
while(*p1!='\0'){
*p2=*p1;
p2++;
p1++;
}
*p2='\0';
p1=strA;
p2=strB;
cout<<p1<<endl;
cout<<p2<<endl;
return 0;
}
5. 指针与对象
6. 指针小结
6.1 指针数据类型小结
| 变量定义 | 类型表示 | 含义 |
|---|---|---|
| int i ; | int | 定义整型变量i |
| int *p | int * | 定义p为指向整型数据的指针变量 |
| int a[5]; | int [5] | 定义整型数组a,它有五个元素 |
| int *p[4] ; | int *[4] | 定义指针数组p,它由4个指向整型数据的指针元素组成 |
| int *p[4] ; | int *[4] | 定义指针数组p,它由4个指向整型数据的指针元素组成 |
| int (*p) [4] ; | int (*)[4] | 定义指针p,指向包含4个元素的一维数组的指针变量 |
| int f() ; | int () | f为返回整型函数值的函数 |
| int *p() ; | int *() | p返回一个指针的函数,该指针指向整型数据 |
| int (*)p() | int (*) () | p为指向函数的指针,该函数返回一个整型值 |
| int **p ; | int ** | 指向指针的指针 |
| int const *p ; | int const * | p常指针,其值是固定的,指向不能变 |
| const int *p | const int * | p为指向常量的指针变量,不能通过p改变其指向的对象的值 |
| const int const *p | const int const * | p为指向常量的常指针,值不能改变,也不能通过p改变其指向的对象的值 |
6.1 指针运算小结
(1)指针加一个整数,减去一个整数
(2)两个指针变量也可以相减
(3)两个指针的比较
若两个指针指向同一个数组的元素,则可以进行比较,指向前面的元素的指针变量小于指向后面元素的指针变量
(4)对指针变量的赋值应该注意类型的问题
2万+

被折叠的 条评论
为什么被折叠?



