第10章 指针10.0 指针概述 10.1 地址与指针变量 10.2 指针与函数 10.3 指针与数组 10.4 指针与结构体(*)
10.0 指针概述 指针是C语言中的一个重要概念,也是C语言的一个重要特
色。 指针作为函数参数,能使函数调用得到多于一个值; 在程序中适当使用指针,会使程序显得灵活高效。
10.1 地址与指针变量10.1.1 内存单元地址10.1.2 指针 10.1.3 指针变量的定义和初始化 10.1.4 指针的运算
10.1.5 指向指针的指针(*)
10.1.1 内存单元地址 计算机主存储器由一个个存储单元组成,微型计算机以字节作
为存储单元。 每个存储单元具有唯一的地址,存储单元的地址是一个无符号
整数,主存储器的所有存储单元的地址是连续的。 编译系统根据变量的数据类型,为变量分配若干个存储单元
(字节)。 每个字符变量分配一个字节 每个整型变量分配4个字节
每个单精度实数分配4个字节。
一个变量所占用存储区域的所有字节都有各自的地址,C系统把
存储区域中第一个字节的地址作为变量的地址。 要访问变量中的数据,就要知道该变量的内存地址。
10.1.1 内存单元地址 直接访问:C语言屏蔽了底层的实现细节,在程序中定义的变
量,编译时系统就给这个变量分配适当的内存单元,并把变量名和变量存储地址对应起来,我们就可以直接在程序中 通过 变量名访问存储单元中的数据。通过变量名访问变量中的数据, 这种变量存取方式称为“直接访问”。 间接访问:变量的地址也是数据,如果定义一种特殊的变量
(即指针变量),用指针变量存放某变量的地址,就可以由前 一个变量的值得到后一个变量的地址,然后通过该地址取得后
一个变量的值,这就是所谓的“间接访问”。
10.1.2 指针1. 存储整数的变量称为整型变量,存储字符的变量称为字
符变量,存储某个变量地址的变量应该称为“地址变量”。在C语言中,把地址变量称为“指针变量”。2. 变量的地址是在程序编译时由系统分配的,变量地址一
经分配就不能改变,因此变量地址是一个常量。3. 变量地址可由运算符“&”和变量名运算获得。
例如,输入函数scanf(“%d”,&a)
4. 数组名本身就是地址,它代表该数组首元素的地址。设a
为一维数组,则有a==&a[0],即a代表a[0]的地址。
10.1.2 指针
a的地址(十进制): 1245052 例10.1.1 变量地址输出示例,程序清单如下: b的地址(十进制): 1245036 #include <stdio.h> b[1]的地址(十进制): 1245040 a的地址(十六进制): 12ff7c void main() b的地址(十六进制): 12ff6c { b[1]的地址(十六进制): 12ff70 int a,b[4]; printf("a
的地址(十进制): %d\n",&a); printf("b的地址(十进制): %d\n",b);//b的地址就是b[0]的地 址 printf("b[1]的地址(十进制): %d\n",&b[1]); printf("a的地址(十六进制): %x\n",&a); printf("b的地址(十六进制): %x\n",b); printf("b[1]的地址(十六进制): %x\n",&b[1]); }
10.1.3 指针变量的定义和初始化 定义指针变量的一般形式为:
基类型 * 指针变量名; 例如: int var=10; int * pointer = &var;
变量名:pointer 地址:1310584值:1310588
变量名:var 地址:1310588值:10
图10.1.1 指针变量示意图
注意:指针变量的变量名是pointer, 而不是*pointer。指针变量pointer的基 类型为int,表示变量pointer只能存储 一个整型变量的地址。例如下面的初 始化是错误的: float f; int *p = &f; ×
int a,*p=&a; √
int *p,a=&p; ×char a;int *p=&a; ×
10.1.3 指针变量的定义和初始化 可以在一个语句中同时定义整型变量和指针变量,例如:
int a,b,*p1,*p2; 当定义一个指针变量而没有初始化时,指针变量的值没有 确定,即该指针不指向特定的变量。这时使用这个变量是 危险的,可能造成不可预料的后果。 可以把指针变量初始化为0,即不指向任何变量。例如: int *pinter=0; 或 int *pointer=NULL;
10.1.4.2 赋值运算 可以把指针常量或另一个同类型的指针变量赋给指 针变量。例如:int a,*p1,*p2=0; //对p2初始化 p1=p2; //把p2的值赋给p1 p2=&a; //把变量a的地址赋给p2
指针变量的值虽然是一个整数,但不能把整数(0
除外)直接赋给指针变量,也不能把指针赋给整型 变量。例如下面的运算时错误的:p1=100; × a=p1; ×
10.1.4 指针的运算 10.1.4.1 指针专用运算符 10.1.4.2 赋值运算(上面已提前讲) 10.1.4.3 算术运算 10.1.4.4 关系运算(*)
10.1.4.1 指针专用运算符(1)取地址运算符&运算符&是个单目运算符,结合方向是右结合。&的
运算对象只能是变量名,不能是表达式。&运算结果就是运算对象(变量)的地址。例如:int *p1,*p2,a,b[10]; p1=&a; //把整型变量a的地址赋给指针变量p1 p2=&b[0];//把数组元素b[0]的地址赋给指针变量p2
10.1.4.1 指针专用运算符(2)指向运算符* 指向运算符*的运算对象只能是指针变量,*的运 算结果得到运算对象(指针变量)所指的变量。 例如当p1=&a时,*p1就表示变量a,是对变量a的间接
引用。*p1是整型变量,不是指针,*p1可以像一般整型 变量一样使用。
*p a 注意:符号*出现在不同的位置,含义也不同。 1. int * p; 定义变量 2. p=&a;*p=3; a=3
10.1.4.1 指针专用运算符 例10.1.2输入两个整数,按先大后小的顺序输出。程序清单如下: #include <stdio.h> void main() { int * p1, * p2, * p, a, b; printf("输入任意两个
整数:"); scanf("%d%d",&a,&b); p1=&a; p2=&b; //如图10.1.2(a)所示 if(a<b) { p=p1; p1=p2; p2=p;//如图10.1.2(b)所示 } printf("a=%d\tb=%d\n",a,b); printf("max=%d\tmin=%d\n",*p1, *p2); }
p1 &a p2
a
3b 5 图10.1.2(a) a
&bp1 &b p2
3b 5 图10.1.2(b)
程序运行结果: 输入任意两个整数:3 5 a=3 b=5 max=5 min=3
&a
练习 书后选择题1、2、3
10.1.5 指向指针的指针 可以定义一个指针变量pp存储另一个指针变量p的地址,这个变量pp,就是
指针变量也是变量,它在内存中也分配存储空间,因此,指针变量也有地址。
指向指针变量p的指针变量。 定义指向指针的指针的一般形式:
类型名 ** 变量名;例如:int a=10, *p=&a, **pp=&p; 利用指针变量对数据进行访问是“间接访问”,普通的指针变量用的是“单
级间址”,而指向指针的指针使用的则是“二级间址”。 变量名:pp 地址:1310580 变量名:p 地址:1310584 变量名:a 地址:1310588
值:1310584
值:1310588
值:10
10.2 指针与函数 10.2.1 指针变量作为函数参数 10.2.2 函数的返回值为指针(*) 10.2.3 指向函数的指针(*)
10.2.1 指针变量作为函数参数 用指针做参数,实际参数和形式参数之间仍然是值传递,
即在调用函数时,把实际参数的值赋给形式参数。被调函 数中虽然不能改变作为实际参数的指针变量的值,但可以 改变指针变量所指变量的值,从而达到在被调函数中修改 主调函数中变量的目的。 用指针变量作为函数参数,可以获得从函数中带回多于一
个值的客观效果。
10.2.1 指针变量作为函数参数例10.2.1调用函数,交换两个 变量的值。 //程序1,使用整型参数: #include <stdio.h> void swap(int x , int y) { int temp; temp=x; x=y; y=temp; //交换形参x,y的值 }程序运行结果: 请输入两个整数a和b:3 5 调用函数前:a=3 b=5 调用函数后:a=3 b=5
void main() { int a,b; printf(“请输入两个整数a和b:”);
scanf("%d%d",&a,&b);printf("调用函数前: a=%d\tb=%d\n",a,b); swap(a,b); printf("调用函数后: a=%d\tb=%d\n",a,b);}