CPU 处理的数据保存在内存中。而内存又是分成一个个单元,这些单元是顺序排列,每个单元都有一个称为内存地址的编号,对内粗数据的访问都是通过地址进行的。内存单元的编号叫做地址(Address),也称为指针(Pointer)。内存单元的指针和 内存单元的内容是两个不同的概念。对于一个内存单元来说,单元的地址(编号)即为指针,其中存放的数据才是该单元的内容。在C语言中,允许用一个变量来存放指针,这种变量称为指针变量。因此,一个指针变量的值就是某个内存单元的地址或称为某内存单元的指针。
举例说明:
char C = 'K';
假设有字符变量C,给其赋值内容为 'K'(ASCII码为十进制数 75),C占用了011A号单元(地址通常用十六进数表示)。设有指针变量P,内容为011A,这种情况我们称为P指向变量C,或说P是指向变量C的指针。
一个指针是一个地址,是一个常量。一个指针变量却可以被赋予不同的指针值,是变量。针变量的值是一个地址,那么这个地址不仅可以是变量的地址,也可以是其它数据结构的地址。
数组或函数都是连续存放的。通过访问指针变量取得了数组或函数的首地址,也就找到了该数组或函数。这样一来,凡是出现数组,函数的地方都可以用一个指针变量来表示,只要该指针变量中赋予数组或函数的首地址即可。
在C语言中,一种数据类型或数据结构往往都占有一组连续的内存单元。用“地址”这个概念并不能很好地描述一种数据类型或数据结构,而“指针”虽然实际上也是一个地址,但它却是一个数据结构的首地址,它是“指向”一个数据结构的,因而概念更为清楚,表示更为明确。 这也是引入“指针”概念的一个重要原因。
定义指针变量
一般形式类型说明符 *变量名;
*****表示这是一个指针变量,
变量名是一个合法的标识符,
类型说明符表示该指针变量所指向的变量的数据类型。
int *i; // 定义一个int 类型指针变量 i
char *c;// 定义一个char 类型指针变量 c
float *f;// 定义一个float 类型指针变量 f
需要注意:
一个指针变量只能指向同类型的变量,如 i 只能指向 int 变量,不能时而指向一个 float 变量,时而又指向一个 char 变量.
指针变量的引用
指针变量同普通变量一样,使用之前不仅要定义说明,而且必须赋予具体的值(初始化)。未初始化的指针变量的值是垃圾值,没有意义。
指针相关的两个运算符:
&:取地址运算符
*:指针运算符(或称“间接访问” 运算符)
指针初始化
int a=10; // 定义一个 int 变量 a
int *p=&a; // 定义一个 int 指针变量 p, 并且指向 a 的地址
或者
int a=10; // 定义一个 int 类型变量 a 并且赋值 10
int *p; // 定义一个 int 类型指针变量 p
p=&a; // 将 a 的地址赋值给 p 指针变量
注意: 上面 第三行,被赋值的指针变量前不能再加*说明符,如写为 * p=&a 是错误的。
常见的一些指针操作
int main(){
int *max, *min,*tmp, a, b;
scanf("%d %d",&a, &b);
max = &a;
min = &b;
if(*max < *min){
// 交换指针变量的值,tmp 为临时变量
tmp = max;
max = min;
min = tmp;
}
printf("a=%d\nb=%d\n", a, b);
printf("max=%d\nmin=%d\n", *max, *min);
return 0;
}
22 122
a=22
b=122
max=122
min=22
Process returned 0 (0x0) execution time : 6.454 s
Press any key to continue.
指针变量作为函数参数
输入两个整数,按大小顺序输出
#include <stdio.h>
// 交换两个数
void swap(int *p1, int *p2){
int temp; //临时变量
temp = *p1;
*p1 = *p2;
*p2 = temp;
}
int main(){
int a, b;
int *pointer_1, *pointer_2;
scanf("%d, %d",&a, &b);
pointer_1 = &a;
pointer_2 = &b;
if(a<b){
swap(pointer_1, pointer_2);
}
printf("\n%d, %d\n",a, b);
return 0;
}
运行结果:
10, 21
21, 10
解释:
- swap是自定义函数,它的作用是交换两个变量(a和b)的值。swap函数的形参p1、p2是指针变量。
2)程序运行时,先执行main函数,输入a和b的值。然后将a和b的地址分别赋给指针变量pointer_1和pointer_2,即使pointer_1指向a,pointer_2指向b。
接着执行if语句,由于a<b,因此执行swap函数。注意实参pointer_1和pointer_2是指针变量,在函数调用时,将实参变量的值传递给形参变量。采取的依然是“值传递”方式。因此虚实结合后形参p1的值为&a,p2的值为&b。这时p1和pointer_1指向变量a,p2和pointer_2指向变量b。
接着执行执行swap函数的函数体使p1和p2的值互换,也就是使a和b的值互换。函数调用结束后,p1和p2不复存在(已释放)。
如果将 swap 函数 改成这样,运行看看结果是怎样,猜想为什么是这样的结果
void swap(int x,int y){
int temp;
temp=x;
x=y;
y=temp;
}
根据上面代码改造
#include <stdio.h>
// 交换两个数
void swap(int *p1,int *p2){
int *p;
p = p1;
p1 = p2;
p2 = p;
}
int main(){
int a, b;
int *pointer_1, *pointer_2;
scanf("%d, %d",&a, &b);
pointer_1 = &a;
pointer_2 = &b;
if(a<b){
swap(pointer_1, pointer_2);
}
printf("\n%d, %d\n",a, b);
return 0;
}
运行代码,看看结果怎样?
指针运算符
取地址运算符&:& 是单目运算符,其结合性为自右至左,功能是取变量的地址。
取内容运算符*:* 是单目运算符,其结合性为自右至左,用来表示指针变量所指的变量。在 * 运算符之后跟的变量必须是指针变量。
需要注意: 指针运算符(*)和指针变量说明中的指针说明符(*)不是一回事。
int *p; // 指针说明,在指针变量说明中,“*”是类型说明符,表示其后的变量是指针类型
int *p=&a; // 表示指针变量p取得了整型变量a的地址
printf("%d\n",*p); // 语句表示输出变量a的值。
把一个变量的地址赋予指向相同数据类型的指针变量
int a, *pa;
pa=&a; //把整型变量a的地址赋予整型指针变量pa
把一个指针变量的值赋予指向相同类型变量的另一个指针变量
int a, *pa=&a, *pb;
pb=pa; //把a的地址赋予指针变量pb,也就是 pa, pb 都指向a的地址
把数组的首地址赋予指向数组的指针变量
int arr[15], *pa;
pa=arr;
//数组名表示数组的首地址,可以赋予指向数组的指针变量pa
//也可以写成这样
pa = arr[0]; //数组第一个元素的地址也是整个数组的首地址
对于数组的加减运算
对于指向数组的指针变量,可以加上或减去一个整数n。
pa+n -- 往后移动 n 个位置
pa-n -- 往前移动 n 个位置
pa++ -- 往后移动 1 个位置
++pa -- 往后移动 1 个位置
pa-- -- 往前移动 1 个位置
--pa -- 往前移动 1 个位置
需要注意:
数组指针变量向前或向后移动一个位置和地址加1或减1在概念上是不同的。
因为数组可以有不同的类型,各种类型的数组元素所占的字节长度是不同的。
如指针变量加1,即向后移动1 个位置表示指针变量指向下一个数据元素的首地址。
而不是在原地址基础上加1。
举个例子
int arr[5],*pa;
pa=arr; //pa指向数组arr,也是指向arr[0]的地址
pa=pa+3; //pa 往后移动三个位置,即pa现在指向arr[3],即pa的值为&pa[3]
指针之间的运算
a. 两指针变量相减 -- 两指针变量相减所得之差是两个指针所指数组元素之间相差的元素个数。
实际上是两个指针值(地址)相减之差再除以该数组元素的长度(字节数)。
注意:两个指针变量不能进行加法运算。毫无实际意义。
b. 两指针变量进行关系运算
pointer1 == pointer2 表示 比较 pointer1 和 pointer2 指向同一数组元素
pointer1 > pointer2 表示 pf1处于高地址位置
pointer1 < pointer2 表示 pf2处于低地址位置
pointer == 0 表示 ponter 是空指针
pointer != 0 表示 pointer 不是空指针
指针运算例子
#include <stdio.h>
int main(){
//pa、pb为整型指针变量
int a=10, b=20, sum, product, *pa, *pb;
pa = &a; //给指针变量pa赋值,pa指向变量a
pb = &b; //给指针变量pb赋值,pb指向变量b
sum = *pa + *pb; //求a+b之和,*pa就是a,*pb就是b
product = *pa * *pb; //求a*b之积
printf("a=%d\nb=%d\na+b=%d\na*b=%d\n", a, b, a+b, a*b);
printf("s=%d\nt=%d\n", sum, product);
return 0;
}
运行结果:
a=10
b=20
a+b=30
a*b=200
s=30
t=200