一;学习目标如下
1.学习角度
- 指针是什么
- 为什么要学习指针
- 如何使用指针
2.本章重难点
指针的使用与理解
- 本节要点
- 指针是地址,指向某一变量单元(在进行程序编译时根据定义的变量类型为变量分配的内存单元(每个字节单元都有一个编号))
注意:C中的地址包括位置信息(内存编号,或称为纯地址)和它所指向的数据的类型信息
对变量的访问都是通过地址访问的访问方式:
(1)直接访问(通过变量名进行访问)
(2)间接访问(通过变量的地址进行访问)
- 为什么要使用指针(有哪些优点)?
(1)指针的使用使得不同区域的代码可以轻易的共享内存数据
当然也可以通过数据的复制达到相同的效果,但是这样往往效率不太好。指针节省 内存主要体现在参数传递上,比如传递一个结构体指针变量和传递一个结构体变 量,结构体占用内存越大,传递指针变量越节省内存的,也就是可以减少不必要的 数据复制
(2)C语言中一些复杂的数据结构往往需要使用指针来构建,如链表、二叉树等。
(3)有些操作必须使用指针完成
①如:操作申请的堆内存。
②又如:C语言中的一切函数调用中,值传递都是“按值传递”的。如果要在函数 中修改被传递过来的对象,就必须通过这个对象的指针来完成。(如对一个函数传 入一个x一个y,交换两者的值,如果只是按值传递,那在函数内交换并不影响函 数外的x和y,而指针则可以做到)
(4)动态分配内存
大多数情况下,可以看到程序使用的内存是通过显式声明分配给变量的内存(也就 是静态内存分配)。这一点对于节省计算机内存是有帮助的,因为计算机可以提前 为需要的变量分配内存。但是在很多应用场合中,可能程序运行时不清楚到底需要 多少内存,这时候可以使用指针,让程序在运行时获得新的内存空间(实际上应该 就是动态内存分配),并让指针指向这一内存更为方便。
(5)函数多个返回值
可以用指针(或者结构体?)
(6)指针和数组的效率问题(不太清楚缘由)
需要遍历数组或频繁引用其元素时, 这样效率比使用下标高.
- 如何使用指针?
- 指针变量:仅存放地址的变量,可用来指向其他对象(如变量、数组、函数等)
I.定义格式: 类型名(基类型) *变量名;
II.说明变量类型:指向某(基类型)数据的指针变量
III.如何使用:
(1)指针指向变量时
赋值(将某一变量的地址赋值给指针变量)
int a;
int *p1;
p1 = &a;
引用指针变量指向的变量(按某一种格式输出或者改变其值)
int a;
scanf_s("%d",&a);
int *p1;
p1 = &a;
printf("%d",p1);
*p1=2;
注意:(1)两个重要的运算符
- &:取地址运算符。如&a:变量a的地址
- *:指针运算符。(也被称为解引用操作)如:*p
补充:二者的运算优先级是一样的,所以说在组合运算时是按照从右向左的方向进行结合的
例子:&*p(最终取的为地址); *&a(最终取得为a的值)
实际应用实例:
用指针来实现两个数的大小比较并按照从大到小顺序输出
方法一:可以通过函数(用指针)来实现两个数值的互换
方法二:也可以通过交换指针的指向(如果3个数,可以考虑用方法一)
#include<stdio.h>
int main(void)
{
int a,b;
scanf_s("%d",&a,&b);
int *p1,*p2,*p3; //定义了三个指针变量
int t;
p1 = &a;
p2 = &b;
if(*p2>*p1)/ /方法一:通过交换指针变量指向的地址来实现两个数的互换,变量内容不变
{
p3=p2;
p2=p1;
p1=p3;
}
printf("%d%d",*p1,*p2);
if(*p1<*p2) 方法二:通过交换指针变量指向变量的内容来实现 也可以设计一个函数来实现此功能
{
t=*p1;
*p1=*p2;
*p2=t;
}
printf("%d%d",*p1,*p2);
return 0;
补充:如果是在交换值的情况下,不能够用第三个定义的指针变量,因为不知它指向谁(无确定的值)有可能其中存储着有用的数据,如果改变,可能会影响系统的正常工作状态
- 指针指向数组时
- 引用数组元素的方法:下标法(如s[2]) 和 指针法
如*(p+i)和*(s+i)
- 指针法的优点:目标程序效率高(占用内存少、运行速度快)
下标法的优点:更加直观,能直接知道是第几个元素
注意:数组名和指针的值均是指向首元素的地址,并非指向所有的数组元素地址
- 指针的算术运算
当指针指向数组元素时并且指针变量的基类型和数组元素一样时,指针加一或指针减一,会根据定义的指针变量的基类型进行移动,在读取数据时也是根据其基类型进行的
#include<stdio.h>
int main(void)
{
int s[10];
int i;
int *p1;
p1 = s;
*(p1+5)<=>*(s+5)<=>s[5]
return 0;
}
补充:[]为变址运算符,即将s[i]按照s+i计算地址,然后找出地址中的值,地址相加无意义
格外注意:(1)数组名虽代表地址,但其为指针型常量,其值固定不变,不可对其进行自增和自减操作
(2)在编写程序时,一定要注意指针的当前指向
- * 与++与--的用法如下:
* 、++、--三者的优先级一致,运算方向为从右向左,一定要注意
使用说明:(1)行地址前加*变为列地址 如*(a+i),其指向的是a[i][0]的地址
列地址前加&变为行地址 如&a[0],a[0]等价于*a,其前加个取地址符,变为列地址
(2)a[i]与*(a+i)等价(二维数组中)在一维数组a[i]代表的是第i+1个元素的值
- *(p++)与*(++p)二者的作用不同,前者先取*p值然后再使p加1;后者则是先使p+1,然后再取其内容 ++(*p)先取*p指向的内容,后使内容加1;
- *(p++)<==>a[++i] *(--p)<==>a[--i]
- 在二维数组中,*(a+i)、a[i]、a[i]+0 均指向第一行0列地址
(3)用数组名作为函数参数
数组名实际上就是数组首元素的地址,而指针指向的也是地址,故二者可以互换使用,有四种组合方式,如下:
实参 数组名 指针变量 数组名 指针变量
形参 数组名 指针变量 指针变量 数组名
注意:如果指针变量作实参,必须先使指针变量有确定值,指向一个已定义的对象