指针也是一种数据类型
1.指针变量的声明
(具有指针类型的变量)指针变量适用于存放内存单元地址的,所以赋值时不加取址符号&会报错,如下。
(声明的数据类型声明了变量需要的内存空间的同时也限定了对变量可以进行的运算及其运算规则。)
指针可以指向各种数据类型,包括基本数据类型类型、函数、对象、同样也包括指针。
1.2.*和&
*称为指针运算符,也称解析,表示获取指针所指向的变量的值。例如,*ptr 表示指针ptr所指向的int型数据的值。
&成为取地址运算符,用来得到一个对象的地址。例如,&i就可以得到变量i的存储单元。(教材C++语言程序设计中有时将普通变量和类类型的对象都统称为对象)
注意,*和&出现在声明语句中和执行语句中其含义是不同的,它们作为一元运算符和二元运算符时的含义也是不同的。
例如: int *p;//声明p是一个int型的指针变量 cout<<*p;//输出指针p所指向的变量的值
int &rf;//声明一个int型的引用 int b; int *pa=&b;//表示取b的地址
2.指针的赋值
定义了一个指针,只是得到了一个用于存储地址的指针变量,但是变量中没有确定的值,其中的地址值是一个不确定的数,也就是不能确定这时候的指针变量中村反对个是哪个内存单元的地址。这时候指针所指的内存单元中有可能存放着重要数据或程序代码,如果盲目去访问,可能会破坏数据或造成系统的故障。因此定义指针后必须先赋值,然后才可以引用。
赋值方法:
(1)定义的同时初始化:存储类型 数据类型 *指针名=初始地址;
(2)定义后单独赋值:指针名=地址;
若将对象地址赋值给指针变量,该对象必须在这之前声明过且数据类型与指针类型一致,也可以使用一个已经赋值的指针去初始化另一个指针,也就是说可以多个指针指向同一个变量。
一个数组,可以用它的名称来直接表示它的起始地址。数组名称实际上就是一个不能被赋值的指针,即指针常量。(此观点有争议)
#include<iostream>
using namespace std;
int main(){
int i;//定义int型数i
int *ptr=&i;//取i的地址赋给ptr
i=10;//int型数赋初值
cout<<"i="<<i<<endl;//输出int型数的值
cout<<"*ptr="<<*ptr<<endl;//输出int型指针所指地址的内容
return 0;
}
运行结果:
i=10
*ptr=10
输出的i和*ptr都是10.前者是直接访问,后者是通过指针的间接访问。
第一次是在指针声明语句中,*表示被声明的标识符是指针;第二次是在输出语句中,是指针运算符,是对指针所指向的变量的间接访问。
关于指针特殊类型还需注意以下几点
(1)指向常量的指针:不能通过指针来改变对象的值但可以改变指针本身的指向,可以确保指针所指向的常量不被意外更改,但并不意味这指向的对象是常量。例如:
(2)指针类型的常量,这时指针本身的值不能被改变,在定义的同时必须初始化。例如:
(3)void类型指针,可以存储任何类型的对象地址,任何类型的指针都可以赋值给void类型的指针变量。且经过类型显式转换,可以访问任何类型的数据。一般只在指针所指向的数据类型不确定时使用。
3.指针运算
前面已经介绍过了指针的赋值运算,本小节介绍指针的算术运算和关系运算。
执政进行加减运算的结果与指针的类型密切相关。比如指针p和整数n,p+n表示指针p当前所指位置后方第n个数的地址,p-n即前方。“指针++”表示下一个数据的地址,“指针--”表示前一个。
*(p+n)和*(p-n)同理可得,也可写作p[n]和p[-n]。
一般指针的算术运算和数组的使用是相联系的,因为只有使用数组时才有连续分布的可操作内存空间。指针算术运算的不慎使用会导致指针指向无法预期的而地址,从而造成不确定的结果,因此指针的算术运算一定要慎用。
指针变量的关系运算指的是指向相同类型数据的指针之间进行的关系运算,但是指针可以和整数0进行比较,0专用于表示空指针,也就是一个不指向任何有效地址的指针。
int *p=0;//定义一个空指针p,不指向任何地址
(NULL时一个在很多头文件中都有定义的宏,被定义为0)
如果没有或不便于用一个有效地址给一个指针变量赋初值,那么应当用0作为它的初值,从而避免指向不确定地址的指针出现。
4.用指针处理数组元素
指针加减运算的特点使得指针特别适合于处理存储在一段连续内存空间中的同类数据,可以用指针对数组及其元素进行方便而快速的操作。因为数组名就是数组的首地址,所以数组中下标为i的元素就是*(数组名+i),例如*array就是array[0],*(array+3)就是数组元素array[3]。
#include<iostream>
using namespace std;
int main()
{
int array[5]={1,2,3,4,5};
for(int i=0;i<5;i++)//指针法(利用数组名)
{
cout<<*(array+i)<<endl;//0.066s
}
for(int i=0;i<5;i++)//下标法
{
cout<<array[i]<<endl;//0.063s
}
for(int *p=array;p<(array+5);p++)//指针法(利用指针变量)
{
cout<<*p<<endl;//0.061s
}
for(int *p=array,i=0;i<5;i++)
{
cout<<p[i]<<endl;//0.070s
}
return 0;
}
把数组作为函数的形参,等价于把指向数组元素类型的指针作为形参。例如下面3个写法,出现在形参列表中时等价的:
void f(int p[]);
void f(int p[3]);
void f(int *p)
5.指针数组
由于指针数组的每个元素都是一个指针,必须先赋值,后引用。
二维数组也可当作指针数组来使用,其它多位数组类推,例如:
之后无额外笔记,看书和ppt。