9.1 地址、指针和变量 9.2 指针运算 9.3 指针与数组 9.4 函数与指针 9.5 程序综合举例 9.6 上机实训.

Slides:



Advertisements
Similar presentations
第 8 章 数组 计算机科学学院 李淮 Tel QQ
Advertisements

第九章 指针 西安工程大学.
第七章 指针 计算机公共教学部.
第六章 指针 指针的概念 指针变量 指针与数组 指针与函数 返回指针值的函数.
第十章 指针 分析C程序的变量所存放的数据:  数值型数据:整数、实数  字符型数据:字符、字符串 这些变量具有以下性质:
第7章 指针 存储地址的变量的类型就是指针类型 能直接对内存地址操作, 实现动态存储管理 容易产生副作用, 初学者常会出错
第七章 指针 教 材: C程序设计导论 主 讲: 谭 成 予 武汉大学计算机学院.
二级指针与二维数组.
C语言程序设计基础 第10章 指针进阶 刘新国.
10.1 二级指针 10.2 指针与二维数组 10.3 指针的动态存储分配 10.4 函数指针 10.5 main函数的参数
第 6 章 第 6 章 指 针 指 针 1.
C语言程序设计.
C语言基础——指针的高级应用 Week 05.
第6章 指针 6.1 指针的概念 6.2 变量与指针 6.3 数组与指针 6.4 字符串与指针 6.5 函数与指针 6.6 返回指针值的函数
6.4 字符串与指针 1. 用字符数组存放一个字符串.
第六节 二维数组和指针 二维数组的地址 对于一维数组: (1)数组名array表示数组的首地址, 即array[0]的地址;
C语言实验 第一课 标题:学号+姓名.
8.1 指针的概念 8.2 指针变量 8.3 指针变量的基础类型 8.4 指针的运算 8.5 指针与一维数组 8.6 指针应用实例
C++中的声音处理 在传统Turbo C环境中,如果想用C语言控制电脑发声,可以用Sound函数。在VC6.6环境中如果想控制电脑发声则采用Beep函数。原型为: Beep(频率,持续时间) , 单位毫秒 暂停程序执行使用Sleep函数 Sleep(持续时间), 单位毫秒 引用这两个函数时,必须包含头文件
第九章 指针 目录 指针与指针变量的概念 变量的指针和指向变量的指针变量 数组的指针和指向数组的指针变量
第5章 函数与模块化设计 学习目的与要求: 掌握函数的定义及调用方法 理解并掌握参数的传递方法 理解函数的嵌套与递归调用
程序设计基础.
第6章 指针 学习目的与要求: 了解指针的概念和相关术语 熟练掌握指向变量、数组和字符串的指针变量的使用方法 了解指向函数的指针变量
指 针 为什么要使用指针 指针变量 指针与数组 返回指针值的函数 动态内存分配 通过指针引用字符串 指向函数的指针 小 结 习 题.
C++语言程序设计 C++语言程序设计 第六章 指针和引用 第十一组 C++语言程序设计.
目录 10.1 指针的基本概念 10.2 指向变量的指针变量 10.3 指向数组的指针变量 10.4 指向函数的指针变量和指针型函数
第八章 指 针 8.1 指针的概念与定义 8.2 指针作函数参数 8.3 指针与数组 8.4 指针与函数 8.5 复杂指针.
第 十 章 指 针.
项目六 用指针优化学生成绩排名 项目要求 项目分析
第七章 函数 目录 有参的加法函数的开发 函数定义的一般形式 函数参数和函数的值 函数的调用
走进编程 程序的顺序结构(二).
第八章 函数.
第8章 善于利用指针 8.1 指针是什么 8.2 指针变量 8.3 通过指针引用数组 8.4 通过指针引用字符串 8.5 指向函数的指针
第8章 善于利用指针 8.1 指针是什么 8.2 指针变量 8.3 通过指针引用数组 8.4 通过指针引用字符串 8.5 指向函数的指针
二维数组的指针表示 与复杂的指针例子 专题研讨课之三.
第一单元 初识C程序与C程序开发平台搭建 ---观其大略
C++语言程序设计 C++语言程序设计 第六章 指针和引用 第十一组 C++语言程序设计.
第8章 指针.
第八章 使用指针.
第十章 指针.
欲穷千里,更上层楼 第十章 指 针 指针是C语言中广泛使用的一种数据类型。 运用指针编程是C语言最主要的风格之一。利用指针变量可以表示各种数据结构; 能很方便地使用数组和字符串; 并能象汇编语言一样处理内存地址,从而编出精练而高效的程序。指针极大地丰富了C语言的功能。 学习指针是学习C语言中最重要的一环,
第五章 习题课 电子信息与计算机科学系 曾庆尚.
C++语言程序设计 C++语言程序设计 第七章 类与对象 第十一组 C++语言程序设计.
C++语言程序设计 C++语言程序设计 第六章 指针和引用 第十一组 C++语言程序设计.
C语言复习3----指针.
线 性 代 数 厦门大学线性代数教学组 2019年4月24日6时8分 / 45.
C语言大学实用教程 第6章 数组 西南财经大学经济信息工程学院 刘家芬
C语言大学实用教程 第7章 指针 西南财经大学经济信息工程学院 刘家芬
函数 概述 模块化程序设计 基本思想:将一个大的程序按功能分割成一些小模块, 特点: 开发方法: 自上向下,逐步分解,分而治之
指针 几个概念:  指针也是一种数据类型,具有指针类型的变量,称为指针变量。
C++语言程序设计 C++语言程序设计 第六章 指针和引用 第十一组 C++语言程序设计.
第6讲 指针与引用 6.1 指针 6.2 引用.
<编程达人入门课程> 本节内容 内存的使用 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群: ,
C语言程序设计 第一章 数据类型, 运算符与表达式 第二章 顺序程序设计 第三章 选择结构程序设计 第四章 循环控制 第五章 数组.
第六章 指针 C++程序设计中使用指针可以: 使程序简洁、紧凑、高效 有效地表示复杂的数据结构 动态分配内存 得到多于一个的函数返回值.
7.1 C程序的结构 7.2 作用域和作用域规则 7.3 存储属性和生存期 7.4 变量的初始化
第6章 指针 6.1 指针的概念 6.2 变量与指针 6.3 数组与指针 6.4 字符串与指针 6.5 函数与指针 6.6 返回指针值的函数
第十章 指针 指针是C语言的重要概念,是C语言的特色,是C语言的精华。 10.1 地址和指针的概念 内存中的每一个字节都有一个地址。
C程序设计.
第4章 Excel电子表格制作软件 4.4 函数(一).
第九节 赋值运算符和赋值表达式.
第8章 善于利用指针 8.1 指针是什么 8.2 指针变量 8.3 通过指针引用数组 8.4 通过指针引用字符串 8.5 指向函数的指针
多层循环 Private Sub Command1_Click() Dim i As Integer, j As Integer
C++语言程序设计 C++语言程序设计 第六章 指针和引用 第十一组 C++语言程序设计.
C程序设计.
第二章 Java基本语法 讲师:复凡.
C语言程序设计 第8章 指针.
第九章 指针 C程序设计中使用指针可以: 使程序简洁、紧凑、高效 有效地表示复杂的数据结构 动态分配内存 得到多于一个的函数返回值.
第八章 指 针 北京邮电大学出版社.
第7章 地址和指针 7.1 地址和指针的概念 7.2 指针变量的定义和指针变量的基类型 7.3 给指针变量赋值 7.4 对指针变量的操作
Presentation transcript:

9.1 地址、指针和变量 9.2 指针运算 9.3 指针与数组 9.4 函数与指针 9.5 程序综合举例 9.6 上机实训

【本章要点】 本章主要介绍指针的基本概概念,指针运算,指针与数组,指针与函数等内容。指针是C语言的一个重要概念,也是C语言的一个重要特色。正确灵活的运用指针,可以使程序简洁、紧凑、高效;可以有效地表示复杂的数据结构。可以说,不掌握指针就没有掌握C语言的精华。

9.1 地址、指针和变量 地址:内存单元的编号也叫做地址。 指针:内存单元地址称为指针,即指针就是地址。 9.1 地址、指针和变量 地址:内存单元的编号也叫做地址。 指针:内存单元地址称为指针,即指针就是地址。 指针变量:存放指针的变量称为指针变量。 各种类型变量都有地址,通过地址(指针)或变量名访问变量。

9.1.1地址和指针的基本概念 变量:命名的内存空间,用于存放各种类型的数据。 变量名:变量名是给内存空间取的一个容易记忆的名字。 变量的地址:变量所使用的内存空间的地址。 变量值:在变量单元中存放的数值。即变量的内容。 “&”符号为取地址符号,可以取得变量的地址。

例如:输出整形变量a,b,c在内存分配的地址。 void main() { int a,b,c; printf(“\n%ld ,%ld ,%ld”,&a,&b,&c); } 运行结果为: 393176 , 589831, 687020

直接访问:在程序中使用变量名(变量地址)存取变量值的方式,称为“直接访问”方式。以前的程序中都是采用这种方式。 间接访问:定义一个指针变量来存放了一个变量的地址,通过指针变量存取变量的值,称为“间接访问”方式。 如图9.2所示:指针变量P存放变量a变量的地址393176,a变量的值为5。

9.1.2 指针变量类型的定义 定义的一般格式为: <存储类型> <数据类型> <*指针变量名>[=初始地址值]; 其中: (1)存储类型是任选项,主要有 auto型、register型、static型和extern型四种。 (2)数据类型是指针变量所指向变量数据类型。可以是int、char、float等基本类型,也可是数组等构造类型。 例如: int *p1,*p2;

9.1.3 指针变量的赋值 指针变量一定要周赋值后才可以使用。禁止使用未初始化或未赋值的指针(否则可能导致系统的崩溃)。 指针运算符: (1) &: 取地址运算符。 功能:取变量的地址。单目运算符,结合性为自右向左。 例如:&a为取变量a的地址。 (2) *: 取内容运算符 它的作用:与&相反,表示指针所指向的变量(取变量内容)。*是单目运算符,其结合性为自右向左。 例如:*p为指针变量p所指向的变量。

指针变量的赋值方法: 1.将地址直接赋值给指针变量 例如:float *f=(float *)malloc(4); 注: malloc()函数申请动态分配内存空间,返回空间首地址; free()函数释放不用内存空间。 使用这2个函数时需要声明头文件<stdlib.h>或<alloc.h>。 2.将变量的地址赋值给指针变量 例如: int i,*p; p=&i;

【例9.1】 通过指针变量访问整形变量。 void main() { int a,b; int *p1,*p2; /*定义两个指针变量*/ a=100;b=50; p1=&a; p2=&b; /* p1指向a,p2指向b*/ printf(“%d,%d\n”,a,b); printf(“%d,%d\n”,*p1,*p2); } 运行结果: 100,50

【例9.2】 输入两个整数,按先大后小的顺序输出。 【例9.2】 输入两个整数,按先大后小的顺序输出。 程序如下: void main() { int a,b,*p1,*p2,*p; scanf(“%d%d”,&a,&b); p1=&a;p2=&b; if (a<b) {p=p1;p1=p2;p2=p;} printf(“\na=%d,b=%d\n”,a,b); printf(“max=%d,min=%d\n”,*p1,*p2); } 运行结果为: 输入:5 9 ↙ 输出:a=5,b=9 max=9,min=5 程序运行中,指针变量p1,p2的指向变化如图

9.2 指针运算 9.2.1指针运算符 1.取地址运算符 & 功能:取变量的地址。单目运算符,结合性为自右向左。 例如:&a为取变量a的地址。 2.取内容运算符 * 功能:与&相反,表示指针所指向的变量(取指针内容,即变量)。*是单目运算符,其结合性为自右向左。在*运算符之后跟的变量必须是指针变量。

9.2.2指针变量的运算 1.赋值运算 有以下几种形式: (1) 指针变量初始化赋值 例如: float *f=(float *)malloc(4); int i,*p=&i; (2) 变量的地址赋予指针变量 int a,*p; p=&a; /*把整型变量a的地址赋予整型指针变量p*/ (3) 指针变量的值赋予另一个指针变量(类型相同) int a,*pa=&a,*pb; pb=pa; /*把a的地址赋予指针变量pb*/

或写为:p=&a[0]; 或:int a[5],*p=a; (5) 字符串首地址赋予指针变量。 例如:char *pc; (4) 数组的首地址赋予指针变量。 例如:int a[5],*p; p=a; 或写为:p=&a[0]; 或:int a[5],*p=a; (5) 字符串首地址赋予指针变量。 例如:char *pc; pc="Hello"; 或写为: char *pc="Hello"; 说明:并不是把整个字符串装入指针变量,而是把存放该字符串的首地址装入指针变量。 (6) 函数的入口地址赋予指针变量。 例如: int (*pf)(); pf=f; /*f为函数名*/

2.加减运算 (1)指针加减任意整数运算 运算条件:必须是指向数组的指针变量(即数组指针,在9.3.1节中介绍),才能加可以加上或减去一个整数n。对指向其它类型变量的指针变量作加减运算是毫无意义的。 运算形式:设有数组指针变量p,则有: p+n,p-n,p++,++p,p--,--p 运算都是合法的。 运算作用:指针变量±n就是把指针指向的当前位置向前(减)或向后(加)移动n个元素位置。 注意:数组指针变量±n不是地址加减n,而是移动n个元素位置。 例如: int a[5],*p; p=a; /*p指向数组a,也是指向a[0]*/ p=p+2; /*p指向a[2],即p的值为&p[2]*/

(2)两指针变量相减 运算条件:必须是指向同一数组的2个指针变量才能进行两指针相减运算。 运算形式:设有数组指针变量p、q,则有: p-q 运算作用:相减所得之差是两个指针所指数组元素之间相差的元素个数。 例如: 设pf1=2010H,pf2=2000H且指向同一实型数组a的两个指针变量, 则得: pf1-pf2=(2000H-2010H)/4=4 注意: pf1+pf2是什么意思呢? 毫无实际意义。

(3)指针的关系运算 运算条件:必须是指向同一数组的2个指针变量才能进行关系运算。 运算作用:两个指针变量通过关系运算进行比较,主要用于判断他们的前后位置关系。 例如:设如果pa和qa都指向同一个数组a, 则有:pa>qa、pa<qa、 pa>=qa、 pa<=qa、 pa==qa、 pa!=qa 说明:当pa所指元素在qa之前,则表达式“pa<qa”为真(值为1); 当pa和qa都指向同一个元素时,表达式“pa==qa” 为真(值为1)。

【例9.4】(1)已知指针p的指向如图9.5所示,执行语句*p++;后,*p的值是多少?p指向哪一个元素? 解答: 先进行*p的操作,得到p所指变量的值20,然后进行p+1操作,指向a[2]。 先将指针p加一,指向a[2],然后进行*p操作,值是30。 ++*p是使p所指的变量的内容加一,值为21,p仍指向a[1]。

9.3 指针与数组 9.3.1 数组指针 1.指向一维数组的指针 数组名代表数组的首地址,是一个常量。 数组指针:就是指向数组元素地址的指针变量。 引用数组元素除了用下标法外也可以用指针法来引用数组元素。 例如:int a[8]={2,4,6,8,10,12,14,16}; int *p;p=&a[0]; 如图9.6所示: 下面的语句是等价的: p=&a[0]; p=a;

例如: int a[8]={2,4,6,8,10,12,14,16}; int *p=&a[0]; 它相当于: int *p; p=&a[0]; 有以下四种方法引用数组元素a[k]: *(p+k)、*(a+k)、p[k]、a[k] 前两种称为指针法,后两种称为下标法。 注意:p++; 操作时允许的。 a++; 操作是错误的,因为a是常量。

① 执行p++ ,p指向下一个元素,即a[1]。*p为a[1]的值。 ② *p++,相当于 *(p++)。 注意指针变量的运算。 设指针p=a(a为数组名) ① 执行p++ ,p指向下一个元素,即a[1]。*p为a[1]的值。 ② *p++,相当于 *(p++)。 ③ *(p++)与 *(++p)作用不同。 ④ (*p)++,表示将p所指向的元素值加1. ⑤ 如果p当前指向a数组中的第i个元素,则: *(p--)相当于a[i--],先取p值作“*”运算,再使p自减。 *(++p)相当于a[++i],先使p自加,再作*运算。 *(--p)相当于a[--i], 先使p自减,再作*运算。

【例9.5】用上面介绍的四种不同方法访问数组元素。 #include<stdio.h> void main() { int a[5]={0,1,2,3,4}; int *p,i; for(i=0;i<5;i++) { printf(“%d ”,a[i]); printf(“%d ”,*(a+i)); printf(“%d ”,p[i]); printf(“%d ”,*(p+i)); printf(“\n”); } 程序中的四个输出是一样的。程序输出如下: 0 0 0 0 1 1 1 1 2 2 2 2 3 3 3 3 4 4 4 4

【例9.6】通过指针变量输入输出a数组的8个元素。程序如下: void main() { int *p,i,a[8]; p=a; for (i=0;i<8;i++) scanf(“%d”,p++); printf(”\n”); p=a; /*注意此语句的作用*/ for (i=0;i<8;i++,p++) printf(“%4d”,*p); }

二维数组a,可视为三个一维数组:a[0]、a[1]、a[2];而每个一维数组又是一维数组,分别由4个元素组成,即: 二维数组名 一维数组名 2.指向二维数组的指针 设有一个二维数组a定义为: int a[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}}; 二维数组a,可视为三个一维数组:a[0]、a[1]、a[2];而每个一维数组又是一维数组,分别由4个元素组成,即: 二维数组名 一维数组名 数组元素 a a[0] a[1] a[2] a[0][0] a[0][1] a[0][2] a[0][3] a[1][0] a[1][1] a[1][2] a[1][3] a[2][0] a[2][1] a[2][2] a[2][3]

用数组名表示二维数组的行地址 数组名总是代表数组的首地址。 则有:a 为二维整型数组名,a=2000。 a 就是第0行的首地址2000。即为a[0] a+1 代表第一行首地址。为2008。即为a[1] a+2 代表第二行首地址。即2016。即为a[2] (2)用数组名表示二维数组元素地址 二维数组中a[0]、a[1]、a[2]都是地址, 则有:*(a+0)、*(a+1)和*(a+2)也是地址,它们分别是第0行、1行和2行的第0列首地址。 因此,a[0]+1等介于*(a+0)+1,即&a[0][1]。 a[1]+2等介于*(a+1)+2,即&a[1][2]。 a[2]+3等介于*(a+1)+3,即&a[1][3]。

a[0][1]的值 可表示为:*(a[0]+1)和*(*(a+0)+1) a[i][j]的值 可表示应为:*(a[i]+j)和*(*(a+i)+j)。 数组元素三种形式引用: ⑴ a[i][j] 下标法 ⑵ *(a[i]+j) 用一维数组名 ⑶ *(*(a+i)+j) 用二维数组名

3.用指针变量指向二维数组及其元素 (1) 指向数组元素的指针变量 二维数组的每个元素在内存中存储在地址连续的存储空间中。如图9.7和9.8所示。用指向数组元素的指针变量来引用数组。

【例9.7】 用指针变量输出二维数组每个元素的值。 void main() { int a[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}}; int *p; for (p=a[0];p<a[0]+12;p++) printf(“%4d”,*p); } 注意:for语句中的p=a[0]可改为p=&a[0][0],但不能为p=a。

【例9.8】 输出二维数组a中任一行任一列元素的值。 程序如下: void main() { int a[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}}; int *p=a[0],i,j; scanf(“%d,%d”,&i,&j); printf(“\n%4d”,*(p+i*4+j)); } 运行程序输入:2,2↙ 输出: 21

(2) 指向由m个整数组成的一维数组的指针变量 定义格式: (*标识符)[一维数组元素个数]; 例如:int (*q)[4]; 定义一个指针变量q,它指向包含有4个元素的一维数组。 注意:*q必须放在括弧内,否则就变成了定义指针数组。 由于q是指向有4个整形元素的一维数组的指针变量,因此,q+1是将地址值加上4*2,即指向下一个一维数组。如图9-8所示。

设有如下定义: int a[3][4]= {{1,2,3,4},{5,6,7,8},{9,10,11,12}}; int (*q)[4]; q=a; 则: q+0 为二维数组第0行首地址,与a+0或*(a+0)相同; q+1 为二维数组第1行首地址,与a+1或*(a+1)相同; q+2 为二维数组第2行首地址,与a+2或*(a+2)相同; *(q+i)+j 为第i行第j列元素的地址,与*(a+i)+j相同; *(*(q+i)+j) 为第i行第j列元素,与*(*(a+i)+j)相同,即a[i][j]。

【例9.9】 用指向有m个元素一维数组的指针变量输出二维数组任一行任一列元素的值。 void main() { int a[3][4]= {{1,2,3,4},{5,6,7,8},{9,10,11,12}}; int (*q)[4]; /*指针变量p是指向有4个元素的一维数组*/ q=a; scanf(“%d,%d”,&i,&j); printf(“\na[%d][%d]=%d”,i,j,*(*(q+i)+j)); } 运行结果如下: 输入:1,2↙ 输出:a[1][2]=13

【例9.10】有一个3×3的矩阵a。编程对它进行转置操作。 程序思想:主对线为界,对矩阵元素的行列元纯洁互换即可。即a[i][j]与为a[j][i]交换。 程序结构分为以下几块: (1)对数组a进行初始化; (2)给数组a的指针p赋值; (3)进行数组元素的转置; (4)输出结果数组。

#include<stdio.h> void main() { int a[3][3]={1,2,3,4,5,6,7,8,9}; int i,j,k,(*p)[3]=a; for(i=0;i<3;i++) { for(j=i;j<3;j++) { k=*(*(p+i)+j); *(*(p+i)+j)= *(*(p+j)+i); *(*(p+j)+i)=k; } { printf(“\n”); for(j=0;j<3;j++) printf(“%d ”, *(*(p+i)+j)); 输出结果为: 1 4 7 2 5 8 3 6 9

函数的参数传递可以采用地址传递。所以指针可作为函数参数。 4.指针作为函数的参数 函数的参数传递可以采用地址传递。所以指针可作为函数参数。 当指针作为函数的形参时,实参传递的是地址,在函数中通过地址访问实参,所以,在函数中通过地址对实参的修改影响到实参的值。 【例9.11】输入的两个整数按大小顺序输出。 #include<stdio.h> void swap(int x,int y) { int temp; temp=x; x=y; y=temp; }

void main() { int a,b; scanf("%d,%d",&a,&b); if(a<b) swap(a,b); printf("\n%d,%d\n",a,b); } 运行结果: 1, 2↙ 1,2 可见:此程序没能够达到题目要求。 虽然a<b,并且进入swap()函数进行数据交换,实现了x和y的交换,返回到主函数后,x和y都被释放掉了。

#include<stdio.h> swap(int *p1,int *p2) { int temp; temp=*p1; 【例9.12】输入的两个整数按大小顺序输出。 #include<stdio.h> swap(int *p1,int *p2) { int temp; temp=*p1; *p1=*p2; *p2=temp; } void main() { int a,b; int *p1,*p2; scanf("%d,%d",&a,&b); p1=&a;p2=&b; if(a<b) swap(p1,p2); printf("\n%d,%d\n",a,b); 运行结果: 1, 2↙ 2,1

5.数组名作为函数参数 【例9.13】 在主函数中定义数组,在被调用函数中用库函数产生20个100以内的随机整数,在主函数中输出这些整数。 程序如下: #include<stdio.h> #include “stdlib.h” #define N 20 getin(int x[ ],int m) { int i; for (i=0;i<m;i++) x[i]=random(100); /*产生100以内的随机整数*/ }

{ if (i%5==0 ) printf(“\n”); printf(“%4d”,array[i]); } void main() { int array[N]; int i; getin(array,N); for (i=0;i<N;i++) { if (i%5==0 ) printf(“\n”); printf(“%4d”,array[i]); } 程序运行结果为: 46 30 82 90 56 17 95 15 48 26 4 58 71 79 92 60 12 21 63 47 数组指针作为函数参数可以分为4种情况: ☆ 形参、实参都是数组名; ☆ 实参是数组名,形参是指针变量; ☆ 形参、实参都是指针变量; ☆ 实参是指针变量,形参是数组名。

【例9.14】 用选择排序法,将10个数升序排列。 程序思想:选择排序的基本思想是,首先在10个数中选出一个最小数并将其存入a[0];然后在剩下的9个数中再选出一个最小数并存入a[1];依次类推,共选9次。 具体操作步骤: (1) 将10个数存入数组a。 (2) 在10个数选出一个最小数存入a[0]。 (3) 在剩下的9个数中,再选出一个最小数并存入a[1] (4) 在剩下的8个数中选出一个最小数并存入a[2]。 (5) 依此类推,直到选出第9个数,剩下的一个数是最大的。 (6) 用外循环控制选第几个最小数,内循环控制从第几个数开始选。

程序如下: #include<stdio.h> void sort (int *x,int n) /*可以为:void sort(int x[],int n) */ { int i,j,k,t; for (i=0;i<n-1;i++) { k=i; /*变量k用来记录最小数的位置*/ for (j=i+1;j<n;j++) if (*(x+j)<*(x+k)) k=j; if (k!=i) {t=*(x+i);*(x+i)=*(x+k);*(x+k)=t;} } void main() int *p,i,a[10]; for (i=0;i<10;i++) scanf(“%d”,&a[i]); p=a; sort(p,10); for (p=a,i=0;i<10;i++,p++) printf(“%4d”,*p) 运行结果如下: 1 0 4 8 12 65 -76 100 -45 123↙ -76 -45 0 1 4 8 12 65 100 123

9.3.2字符指针 1.字符串的表示形式 在C语言中,可以用两种方法实现对字符串的操作。 (1)用字符数组处理字符串。 【例9.15】 void main() { char str[]=“I love china!”; printf(“%s”,str); } 或: char str[]=”I love china!”; int i; for (i=0;*(str+i)!=’\0’;i++) printf(“%c”,*(str+i)); 运行结果: I love china!

(2)用字符指针实现 将字符串的首地址赋给指针,用字符指针变量来处理字符串。 【例9.16】 用指针变量逐个输出数组中的每个字符。 void main() { char str[ ]=”I love china!”; char *p; int i; p=str; for (i=0;*(p+i)!=’\0’;i++) printf(“%c”,*(p+i)); } 或用指针变量整体输出字符数组的值。 void main() { char str[ ]=”I love china!”; char *p; int i; p=str; printf(“%s”,p); } 也可以在定义字符指针的同时初始化。 { char *str=“I love china!”; printf(“%s\n”,str);

【例9.17】 将字符串a复制到字符串b。 void main() { char a[ ]=”I love china!”; char b[20]; int i; for (i=0;*(a+i)!=’\0’;i++) *(b+i)=*(a+i); *(b+i)=’\0’; printf(“%s\n”,a); for (i=0;b[i]!=’\0’;i++) printf(“%c”,b[i]); } 用指针变量处理例9.17问题。程序如下: void main() { char a[ ]=”I love china!”,b[20],*p1,*p2; int i; p1=a;p2=b; for (;*p1!=’\0’;p1++,p2++) *p2=*p1; *p2=’\0’; printf(“%s\n”,a); for (i=0;b[i]!=’\0’;i++) printf(“%c”,b[i]); } 运行结果: I love china!

字符数组名可作函数参数,字符指针变量也可作函数参数。 2.字符指针作函数参数 字符数组名可作函数参数,字符指针变量也可作函数参数。 【例9.18】 用函数调用实现字符串的连接。 strcat12(char *p1,char *p2) { while (*p1!=’\0’) /*使p1指向第一个字符串末尾*/ p1++; while (*p2!=’\0’) /*将p2连接到第一个字符串的当前位置*/ { *p1=*p2;p1++;p2++; } *p1=’\0’; } void main() char str1[40]={“People’s Republic of ”}; char str2[ ]={“China”}; strcat12(str1,str2); printf(“%s\n”,str1); 运行结果: People’s Republic of China

字符数组和字符指针变量都能实现字符串的存储与运算,但两者之间还是有区别的,主要包括以下几点: 3.字符指针变量与字符数组 字符数组和字符指针变量都能实现字符串的存储与运算,但两者之间还是有区别的,主要包括以下几点: (1) 字符数组由若干元素组成,每个元素存放一个字符; 字符指针变量存放的是字符串的首地址。 (2) 赋值方式不同: 不能用赋值语句给字符数组赋值。 char str[14]; str=“I love china!” 这是错误的。 字符指针变量可以采用下面的形式赋值: char *p; p=“china!” 这是正确的。 但要注意赋给指针变量p的不是字符串,而是字符串的首地址。 (3)定义一个数组,在编译时分配存放n个元素的存储空间; 定义指针变量只分配存放一个地址的空间。 (4)指针变量的值是可以改变的,字符数组名则不行。

【例9.19】字符指针变化输出。 void main() { char *a=“I love China!”; a=a+7; /* a已指向了字符C*/ printf(“%s”,a); } 运行结果如下: China! /*当前地址直到字符串结束为止*/ 字符数组不能采用如下形式: char str[]={“I love China!”}; str=str+7; /*该语句是错误的*/ printf(“%s”,str); 数组名是一个常量其值是不能改变的。 (5) 可以用指针变量指向一个格式字符串,用它代替printf中的格式串。 char *format=“a=%d,b=%f\n”; printf(format ,a,b)

9.3.3 指针数组 指针数组:数组的所有元素都是存放指针的数组称为指针数组。 即:指针数组中每一个元素(下标变量)都是指针变量。 指针数组的定义形式: <存储类型> <数据类型> <*指针数组名>[数组长度][={地址列表}]; 例如: Staic int *p[4]; 由于[ ]比*的优先级高,先构成p[4]数组形式,有4 个元素:p[0],p[1],p[2],p[3]。然后再与p前面的“*”结合成为指针数组。 指针数组的用途:每个元素存放一个字符串首址,使得在处理多个字符串时非常方便。

例如:图书馆有下列一些书籍,Visual BASIC、QBASIC、Pascal、C、Visual Foxpro等 ,将这些书名进行排序。 处理方法: 先定义一个二维数组存放这些书名。 char ch[ ][14]; 存储空间如图9.9所示。 ch[0]VisualBASIC\0Ch[1]QBASIC\0Ch[2]Pascal\0Ch[3]C\0Ch[4]VisualFoxpro\0图9.9 字符数组ch[][14] 存储空间 图9.9 字符数组ch[ ][14] 存储空间

(2)定义一个指针数组 例如定义: char *p[5]; for(i=0;i<5;i++) p[i]=ch[i]; 存储空间如图9.10所示。 或: char *p[5]={“Visual BASIC”,”Qbsic”,”Pascal”,”C”,”Visual Foxpro” }; 【例9.20】 将若干字符串按字母顺序由小到大排序。 程序思想:以上面图书馆书籍名称排序为例,只需改变指针数组的指向,使其指针所指的字符串按字母从小到大排序即可。

程序如下: #include <string.h> void sort (char *xname[ ],int n) { char *temp; int i,j,k; for (i=0;i<n-1;i++) k=i; for (j=i+1;j<n;j++) if (strcmp(xname[k],xname[j])>0) k=j; if (k!=i) { temp=xname[i]; xname[i]=xname[k]; xname[k]=temp; } }

void main() { Char *name[ ]={“Visual BASIC”,”QBasic”,”Pascal”,”C”,”Visual Foxpro” }; int n=5; sort(name,n); for (i=0;i<n;i++) printf(“%s\n”,name[i]); } 运行结果: C Pascal QBasic Visual BASIC Visual Foxpro

9.4 函数与指针 9.4.1函数指针 函数名就代表函数的入口地址。 函数指针:函数的入口地址称为函数指针。即指向函数的指针变量为函数指针。 函数指针定义格式: <存储类型> <数据类型> (*指针变量名)(); 其中:“存储类型”是函数指针本身的存储类型; “数据类型”是指函数返回值的数据类型; 例如: int (*p)(); 定义一个指向整形函数的指针变量p。

【例9.21】 求a和b中的最大者。 程序如下: void main() { int max(); int (*p)(); int a,b,c; p=max; /*函数max入口地址赋给p*/ scanf(“%d,%d”,&a,&b); c=(*p)(a,b); printf(“a=%d,b=%d,max=%d”,a,b,c); } int max(int x,int y) { int z; if (x>y) z=x; else z=y; return(z);

9.4.2指针函数 指针函数:返回指针值的函数称为指针函数。 指针函数定义形式: <类型标识符> <*函数名>(参数表); 例如: int *f1(x,y); 其中f1为函数名,调用f1后得到一个指向整型数据的指针(地址)。 【例9.22】 有若干个学生成绩(每个学生有4门课),要求在用户输入学号后,能输出学生的全部成绩,用指针函数实现。

程序如下: void main() { float score[ ][4]={{66,76,86,96},{66,77,88,99},{48,78,89,90}}; float *serach(float(*pointer)[4],int n); float *p; int i,m; printf(“Enter the number of student:”); scanf(“%d”,&m); /*输入要查找的学生序号*/ printf(“The scores of No.%d are:\n”,m); p=search(score,m); for (i=0,i<4;i++) /*输出第n个学生的全部成绩*/ printf(“%6.2f”,*(p+i)); }

float *search(float (*pointer)[4],int n) /*函数的返回值为指向实型数据的指针*/ { float *pt; pt=*(pointer+n); /*把指针定位在第n个学生的第一个数据上*/ return(pt); /*函数的放回值为第n个学生成绩的首地址*/ } 运行结果如下: Enter the number of student:1 The scores of No.%d are: 66.00,77.00,88.00,99.00

9.4.3指向指针的指针 指针变量:专门用来存放另一个变量的地址的变量就称为指针变量; 指向指针的指针:用来存放指针变量的地址的变量就称为指向指针变量的指针变量。有的教材又称为二级指针变量。 定义格式: <类型标识符> **变量名; 例如:int **p;

【例9.24】 void main() { int a=12; int *p1,**p2; p1=&a; p2=&p1; printf(“%d,%d\n”,*p1,**p2); } 运行结果: 12,12

9.5 程序综合举例 假设每班人数最多不超过40人,具体人数由键盘输入,试编程打印最高分及其学号。 【例9.26】 用一维数组和指针变量作为函数参数,编程打印某班一门课成绩的最高分及其学号。 #include <stdio.h> #define ARR_SIZE 40 int FindMax(int score[], long num[], int n, long *pMaxNum); void main() { int score[ARR_SIZE], maxScore, n, i; long num[ARR_SIZE], maxNum; printf("Please enter total number:"); scanf("%d", &n); /*从键盘输入学生人数n*/ printf("Please enter the number and score:\n"); for(i=0; i<n; i++) /*输入学生的学号和成绩*/ { scanf("%ld%d", &num[i], &score[i]); } maxScore = FindMax(score, num, n, &maxNum); printf("maxScore = %d, maxNum = %ld\n", maxScore, maxNum); }

/* 函数功能:计算最高分及最高分学生的学号*/ int FindMax(int score[ ], long num[ ], int n, long *pMaxNum) { int i; int maxScore; maxScore = score[0]; /*假设score[0]为最高分*/ *pMaxNum = num[0]; for (i=1; i<n; i++) if (score[i] > maxScore) { maxScore = score[i]; /*记录最高分*/ *pMaxNum = num[i]; /*记录最高分学生的学号*/ } return (maxScore); /*返回最高分maxScore*/

【例9.27】 用二维数组和指针变量作为函数参数,编程打印3个班学生(假设每班4个学生)的某门课成绩的最高分,并指出具有该最高分成绩的学生是第几个班的第几个学生。 程序如下: #include <stdio.h> #define CLASS 3 #define STU 4 int FindMax(int score[CLASS][STU], int m, int *pRow, int *pCol); void main() { int score[CLASS][STU], i, j, maxScore, row, col; printf("Please enter score:\n"); for (i=0; i<CLASS; i++) for (j=0; j<STU; j++) scanf("%d", &score[i][j]); /*输入学生成绩*/

maxScore = FindMax(score, CLASS, &row, &col); printf("maxScore = %d, class = %d, number = %d\n",maxScore, row+1, col+1); } int FindMax(int score[ ][STU], int m, int *pRow, int *pCol) { int i, j, maxScore; maxScore = score[0][0]; /*置初值,假设第一个元素值最大*/ *pRow = 0; *pCol = 0; for (i = 0; i<m; i++) for (j = 0; j<STU; j++) if (score[i][j] > maxScore) {maxScore = score[i][j]; /*记录当前最大值*/ *pRow = i; /*记录行下标*/ *pCol = j; } /*记录列下标*/ return (maxScore); /*返回最高分*/

9.6上机实训 实训1 1.实训目的 (1)掌握指针变量的定义与引用。 (2)掌握指针与变量、指针与数组的关系。 (3)掌握用数组指针作为函数参数的方法。 (4)熟悉集成环境的调试指针程序的方法。 2.实训内容 以下均用指针方法编程: (1)下面程序有部分错误,调试下列程序,使之具有如下功能: 用指针法输入12个数,然后按每行4个数输出。写出调试过程。

void main() { int j,k,a[12],*p; for(j=0;j<12;j++) scanf("%d",p++); { printf("%d",*p++); if(j%4 == 0) printf("\n"); } (2)调试此程序时将a、p、*p设置为"watch",调试时注意指针变量指向哪个目标变量。 (3)编写一个函数void sort(int *,int count),接收主程序中数组,并按照从小到大的顺序对数组中的元素排序。 (4)自己编写一个比较两个字符串s和t大小的函数strcomp(char *s,char *t),要求s小于t时返回-1,s等于t时返回0,s大于t时返回1。在主函数中任意输入4个字符串,利用该函数求最小字符串。

3.实验要求 (1)复习指针的定义与使用方法。 (2)编写程序,运行程序并记录运行结果。 (3)将源程序、目标文件、可执行文件和实验报告存在服务器的指定文件夹。