前言
指针是编程语言中的一个对象,利用地址,他的值直接指向存在电脑存储器中的另一个地方的值。他能找到以他为地址的内存单元。
一言蔽之,指针就是变量,是用来存放地址的变量。
正文
指针有两个值得注意的点
1.指针是用来存放地址的,地址是唯一标示一块地址空间的
2.指针的大小在32位平台是4个字节,在64位平台上则是8个字节
指针和指针类型
指针
| 1 2 3 4 5 6 7 8 9 | //指针初阶 int main() { int a = 0; int* pa = &a; *pa = 1; printf("%dn", a); return 0; } |
指针类型
指针类型跟变量类型一一对应,如int*对应int
有两点需要注意,下面会说明
1.指针类型决定了指针解引用的权限有多大
就算说,int*的指针在使用时,能改变int型的变量并一一对应,若使用char型的指针改变int型的变量会产生难以预料的错误
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //1.不同指针类型解引用权限不同 int main() { int a = 0x11223344; int b = 0x11223355; int * pa = &a; *pa = 0; printf("a =%dn", a); char* pb = &b; *pb = 0; printf("b =%dn", b); return 0; } |
2.指针类型决定了指针走一步能走多远(多长)
跟解引用权限类似,使用指针时需要类型匹配的指针进行位移动,不然就会发生错误
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | //2.不同指针类型指针步长不同* int main() { int a = 0x11223344; int* pa = &a; char* pb = &a; printf("a %pn", pa); printf("a %pn", pb); pa += 1; pb += 1; printf("nnna %pn", pa); printf("a %pn", pb); return 0; } |
野指针
所谓野指针就是指向位置不可知(随机的、不正确的、没有明确限制)的指针,就像街上的野狗一样,无人认领,这种就被称为野指针
野指针的成因主要有三种:1.指针未初始化 2.指针越界访问 3.指针指向的空间被释放
1.指针未初始化
指针就像变量一样需要初始化,电脑才会为他开辟空间,不然就会生成一个随机数或无法运行
| 1 2 3 4 5 6 7 8 9 | //野指针 //1.未初始化 int main() { int* p; p++; printf("%pn", p); return 0; } |
2.指针越界访问
主要出现于数组中,越出了数组的界限,就会造成指针越界访问,这种也是野指针
| 1 2 3 4 5 6 7 8 9 10 | //2.指针越界 int main() { int arr[10] = { 0 }; int* p = arr; * (p + 10) = 2;//表示arr[11],已经越界 int*ppa = (p + 10); printf("%pn", ppa); return 0; }//错误代码,如果将*(p+10)改成*(p+9),运行就不会报错 |
3.指针指向的空间被释放
通常出现于函数调用中,因为函数中变量的生命周期短,出函数就会被销毁,所以存储的地址就会无效,指针也会变成野指针
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //3.指针指向的空间被释放 int add(int a, int b) { int d = a + b; printf("d =%pn", &d); return &d; } int main() { int a = 1; int b = 1; int* p = add(a, b); printf("p =%pn", p); return 0; } |
如何规避野指针
1.指针记得初始化
2.小心指针越界
3.指针指向空间被释放后及时置放NULL(空)
4.指针使用之前检查有效性
指针运算
既然变量间有运算,那么指针间也会有运算,常见的指针运算包括指针+-整数、指针-指针、指针的关系运算
指针+-整数
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | //指针+-整数 int main() { int arr[5] = { 1,2,3,4,5 }; int ch[5] = { 1,2,3,4,5 }; int* pa = arr; int* pb = ch; *(pa + 1) = 0; *(pb + 4 - 1) = 0; int i = 0; for (i = 0; i < 5; i++) printf("%d ", *(pa + i)); printf("n"); for (i = 0; i < 5; i++) printf("%d ", *(pb + i)); return 0; } |
指针-指针
C语言语法规定,指针-指针就是两个指针间的元素个数,没有指针+指针的说法,没啥意义!!!
| 1 2 3 4 5 6 7 | int main() { int arr[5] = { 1,2,3,4,5 }; int* p = arr; printf("%dn", (p + 5) - p); return 0; }//可以用来写求字符串长度函数 |
指针的关系运算
类似于变量间的关系运算,不过指针运算最好跟后面的指针进行对比
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | //指针的关系运算 int main() { int arr[5] = { 1,2,3,4,5 }; int* p = arr; for (p = &arr[5]; p > &arr[0];) { *--p = 0;//前置-- } int i = 0; for (i = 0; i < 5; i++) printf("%d ", *(p + i)); return 0; } |
C语言标准规定
允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针进行比较,但不允许与指向第一个元素之前的那个内存位置的指针进行比较(比后不比前)
指针和数组
指针和数组间有密不可分的关系,我们都知道数组名是首元素的地址,那么你有没有想过数组中其他元素与指针间的关系呢?
| 1 2 3 4 5 6 7 8 9 10 | //指针和数组 int main() { int arr[5] = { 1,2,3,4,5 }; int* p = arr; //arr[3]==*(arr+3)==p[3]==*(p+3) printf("%d <==> %d", arr[3], *(arr + 3)); printf("n%d <==> %d", p[3], *(p + 3)); return 0; } |
二级指针
把地址赋一次叫一级指针,把地址赋两次就叫二级指针
| 1 2 3 4 5 6 7 8 9 | //二级指针 int main() { int a = 0; int* pa = &a; int** ppa = pa; printf("&a =%pnpa =%pnppa =%pn", &a, pa, ppa); return 0; } |
指针数组
指针,也想拥有数组,于是指针数组就出现了
int*parr[5]={0}; 就是指针数组
| 1 2 3 4 5 6 7 8 9 | //指针数组 int main() { int arr[5] = { 0 }; char ch[5] = { 0 }; int* parr[5] = { 0 }; //因为是指针初阶,只需认识即可 return 0; } |
总结
本文主要介绍了指针初阶的一些知识,包括指针和指针类型、野指针、如何避免野指针、指针的运算、指针和数组、二级指针和指针数组等,因为是指针初阶,所以并没有很详细的去说明指针的各种使用场景,本文章只起到让大家对指针有一个初步认识的作用。
希望我的文章能够为大家再写代码时提供帮助!
希望各位大牛能够及时指出我文中存在的不足和错误,我好加以改正!
最后希望以后写的文章越来越好!
鸣谢
感谢比特科技鹏哥所传授的知识,让我受益匪浅,写出这篇文章!@比特鹏哥



