1. 指针是什么?
指针是一种保存变量地址的变量。
在计算机中每个存储单元(一个字节)都有一个编号,这个编号称为变量地址。
普通变量的值是实际值,指针变量的值是变量的地址。
- 取地址
我们可以在变量名前加上&
,表示获取变量的地址。
int n = 10;
printf("&n=%p\n",&n);
printf("n=%d\n",n);
变量地址通常使用16进制表示,使用%p
或者%P
打印地址。
试一试,多次执行上面的代码编译的可执行文件。
scanf()
实参前面的&
符号
2. 指针怎么用?
2.1 定义指针
定义指针与定义变量的方式一样,只不过要在类型和变量名中间加上一个*
星号。
类型* 指针变量;
指针变量只能使用同类型变量的地址赋值。
int n = 10;
int* p;
p = &n;
printf("&n=%p\n",p);
printf("n=%d\n",n);
也可以直接初始化。
int n = 10;
int* p = &n;
printf("&n=%p\n",p);
printf("n=%d\n",n);
试一下
int n = 0;
int* p = &n;
scanf("%d",p);
printf("%d\n",n);
变量必须赋值后才能使用,指针也是必须赋值后才能使用。
2.2 解引用
指针的强大之处可以直接操作储存地址里面的数据。这种操作称为解引用。使用时需要在指针前加上*
星号。
注意:这里的*
与声明指针的含义不一样,与乘号也不一样。
int n = 10;
int* p = &n;
printf("n=%d\n",n);
printf("*p=%d\n",*p);
n = 100;
printf("n=%d\n",n);
printf("*p=%d\n",*p);
*p = 1000;
printf("n=%d\n",n);
printf("*p=%d\n",*p);
在这里对*p
操作就是对n
操作;对n
操作就是对*p
操作。
访问变量两种方式:一是通过变量名直接访问,二是指针解引用访问。
- 试一试
int n = 10; printf("*(&n) = %d\n",*(&n));
3. 指针与函数
3.1 值传递
试分析下面代码执行结果。
int func(int m){
m = 100;
}
int main(){
int n = 10;
func(n);
printf("n = %d\n",n);
}
函数调用的秘密:参数初始化。
3.2 指针/地址传递
试分析下面代码执行结果。
int func(int* p){
*p = 100;
}
int main(){
int n = 10;
func(&n);
printf("n = %d\n",n);
}
函数内部改变函数外部定义的局部变量必须满足两个条件:
- 指针参数
- 解引用
4. 试一试
- 形参与实参同名情况
int func(int n){
n = 100;
}
int main(){
int n = 10;
func(n);
printf("n = %d\n",n);
}
- 指针变量连续定义
int m,n;
m = 10;
n = 20;
int* p,q;
p = &m;
q = &n;
printf("%d %d\n",*p,*q);
- 从终端输入地址
#include <stdio.h>
int main(){
int m=0;
int n=0;
printf("&m=%p\n",&m);
printf("&n=%p\n",&n);
int* p;
scanf("%p",&p);
scanf("%d",p);
printf("m=%d\n",m);
printf("n=%d\n",n);
}
5. 实践
- 实现函数
swap()
交换两个变量的值。
- 实现函数
divmod()
输入参数a
和b
,同时获取a
与b
的商和余数。
- 为什么
scanf()
参数需要输入地址?
指针在函数中有这两种应用,一种是即作为输入又作为输出;另一种只作为输出。
6. 练习
实现二元一次方程求根函数root()
输入参数a
、b
和c
,返回是否有根,如果有根返回两个根。
一元二次方程的解
7. 要点
- 变量访问的两种方式:名字访问和地址解引用访问。
- 指针的两种操作:访问保存的值(地址)和访问指向的内存。