前言
许多同学闻C语言指针色变,但是指针其实并没有大家想象中的那么难,也没有那么复杂,其实连能想到生活,指针还是很好理解的,虽然题目是指针的详解,但是详细程度在大家的眼中不太相同,但是我会把我学到的有关指针的东西尽力地写出来,帮助大家更好的理解、运用指针!
一、内存和地址
内存对于计算机来说就是存储数据的地方,内存也可以划分为一个个内存单元,每个内存单元一个字节大小,而每一个内存单元都有一个相对应的地址,也就是说内存就像是一个酒店,里面的所有房间都有一个房间号,我们可以通过房间号快速地访问到我们要去的房间
二、指针变量
在C语言中,变量的声明就是向内存空间申请空间的过程,而指针变量存储的是变量的内存地址。这个地址可以是任何类型的数据,包括整数、浮点数、结构体等,我们也可以通过指针访问我们的内存空间,我们观察下面的代码
#include <stdio.h>
int main() {
int a = 0;
int* pa = &a;
printf("%p\n", pa);
return 0;
}
这里我们声明了一个变量 a ,并且声明了一个指针变量 pa 储存变量 a 的地址,至于取地址符号& 与 解引用符号 * 我已经在操作符详解里面讲过了
三、指针变量的类型
指针变量是用很多类型的,比如上面的代码的指针变量是整形指针变量,指针还有char* 、double*、float*等等
指针类型多种的意义: 为指针的解引用提供依据,给解引用说明按照什么类型解引用
下面我们看两段代码
//代码1
#include <stdio.h>
int main(){
int n = 0x11223344;
int *pi = &n;
*pi = 0;
return 0;
}
下面我们看代码二
#include <stdio.h>
int main() {
int n = 0x11223344;
char* pi = (char*)&n;
*pi = 0;
return 0;
}
结论: 指针的类型决定了,对指针解引用的时候有多大的权限(一次能操作几个字节)。
比如: char* 的指针解引用就只能访问一个字节,而 int* 的指针的解引用就能访问四个字节。
※ void 类型指针(空指针)
在上面我们说过,指针解引用时会根据指针的类型对指针指向的内存进行解读,但是对于 void 类型的指针是无法解引用的,因为 void 指针的类型为空,指针解引用不知道如何去读这一段内存,所以 void 类型的指针只能当作一个零时的指针拷贝,也就是保存指针的变量,如下面的代码
#include <stdio.h>
int main() {
int n = 0x11223344;
int* pi = &n;
void* tmpp = pi;
int* pa = (int*)tmpp;
printf("%d\n", *pa);
return 0;
}
这里的代码,tmpp为一个空指针类型,它存储了 n 的内存地址,并且把这个地址赋值给了 pa ,这时 pa 、pi 都指向 n 的内存地址
void 指针(空指针)无法直接解引用,编译器会报错
四、指针的运算
指针是一个变量,存储的是一个地址,是十六进制的数值,它也可以进行运算,下面我们看一段代码及运行结果
指针只能进行 +、-、比较 三种运算
#include <stdio.h>
int main() {
int n = 0;
char a = '0';
int* pn = &n;
char* pa = &a;
printf("pn-> %p\n", pn);
printf("pa-> %p\n", pa);
printf("pn + 1-> %p\n", pn + 1);
printf("pa + 1-> %p\n", pa + 1);
return 0;
}
下面是运行结果
pn-> 0000006AA94FF634
pa-> 0000006AA94FF654
pn + 1-> 0000006AA94FF638
pa + 1-> 0000006AA94FF655
我们可以发现对于整数型指针变量 pn 加 1 后它的地址向后偏移了 4,而对于字符型指针变量 pa 加 1 后,它的地址向后偏移了 1 ,4 与 1 是地址便宜的字节量,int整数型变量大小为4个字节,而char字符型数据大小为1个字节,也就说,指针类型的不同决定着指针运算时的步幅大小
五、野指针
概念: 野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)
野指针有三种成因: 指针未初始化、指针越界访问、指针指向的空间释放
指针未初始化
#include <stdio.h>
int main() {
int* p; //此时p为野指针
int a = 10;
p = &a;
return 0;
}
指针越界访问
#include <stdio.h>
int main()
{
int arr[10] = {0};
int *p = &arr[0];
int i = 0;
for(i=0; i<=11; i++)
{
//当指针指向的范围超出数组arr的范围时,p就是野指针
*(p++) = i;
}
return 0;
}
指针指向的空间释放
#include <stdio.h>
int main() {
int* pn = (int*)malloc(sizeof(int));
assert(pn);
free(pn);
return 0;
}
避免野指针的出现需要避免出现这些错误!
六、二级指针及多级指针
我们知道指针是一个变量,指针存放着其他变量的内存地址,也正是因为指针是一个变量,所以在内存中也有着相应的内存地址存放着指针变量,当我们用指针指向另一个指针的内存地址时,这个指针就称为二级指针,同理,若是我们有一个指针指向二级指针的地址时,这个指针就称为三级指针,以此类推,下面我们举例说明
#include <stdio.h>
int main() {
int a = 0;
int* pa = &a;//一级指针
int** ppa = &pa;//二级指针
int*** pppa = &ppa;//三级指针
return 0;
}
多级指针的命名
从上面的代码中,我们也可以看出多级指针是如何命名的,类型*(N),多少级指针后面就跟多少个*号
End
好了,对于基本的指针知识就介绍到这里,后面我还会写其他有关指针的文章,希望这篇文章对你有帮助!谢谢你的阅读!