指针与指针变量
指针: 一个变量的地址
指针变量: 专门存放变量地址的变量
访问一个变量
①直接:通过变量名访问
②间接:通过指针变量访问
指针变量
声明
static int i;
static int*ptr=&i;//int为指向的对象i类型
int *p1,p2;//p1为指针,p2为变量(对每个指针变量名,都需要一个*)
引用
i=3;
*ptr=3;//*ptr表示指向的那个值
赋值
- 空指针:=NULL
int *p=NULL;//不指向任何对象
*p=8;
①当不知道指向哪里时/为了安全使用
②指向内存位置0的指针
- 空类型指针:void *
char *p1;
void *p2;
p1=(char *)p2;//使用时需要强制转成被赋值类型
p2=(char *)p1;
①当不知道指向哪一种类型时
②使用时需要强制转成被赋值类型
初始化:指针名=地址
-
两不要:
不要使用未初始化的指针变量
不要用内部auto变量初始化static指针 -
可以初始化给:
NULL
已经定义的地址&x或指针*p
动态分配内存
int *ptr3=NULL;
int x=31;//已经定义好的地址
//
int *ptr1=&x;//type*name=initialization(定义好的地址)
等价于👇
int *ptr;//声明一个指针
ptr=&x;//指针名=地址(向指针变量赋值,必须是地址常量或变量,为0时,表空指针)
//
ptr=0;//指针变量=0,表空指针
指针类型
它所指向变量的类型,而非本身数据类型
指针本身的数据值都是:unsigned long int
改变指针
可改:指向常量的指针
int a;
const int *p1=&a;//const说明p1指向常量,const不紧跟p1
int b;
p1=&b;//√ 可以改变指针变量,去指向不同的对象
*p1=1;//× 不能改变指针指向的值,因为const
不可改:指针变量为常量
int a;
int *const p2=&a;//p2指针为const类型,不可改
p2=&b;//× 不能改变访问的对象(p2值不能变)
int *const ptr=&a;//const紧跟ptr
*ptr=7;//√,*ptr is not const(地址不变,指向的可以变)
ptr=&y;//× ptr is const,不能改访问对象(ptr地址不变)
int x=5;
const int *const ptr=&x;//ptr and *ptr are both const
*ptr=7;//× *ptr is const
ptr=&y;//× ptr is const
指针运算
与整数
实质:地址运算
加:下一个
减:上一个
*(pa-n)=pa[-n];//移到前n个数据
*(pa+n)=pa[n];//移到后n个数据
- short*pa:每个变量占两个位置,pa[n]两个两个的移
- long *pa:每个变量占四个位置,pa[n]四个四个的移
指针之间(同类型的指针变量)
- p1-p2:
-
结果为各自指向对象之间间隔的数据个数(为整数)
//计算数组元素个数
p1=&a[0];
p2=&a[末];
p1-p2;//
关系运算(同类型指针)
p==NULL;
p!=NULL;
指针处理数组
声明与赋值
int a[10],*pa;//声明数组与指针
pa=&a[0];//指针变量=数组取首地址(本身指针变量就是地址)
或
pa=a;//指针名=数组名
引用
*pa即a[0]
*(pa+n)即a[n]
a[i]即*(pa+i)即*(a+i)即pa[i]//∵pa=a,a为数组首地址,pa也为一个地址
指针数组
是个数组,数组元素是指针
指针数组指向几个二维数组时:
int* pline[3] = { line1,line2,line3 };//定义指针数组并初始化为整型数组,三个元素
for (int i = 0; i < 3; i++)//第一行
{
for (int j = 0; j < 3; j++)//第一列
cout << pline[i][j] << " ";//注意前面* pline[3],此处相当于pline等于line123构成的数组,故变成了二维数组
指针作为函数参数
形参是指针时实参可以为数组 (指向普通变量)
void print(const int* p1, const int *p2);
……
print(array1,array2 );
print(&array[i],&array[i+1]);//若为数组中某个值时,带上&
形参是指向类对象的指针
void fun(Base1* ptr) {//一个函数,形参是指向->基类base1的对象的 指针*ptr
ptr->display();//调用类中成员函数:对象指针->成员名
}
形参是指针时
交换两个指针:
- 指针指向的对象交换了
- 指针变量没有交换
指针大小
- 任何类型的指针变量都是占用4个字节。
(指针即为地址,指针几个字节跟语言无关,而是跟系统的寻址能力有关,譬如以前是16为地址,指针即为2个字节,现在一般是32位系统,所以是4个字节,以后64位,则就为8个字节) - 指针占用多少字节=数据类型占用多少字节
int main() {
double array[20];//声明数组,20个元素
cout << "The number of bytes in the array is" << sizeof(array);//20*8=160
cout << "\nThe number of bytes returned by getsize *ptr&ptr is";
getsize(array);//形参为指针,实参可以是数组
}
void getsize(double* ptr) {//传入的时指针*ptr
cout << sizeof(*ptr) <<" "// 返回指针*ptr指向的double型数据,double是8位
<< sizeof(ptr) << endl;//返回的是指针变量的大小,任何类型的指针变量都是4(32位系统时)
}
注意*ptr与ptr的占位大小不同
函数指针与指针函数
函数指针:
函数指针本质是一个指针,其指向一个函数(会用上此函数)
指针函数:
指针函数本质是一个函数,其返回值为指针
对比:
- 指针函数:int* fun(int x,int y);
函数指针:int (*fun)(int x,int y); - 可以简单粗暴的理解为,指针函数的*是属于数据类型的,而函数指针的星号是属于函数名的。
再简单一点,可以这样辨别两者:函数名带括号的就是函数指针,否则就是指针函数。 - 声明
int (*fun)(int x,int y);//类型说明符 (*函数名) (参数)
//指向的是类非静态成员函数,非静态,不在全局作用
int(point:: * funcptr)()//定义成员函数指针//typedef 返回值 (类名::*指针类型名)(参数列表);
const = &point::getx;
- 赋值
fun = &Function;//赋值,将函数地址赋给指针变量,使函数指针指向fun函数,从而与fun功能相同
fun = Function;//&可有可无
//指向的是类非静态成员函数
const = &point::getx;//定义成员函数指针;指针类型名 指针名 = &类名::成员函数名;
- 调用
//直接调用函数
(*fun)();//通过指针的方式来调用函数,注意两个括号
fun();
//类对象调用函数
(a.*funcptr)();//对象名.指针访问成员函数
a.getx();//对象.成员函数名
谁是指针就写成指针形式
(p1->*funcptr)() ;//对象指针名->成员函数指针
p1->getx();//对象指针名->成员函数(类对象.*指针名)(参数列表);
(类指针->*指针名)(参数列表);
那么类的静态成员函数呢?
指向的是类静态成员函数,静态,在全局作用,视为普通函数,则用法相同
用指针访问
访问类静态数据成员
int* ptr = &point::count;//指针创建,指向类的静态成员,类的静态成员使用时要类名::
point a(4, 5);
cout << "object count=" << *ptr << endl;//使用指针访问静态数据成员
cout<< "object count=" << point::count << endl;//与上等价
杂代码
int main() {
derived d;//子类对象
derived* p = &d;//子类 指向对象d的指针
d.var = 1;//子类对象访问同名成员,默认本类成员
d.fun();
d.base1::var = 2;//子类对象要访问父类成员,父类::修饰
d.base1::fun();
p->base2::var = 3;//子类对象指针访问父类成员
p->base2::fun();
return 0;
类后引用??不太懂 return*this作对应
clock& clock::operator++() {//前置重载
second++;
if (second >= 60) {
second -= 60;
minute++;
if (minute >= 60) {
minute -= 60;
hour = (hour + 1) % 24;//!24进制进位方法!
}
}
return *this;//与&clock匹配,返回clock类型
}