说明
大一咸鱼一只,闲来无趣,随意写写
指针是个啥
指针是一种特殊的变量,和整型、浮点型、字符型等相似。只不过前者存的是地址,后者存的是数、是字符(其实归根结底存的都是一串二进制码)。
因为指针是存储地址的变量,所以指针名表示的就是一个地址(就好比 int a; 中 a 表示的是一个整型数一样)。
- 先谈谈地址 ,地址计算机存储变量的内存单元(常被比喻成房间号),你可以通过地址运算符(&)来对一个变量进行取地址操作;
- 再谈谈指针,指针存的是一个变量的地址,并指向此变量。假设p是一个指针,*p就表示该地址内存的值即指针所指向的变量的值。注意&p表示的也是一个地址,即p这个指针的地址。看一段程序:
#include <iostream>
using namespace std;
int main(void){
int a(7); //定义一个整型数
int *p;
//定义一个可指向整型的指针,在C++中 int* 是一种复合类型,是指向int的指针
p = &a; //把a的地址存入指针
cout<<"p = "<<p<<endl;
cout<<"&a = "<<&a<<endl;
cout<<"*p = "<<*p<<endl;
cout<<"a = "<<a<<endl;
cout<<"&p = "<<&p<<endl;//取指针p的地址
}
输出
p = 0x7ffeefbff48c
&a = 0x7ffeefbff48c
*p = 7
a = 7
&p = 0x7ffeefbff480
Program ended with exit code: 0
- 因为地址与系统有关,32位系统中指针变量占4个字节,64位系统中指针占8个字节。
- 指针不是整型,虽然指针存放的地址是一个整数,但其类型不是整型。比如这样:
int *p;
p = 0x7ffeefbff480;
报错Assigning to 'int *' from incompatible type 'long'
表示类型不匹配。
改正如下:
int *p;
p = (int*)0x7ffeefbff480;
- 指针的危险:在使用指针时,一定要给指针一个地址。
- 可以给指针加上一个整数。每加一,地址值加一个指针指向类型所占用的字节数。也可以将两个指针相减,得到一个整数(只在数组中有意义)。指针还可以进行关系运算。
各种指针
数组与指针
一维数组
对于一个数组
int b[10]; //定义一个int数组
cout<<b<<endl; //输出&b[0],即数组首地址
cout<<b+1<<endl; //输出的数加4
cout<<&b<<endl; //输出整个数组的地址
cout<<&b+1<<endl; //输出的数加4*10=40
输出
0x7ffeefbff460
0x7ffeefbff464
0x7ffeefbff460
0x7ffeefbff488
Program ended with exit code: 0
注意b
与&b
的区分
int b[10]; //定义一个int数组
int *p=b; //正确,int型指针指向数组存放数组首地址
p = &b; //错误,int型指针p不能存放整个数组的地址
大多数时候数组名与指向数组的指针名可以混用,并且既可以使用数组的( [] )表示法,也可以使用(*)运算符,即a[i]
与*(a+i)
等价。但是指针名可以修改(地址变量),数组名不可修改(地址常量)。此外,对数组使用sizeof运算符得到数组的长度,对指针使用则得到指针的长度。
int b[10];
int *p=b;
b += 1; //错误
p += 1; //正确
多维数组
以二维数组为例
int a[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}};
cout<<a[2][3]<<endl;
cout<<*(a[2]+3)<<endl;
cout<<*(*(a+2)+3)<<endl;
输出
12
12
12
Program ended with exit code: 0
二维数组还可以使用行指针处理,定义形式:
类型名 (*指针名)[列长度]
int main(void){
int a[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}};
int (*p1)[4], *p2;
p1=a; //正确,p1为一个行指针,与二维数组名类型相同
p2=a; //错误,类型不匹配
字符串与指针
char ch[80]="wonderland";
char *s1="wonderland1.0";
cout<<ch<<endl; //数组名ch即是第一个元素'w'的地址,输出ch即输出整个字符串
cout<<s1<<endl; //可以像使用字符串那样使用指针s1
输出
wonderland
wonderland1.0
Program ended with exit code: 0
注意在本程序中字符型数组ch中存的是变量,可以更改;而字符型指针中存的是常量,不可更改
在cout和多数C++表达式中,char数组名、char指针以及用引号括起来的字符串常量都被解释为字符串的第一个字符的地址
多级指针与指针数组
即指针的指针与放指针的数组
char *a[]={"wonderland1.0","2.0","3.0"}; //放char型指针的指针数组
char **p=a; //指针p存放的是char型指针的地址,初始化为指针数组a的第一个元素
cout<<p<<endl;
cout<<*(p+1)<<endl;
cout<<**(p+1)<<endl;
cout<<*p+3<<endl;
输出
0x7ffeefbff470
2.0
2
derland1.0
Program ended with exit code: 0
const指针
const类型名前
表示一个指向常量的指针
char *p1="Wonderland", *p2="1.0";
const char *p=p1; //表示声明指向常量的指针
*p = 'F'; //错,指针所指向的是常量,不能更改
p = p2; //正确,指针本身的值可以改变
const在指针名前
表示声明一个指针常量
char *p1="Wonderland";
char *const p2="1.0"; //声明指针常量,声明常量时必须初始化
p2 = p1; //错误,指针本身不能更改
*p2 = '2'; //正确,指针指向的值可以改变
堆内存分配
需要在程序运行时分配空间的情况下使用。
两个运算符,一个例子。
- 运算符:new 和 delete ,new用于申请空间,delete用于释放空间。
- 例子
int *p, m;
cin>>m;
p = new int[m]; //动态分配内存单元
delete []p; //释放所分配的内存
函数指针
与数组类似,函数名也是一个代表函数入口的地址常量
声明一个指向函数的指针即为函数指针,可以通过这个指针调用函数
由此可见,若声明一个名为(*pf)
的函数,那么pf
就是函数指针了。
注意区分:*pf(int)
意味着pf()
是一个返回指针的函数,(*pf)(int)
意味着pf
是一个指向函数的指针。(括号比*优先级高导致)