目录
一.什么是指针
1.指针的概念
(1)指针的初始化
(2) 指针的大小
(3)指针的解引用
2指针的分类
(1)空指针
(2)野指针
(3)指针常量
(4)常量指针
(5)二级指针
二.指针的应用
1.函数传参
(1)值传递
(2)地址传递
2.函数传返回值
三.指针的总结
1.指针的种类
2.指针的应用
一.什么是指针
指针是c语言的精髓所在,如果不会比较优雅地使用指针,也就不能说自己熟悉或者掌握c语言编程,正确且优雅地使用,可以使程序更加简洁高效,每一个学习c语言的小伙伴都应该学习并掌握指针。指针到底是如何成为c语言的灵魂呢,我们一起来探索指针的奥秘吧~
1.指针的概念
指针是一种数据类型,它存放的是数据变量的内存地址,定义指针的格式为 数据类型 * 指名,如int a=10;int*p=&a;这时候我们就说指针p指向了变量a,将变量a看成一个房间,房间的内容就是10,门牌号就是0x123456,则指针p存放的就是a房间的门牌号0x123456,示意图如下图所示
(1)指针的初始化
指针定义的时候可以初始化,初始化的格式为,数据类型 * 指针变量名=&变量名,如下图所示
当指针指向数组的时候,由于数组变量名即为数组的首地址,故可以不用取地址符&
(2) 指针的大小
指针的在操作系统相同的情况,无论是int型char型还是字符型的类型等指针占用的内存大小都是一样的
输出结果
在64位windows操作系统下,几种数据类型的指针都占用8个字节
(3)指针的解引用
当定义完一个指针并指向一个变量时,我们可以通过指针的解引用符*来间接访问变量,即定义完指针后,*p就等价于变量a,而p为变量a的内存地址
输出结果
再用数组来一个解引用的例子,在学习指针前,我们遍历数组都是通过数组下标来访问,而当我们接触到了指针时,我们便可以利用指针来遍历数组
输出结果
2指针的分类
(1)空指针
当我们利用指针进行一些操作后,为了避免后面不小心对某些变量进行操作,我们往往会在操作完成后将指针置空,空指针即指针不指向任何一个内存空间,打印空指针将什么都不会输出
(2)野指针
野指针的几种产生情况
1.定义指针时未初始化,未初始化的指针指向的空间将是随机的,如果此时操作野指针则可能产生一些未知的错误
输出结果
2.指针访问越界
以访问数组为例,当利用指针访问的时候,p的指向一旦超过数组下标,则此时p存放的地址则为未知的空间地址,此时的指针p也称之为野指针
输出结果
可以看到打印第7个变量时产生了一个随机值,这就是因为野指针指向的空间是随机的
3.指针释放后未置空
我们在利用指针进行操作完之后需要将指针释放并置空,而部分小伙伴会在释放指针后忘记将指针置空,释放指针实质上是将指针指向的空间释放,但是指针依然还在,此时指针指向的空间已经被释放也就是已经不存在,则指针会指向另外的随机空间,此时的指针也称为野指针
(3)指针常量
当定义指针并初始化时,用const修饰的位置不同而决定是指针常量还是常量指针,int * const p,此时的指针p则为指针常量,指针变量也是变量,此时指针常量意味着指针的值不可以修改,也就是指向不变,相当于和初始化指向的空间绑定了,指针常量的性质为指针不可修改,而指向的空间的值可以修改
对指针常量指向其他的变量,编译器报错并显示指针变量为已读,不可修改
(4)常量指针
当用const修饰整个定义表达式,cconst int *p,此时指针p为常量指针,即指针指向的空间的值为常量,不可修改,但是指针可以指向其他的空间
当常量指针指向的变量的值修改时,编译器报错并显示变量a为已读,不可修改
(5)二级指针
指针不仅可以指向其他数据类型的变量,指针也可以指向指针,指向指针的指针称为二级指针,此时指针存放的是一级指针变量的地址,二级指针可以通过两次解引用访问变量
输出结果为
可以看到输出结果第一行为一级指针解引用后的值,即变量a的值;第二行为二级指针一次解引用的值,即为一级指针的值,一级指针的值即为变量a的地址;第三行为二级指针二次解引用的值,即为变量a的值
二.指针的应用
1.函数传参
(1)值传递
函数的形参为普通变量时即为值传递,此时将实参传入函数将不会修改,我们以交换两个变量的值为例
可以看到在函数内两个变量的值交换了,但是调用完函数后两个变量的值并没有交换
(2)地址传递
函数的形参为指针变量时即为值传递,此时传入实参必须传入实参的地址,即需要取地址符&,传入实参的地址后,在函数对形参修改将会使实参也发生相应的修改,我们以交换两个变量的值为例
可以看到在函数内两个变量的值交换了,调用完函数后两个变量的值也会相应地交换
2.函数传返回值
在学习指针之前,我们利用函数传返回值时只能传递一个值,在学到指针的时候,我们便可以在传返回值时利用指针传递多个返回值,当我们某个函数的形参为数组,且返回值也为数组时,我们可以利用指针作形参和返回值,我们以冒泡排序为例,传入任意一个数组,然后返回排序后的数组
#include<stdio.h>
int * BubbleSort(int *a) //用指针作为形参,传入的是数组首元素的地址
{
int i=0;
int j=0;
//冒泡排序
for(i=0;i<5;i++)
{
for(j=0;j<5-i-1;j++)
{
if(a[j]>a[j+1])
{
int temp=a[j];
a[j]=a[j+1];
a[j+1]=temp;
}
}
}
//排序完传回指针
return a;
}
int main()
{
int a[5]={5,9,1,5,7};
int i=0;
int *p=BubbleSort(a);//调用完函数定义一个指针接受返回值
for(i=0;i<5;i++)
打印调用完冒泡排序的数组
{
printf("%d\n",*p);
p++;
}
return 0;
}
输出结果为
可以看到,将数组名传入冒泡排序函数后数组的元素进行了排序
三.指针的总结
1.指针的种类
指针总体可以分为空指针、野指针、指针常量、常量指针、二级指针(多级指针),在学习指针是我们要尽量避免空指针和野指针,以免引起一些未知的错误,根据使用场景合适地选择指针种类,可以有效地提高程序的简洁性和可读性
2.指针的应用
指针的应用最常用的两个功能就是函数传参和函数传返回值
在我们想要在函数内修改实参时可以使用指针传参,不过指针传参不可滥用,防止在不需要修改实参时意外对实参进行改动
在我们想要函数传回数组、结构体等多个变量值时我们可以将指向它们的指针作为返回值,在主函数调用函数后定义指针接受即可