指针
一个变量的地址称为该变量的“指针”;
- 如果说地址是对内存单元的编号,那么指针就是存放内存单元的变量
简单来说,如果你去宾馆住宿,前台给你门卡并且告诉你房间在 666号,这时候你就能根据前台提供的地址精准的找到属于你自己的房间了。同理,指针就是指向变量的门牌号,通过指针,你就能找到它所指向的变量的地址了了。
要注意的是:int* p 中,int * ->是整形指针类型, p -> 才是指针, * -> 解应用操作符。
如果说指针是房间的门牌号,那*就是房间的钥匙。
int a = 10;
int *p;
p = &a; //p 是指针,它指向变量a存放数据(10)的内存地址
*p = a = 10; //对p解应用相当于顺着p指向的地址找到变量(a)存放的数据(10)
一级指针
一级指针的定义形式一般为:
类型名 * 指针变量名;
如以下的几种形式:
int a; // a是变量
int *p;
p = &a;
//or
int *p = &a;
int a[] = {0,1,2,3,4}; //a是数组
int *p;
p = &a[0];
//or
int *p = a;
一级指针的传参:
void Ner(int *x, int *y)
{
}
int main()
{
int x,y;
int *p1 = &x;
int *p2 = &y;
Ner(p1,p2); //变量的传参
return 0;
}
//****************************
void Fun(int *str)
{
}
int main()
{
int arr[] = {0};
Fun(arr); // 数组的传参
return 0;
}
二级指针
二级指针是存放一级指针地址的指针,是 “地址的地址”
二级指针的传参:
void test1 (int **p)
{
}
int main()
{
int n = 10;
int *p = &n; // p是n的地址
int **pp = &p; // pp是p的地址
test1(pp); // 方式1
test1(&p); // 方式2
return 0;
}
指针数组
其一般形式为:
类型名 * 数组名【数组长度】
- int *p[10]
本质上是一个数组,是一个存放指针的数组。也就是说指针数组中的每一个元素都存放着一个地址,相当于一个指针变量。
数组指针
其一般形式为:
类型名 (*)【数组长度】
- int (*p) [10]
本质上是一个指针,表示指向数组的指针,即数组首元素地址的指针。
上面的数组指针表示:定义p为一个指针变量,它指向包含10个整形元素的一维数组,即p是指向一维数组的指针。所以数组指针一般用来表示二维数组。
数组指针的应用:
int arr[2][3] = {{1,2,3},{4,5,6}};
// 1 2 3
// 4 5 6
*(*(arr+0)+2) = arr[0][2] =3;
*(*(arr+1)+1) = arr[1][1] = 5;
指针常量和常量指针
区别
1、本质
- 指针常量:本质上一个常量,指针用来说明常量的类型,表示该常量是一个指针类型的常量。
- 常量指针:本质上是一个指针,常量表示指针指向的内容,说明该指针指向一个“常量”
2、地址
- 指针常量:在指针常量中,指针自身的值是一个常量,不可改变,始终指向同一个地址。在定义的同时必须初始化。
- 常量指针:指针可以指向其他地址
3、内容
- 指针常量:指向的内容可以修改,地址不能改
- 常量指针:在常量指针中,指针指向的内容是不可改变的,指针看起来好像指向了一个常量,但是地址能更改。
演示
int main()
{
//这是常量指针,内容不能改,地址能改
int a = 10;
int b = 20;
const int *p = &a;
*p = 30; // 出错
p = &b; //正确
//这是指针常量,内容能改,地址不能改
int* const q = &b;
q = &a; //出错
*q = 30; //正确
}
总结
- 主要是看 const 修饰的位置, const int *p 和 int const *p 都是指针常量,因为const 修饰的都是 *p(也就是 p 指向的常量),常量不能被更改,所以指向的内容不能改,但指向的地址能更改
- int* const p 中 const 修饰的是 p, 而 p 是一个指针,所以 p 指向的地址不能更改,而内容却能够更改