1、第六章指针第一节指针与指针变量 1 指针的基本概念计算机内存是有一片连续的存储单元组成 操作系统给每个单元一个编号 这个编号称为内存单元的地址 每个存储单元占内存一个字节 定义变量时 系统就按照其类型为变量分配一块连续的存储单元 则这块存储单元的首地址称为该变量的指针 也称该变量的地址 如 floatf 假设分配给f的是地址为1500 1501 1502 1503的四个连续字节 则称地址1500是变量f的指针 或说变量f的地址是1500 所以 变量的地址就是变量的指针 第六章指针第一节指针与指针变量 先来看卡片管理系统假设有许多存储不同数据的卡片 如图 想对这些数据快速存取 一个好方法就是对每
2、张卡片编号 再为每张卡片取个名字 让名字和编号一一对应起来 这样就能通过名字存取卡片上的数据 比如指出卡片名f 就可以由对应地址1500处取出数据456 789 注意 p是一种特殊的卡片 它存储的是卡片f的编号 则通过p也能间接地存取卡片f的数据 图5 1 第六章指针第一节指针与指针变量 变量值的存取与卡片数据存取相类似 每个变量都有名字和地址 同样是使用变量名通过相应地址存取数据 可以把图5 1理解成变量存储的情况 如图5 2 假设变量f为float型 则读取f的值是从地址1500开始的四个字节中取出数据456 789 这种称为 直接存取 方式 特殊变量p存储了变量f的地址 则可以通过访问p
3、变量 可以得到地址1500 再访问1500的存储单元 也可以得到f的值456 789 这种称为 间接存取 方式 图5 2 第六章指针第一节指针与指针变量 象p变量这种 专门存放其他变量的地址的变量 称为指针变量 如图5 2 指针变量p里已经存储了f变量的地址 我们又说指针变量p指向了变量f 2 指针变量的定义定义的一般形式 类型名 标识符 如 inti ip jp 定义了ip和jp两个可以指向整型变量的指针变量 floatf p 定义了一个可以指向float型变量的指针变量p 注意 a 定义了一个指针变量 在没有对它赋值前 它指向的存储单元是不确定的 b 一个指针变量只能指向其类型相同的变量
4、第六章指针第一节指针与指针变量 3 指针变量的赋值1 通过地址运算符变量p指向ff3d变量f 第六章指针第一节指针与指针变量 3 通过其他指针变量赋值可以把一个指针变量的地址值赋给另一个指针变量 这样两个指针变量均指向同一个地址 如 inti p1 指向2f3a变量p1变量i变量p2注意 当把一个指针变量的地址值赋给另一个指针变量时 赋值号两边指针变量所指的数据类型必须相同 第六章指针第一节指针与指针变量 如 inti pi 或p 0 NULL可以赋值给指向任何类型的指针变量 第六章指针第一节指针与指针变量 6 1 2指针运算符指针运算符 和取地址运算符 指针运算符 的运算对象必须放在指针运算
5、符的右侧 是用来存取相应的存储单元中的数据 运算符 和 都是单目运算符 它们具有相同的优先级 结合方向均为 从右到左 例如 inti 123 j p p i 则j p 和j i 都将把变量i的值赋给变量j 而 p 456 和 i 456 都将把整数456赋给变量i 第六章指针第一节指针与指针变量 所以 1 i等价于变量i 2 当一个指针变量p指向某变量i时 p i 则表达式 p与变量i等价 例如 p i printf d n p 相当于printf d n i j p 相当于j i十十 注意表达式 p 中的括号不能省略 如果没有括号 则 p 等价于 p 此时先使用变量i的值 再使p的值改变 这
6、样p就不再指向变量i了 第六章指针第一节指针与指针变量 指针变量的值是可以改变的 通过 p方式存取它所指向变量的值是以间接存取的形式进行的 如 inti 1 j 2 p p i p 100 相当于i 100 p j p 相当于j 另外 注意 若有inti p 相当于intI p p i 则1 p等价于i等价于 i2 p等价于p3 i是非法的表达式 因为i不是地址 也不是指针变量 而指针运算符 的运算对象必须是指针变量或地址 第六章指针第一节指针与指针变量 例6 1 由键盘输入一个正整数 求出其最高位数字 用指针变量来完成本题 main longi p p i printf 请输人一个正整数 s
7、canf ld p 本语句等价于scanf ld i while p 10 P 10 求出该正整数的最高位数字 printf 最高位数字是 ld n p 运行结果 请输人一个正整数 56789最高位数字是 5 语句P i 是不可少的 若指针变量P在使用之前未赋初值 它可能指向内存中任意一个地址 可能导致程序出现意想不到的错误 第六章指针第二节数组与指针 6 2 1指针与一维数组1 一维数组和数组元素的地址一个数组的元素在内存中是连续存放的 数组第一个元素的地址称数组的首地址 在C语言中 数组名是该数组的首地址 例如有以下定义语句 inta 10 p 则语句p a 和p a o 是等价的 即a等
8、价于 a o 都表示指针变量p指向a数组的首地址 数组首地址的值是一个地址常量 是不能改变的 因此 语句a p 或a 都是非法的 第六章指针第二节数组与指针 在C语言中 若定义inta 6 则 数组的0元素a 0 的地址是a 等价于数组的2元素a 2 的地址是a 2 等价于 a 2 数组的i元素a i 的地址是a i 等价于 a i 例如 有下述程序段 inta 6 1 2 3 4 5 6 p a p指向整型数组a的首地址 doubled 6 1 1 2 2 3 3 4 4 5 5 6 6 q d 假设数组a的首地址是2000 假设数组d的首地址是3000 第六章指针第二节数组与指针 则上述两
9、个数组分配的内存情况如图5 4所示 应注意整型数组 int 每下移一个元素地址加2字节 双精度实型数组 double 每下移一个元素地址加8字节 图5 4a 第六章指针第二节数组与指针 数组d的内存情况 图5 4b此时的q 1等价于d 1 也等价于 d 1 q i等价于d i 也等价于 d i 第六章指针第二节数组与指针 2 通过一维数组名所代表的地址存取数组元素根据指针运算符 的运算规则知 a i 与元素a i 等价例如 下述程序段 inta 1 2 3 4 5 6 7 8 9 10 a 5 50 相当于a 5 50 scanf d a 8 相当于scanf d a 8 printf d n
10、 a 5 相当于printf d n a 5 第六章指针第二节数组与指针 3 通过指针运算符 存取数组元素设有如下程序段 inta 10 p p a 则 p i 与元素a i 等价以下程序段合法 inta 1 2 3 4 5 6 7 8 9 10 p a p 5 50 相当于a 5 50 scanf d a 8 相当于scanf d p 8 printf d n p 5 相当于printf d n a 5 第六章指针第二节数组与指针 4 通过带下标的指针变量存取数组元素C语言中的下标运算符 可以构成表达式 假设p为指针变量且指向数组首元素 i为整型表达式 则可以把p i 看成是表达式 首先按p i计算地址 然后再存取此地址单元中的值 因此p i 与 p i 等价 例如 下述程序段 inta 1 2 3 4 5 6 7 8 9 10 p a p 5 50 相当于a 5 50 scanf d a 8 相当于scanf d p 8 printf d n p 5 相当于printf d n a 5 第六章指针第二节数组与指针 综上所述 若定义了一维数组a和指针变量p 且p a 则有如下等价规则 以上假设p所指的数据类型与数组a元素的数据类型一致 i为整型表达式 此处 两个表达式 相互等价 仅仅是指 存取变量值 时两个表达式是等价的