第六章 指针 C++程序设计中使用指针可以: 使程序简洁、紧凑、高效 有效地表示复杂的数据结构 动态分配内存 得到多于一个的函数返回值.

Slides:



Advertisements
Similar presentations
C++语言程序设计教程 第5章 构造数据类型 第6章 C++程序的结构.
Advertisements

第九章 指针 西安工程大学.
第六章 指针 指针的概念 指针变量 指针与数组 指针与函数 返回指针值的函数.
电子成绩单项目实现.
C语言程序设计教程 单位:德州学院计算机系.
第一章 C语言概述 计算机公共教学部.
第8章 指针 ● 8.1 指针简介 ● 8.2 指针变量的操作 ● 8.3 数组与指针 ● 8.4 二维数组与指针 ●本章小结 ●本章练习.
C语言基础——指针的高级应用 Week 05.
高级语言程序设计 C++程序设计教程(下) 2006年春季学期 与一些教材的区别 偏重理论,不去讨论某个系统的具体使用方法,但会涉及实现技术
第六节 二维数组和指针 二维数组的地址 对于一维数组: (1)数组名array表示数组的首地址, 即array[0]的地址;
第九章 指针 目录 指针与指针变量的概念 变量的指针和指向变量的指针变量 数组的指针和指向数组的指针变量
第5章 函数与模块化设计 学习目的与要求: 掌握函数的定义及调用方法 理解并掌握参数的传递方法 理解函数的嵌套与递归调用
复习与总结.
程序设计基础.
第六章 数 组 主讲教师 贾月乐 联系电话:
第5章 函数与预处理 《 C语言程序设计》 (Visual C++ 6.0环境) 本章导读
由C程序结构所知,一个完整的C语言程序是由一个且只能有一个main()函数(又称主函数)和若干个其他函数组合而成的。而前面各章仅学习main()函数的编程,本章将介绍其他函数的编程,包括其他函数的定义、调用、参数传递及变量的作用域等。
第4章 函数与预处理 4.1 概述 4.2 定义函数的一般形式 4.3 函数参数和函数的值 4.4 函数的调用 *4.5 内置函数
目录 10.1 指针的基本概念 10.2 指向变量的指针变量 10.3 指向数组的指针变量 10.4 指向函数的指针变量和指针型函数
项目六 用指针优化学生成绩排名 项目要求 项目分析
结构体和共用体 2 梁春燕 华电信息管理教研室.
目录 第八章 数组 1 简单学生成绩管理系统的开发 2 一维数组 3 多维数组 4 字符数组 5 数组作函数参数.
第七章 函数 目录 有参的加法函数的开发 函数定义的一般形式 函数参数和函数的值 函数的调用
Introduction to the C Programming Language
Object-Oriented Programming in C++ 第一章 C++的初步知识
Chap 8 指针 8.1 寻找保险箱密码 8.2 角色互换 8.3 冒泡排序 8.4 电码加密 8.5 任意个整数求和*
C语言程序设计 李祥.
第八章 函数.
第8章 善于利用指针 8.1 指针是什么 8.2 指针变量 8.3 通过指针引用数组 8.4 通过指针引用字符串 8.5 指向函数的指针
第五章 指针 5.1 指针的概念和定义 5.2 指针运算 5.3 指针和数组 5.4 字符串指针 5.5 指针数组 5.6 指向指针的指针
6.4.1指针与二维数组 1、二维数组结构的分析 设有数组定义为:int a[3][4]; 则有: a表示数组在内存中的首地址。
第二章 C++对C 在非面向对象方面的改进 更简洁,更安全.
第8章 指针.
第八章 使用指针.
谭浩强 编著 中国高等院校计算机基础教育课程体系规划教材 C++程序设计.
C++语言程序设计 C++语言程序设计 第六章 指针和引用 第十一组 C++语言程序设计.
第十章 指针.
第六章 指针、引用和动态空间管理 6.1 指针的概念 指针的概念 指针变量的定义和初始化
数组 梁春燕 华电信息管理教研室.
第1章 概述 本章要点: C语言程序结构和特点 C语言程序的基本符号与关键字 C语言程序的编辑及运行 学习方法建议:
C++大学基础教程 第5章 数组 北京科技大学 信息基础科学系.
六、函数 教学目标: 函数的概念、定义、调用和返回 带自定义函数的程序设计 递推算法 递归思想及算法实现 函数的参数传递方式 C语言程序设计.
第8章 函数 函数参数和函数的值 概述 函数定义的一般形式 函数的调用(嵌套调用、递归调用) 数组作为函数参数
C语言大学实用教程 第5章 函数与程序结构 西南财经大学经济信息工程学院 刘家芬
C++语言程序设计 第六章 数组 指针与字符串.
C语言复习3----指针.
第1章 绪论 北京师范大学 教育技术学院 杨开城.
第一章 程序设计和C语言 主讲人:高晓娟 计算机学院.
C语言程序示例: 1.输入10个数,按从小到大的顺序排序。 2.汉诺塔问题。.
C语言大学实用教程 第6章 数组 西南财经大学经济信息工程学院 刘家芬
函数 概述 模块化程序设计 基本思想:将一个大的程序按功能分割成一些小模块, 特点: 开发方法: 自上向下,逐步分解,分而治之
第八章 指標 (Pointer).
7.1 C程序的结构 7.2 作用域和作用域规则 7.3 存储属性和生存期 7.4 变量的初始化
第十四章 若干深入问题和C独有的特性 作业: 函数指针 函数作参数 函数副作用 运算 语句 位段 存储类别 编译预处理
第十章 指针 指针是C语言的重要概念,是C语言的特色,是C语言的精华。 10.1 地址和指针的概念 内存中的每一个字节都有一个地址。
C程序设计.
第5章 函 数.
第一章 C语言概述 教师:周芸.
第九章 指针.
第二章 基本数据类型 ——数据的表示.
第二讲 基本数据类 型及数组等 此为封面页,需列出课程编码、课程名称和课程开发室名称。
C程序设计.
第四章 函数 丘志杰 电子科技大学 计算机学院 软件学院.
Chap 7 数 组 7.1 排序问题 7.2 找出矩阵中最大值所在的位置 7.3 进制转换.
基本資料型態 變數與常數 運算子 基本的資料處理 授課:ANT 日期:2014/03/03.
第九章 指针 C程序设计中使用指针可以: 使程序简洁、紧凑、高效 有效地表示复杂的数据结构 动态分配内存 得到多于一个的函数返回值.
第9章 C++程序设计初步 9.1 C++的特点 9.2 最简单的C++程序 9.3 C++的输入输出 9.4 函数的重载
第六章 复合数据类型 指针的声明与使用 数组的声明与使用 指针与数组的相互引用 字符串及相关库函数 new与delete
C程序设计 复习 1、计算机系统的组成 外部设备:输入、输出设备(同人打交道《十进制》)
Presentation transcript:

第六章 指针 C++程序设计中使用指针可以: 使程序简洁、紧凑、高效 有效地表示复杂的数据结构 动态分配内存 得到多于一个的函数返回值

6.1 指针的基本概念 1. 变量与地址 i k 程序中: int i; float k; 变量是对程序中数据 存储空间的抽象 6.1 指针的基本概念 1. 变量与地址 内存中每个字节有一个编号-----地址 …... 2000 2001 2002 2005 内存 2003 程序中: int i; float k; i 编译或函数调用时为其分配内存单元 k 变量是对程序中数据 存储空间的抽象

2. 指针与指针变量 指针:一个变量的地址,它是一个整数形式的常量。 2019/4/24 2. 指针与指针变量 指针:一个变量的地址,它是一个整数形式的常量。 指针变量:专门用来存放地址的变量叫指针变量,它的值也可以是数组或函数的地址 。 …... 2000 2004 2006 2005 整型变量i 10 变量i_pointer 2001 2002 2003 指针 变量的内容 变量的地址 2000 指针变量 指针变量 变量 变量的地址(指针) 变量的值 指向 地址存入

3. 取地址运算符&与指针运算符* 两者关系:互为逆运算 含义: 取变量的地址 单目运算符 优先级: 14(第二高的级别) 结合性:自右向左 含义: 从某个地址中获取数据 单目运算符 优先级: 14 结合性:自右向左 两者关系:互为逆运算

指针运算符示例 10 i_pointer &i &(*i_pointer) = i *i_pointer *(&i) …... 2000 2004 2006 2005 整型变量i 10 变量i_pointer 2001 2002 2003 指针变量 i_pointer &i &(*i_pointer) i *i_pointer *(&i) = i_pointer-----指针变量,它的内容是地址量2000 *i_pointer----指针的目标变量i,它的内容是数据10 &i_pointer---指针变量占用内存的地址:2004

4. 直接访问与间接访问 直接访问:按变量地址存取变量值 间接访问:通过存放变量地址的变量去访问变量 例 i=3; -----直接访问 10 2019/4/24 4. 直接访问与间接访问 直接访问:按变量地址存取变量值 间接访问:通过存放变量地址的变量去访问变量 指针变量 …... 2000 2004 2006 2005 整型变量i 10 变量i_pointer 2001 2002 2003 例 i=3; -----直接访问 20 3 例 *i_pointer=20; -----间接访问

6.2 指针变量的定义与引用 1. 指针变量与其所指向的变量之间的关系 2. 指针变量的定义 一般形式: [存储类型] 数据类型 *指针名; 3 变量i 2000 i_pointer *i_pointer i &i i=3; *i_pointer=3 2. 指针变量的定义 一般形式: [存储类型] 数据类型 *指针名; 例 int *p1,*p2; float *q ; static char *name; 表示定义指针变量 不是乘法运算符* 合法标识符 指针变量本身的存储类型 指针的目标变量的数据类型 注意: 1、int *p1, *p2; 与 int *p1, p2;不一样。 2、指针变量名是p1,p2 ,不是*p1,*p2。 3、指针变量只能指向定义时所规定类型的变量。 4、指针变量定义后,变量值不确定,应用前必须先赋值。

3.对指针变量的操作 (1) 指针变量的初始化 将地址值赋给指针变量 一般形式:[存储类型] 数据类型 *指针名=初始地址值; 一般形式:[存储类型] 数据类型 *指针名=初始地址值; 变量必须已说明过; 并要求两者类型一致。 例 int i; int *p=&i; 例 int *p=&i; int i; 例 int i; int *p=&i; int *q=p; 用已初始化指针变量作初值 例 main( ) { int i; static int *p=&i; () .............. } 不能用auto变量的地址 去初始化static型指针

3.对指针变量的操作(续) (2) 指针变量 +/- 整数新的地址 (3) 指针变量 - 指针变量 整数(多少个数) (4) 关系运算 int a,b,c,d,*p,*q; p=&b; q=p+1; (2) 指针变量 +/- 整数新的地址 所加的数值:整数*字节数 q=p-1; p++; ++p; 注意:*p++; *++p; 不同于 (*p)++; ++ (*p); …... 2000 2008 200A 2002 2004 2006 200C 200E 2010 ... 5 9 整型变量a 整型变量b 整型变量c 整型变量d 20 22 指针变量p 指针变量q (3) 指针变量 - 指针变量 整数(多少个数) q-p 1; (4) 关系运算 p<q 1; p==q 0;

4. 指针变量必须先赋值,再使用! 例 main( ) { int i=10; int *p; *p=i; cout<<*p; } …... 2000 2004 2006 2005 整型变量i 10 指针变量p 2001 2002 2003 随机值 危险! 例 main( ) { int i=10,k; int *p; p=&k; *p=i; cout<<*p; }

5. 零指针 零指针与空类型指针 p指向地址为0的内存单元; 零指针:(空指针) 系统保证该单元不作它用; 表示指针变量的值没有意义。 定义:指针变量值为零 例如: int * p=0; p指向地址为0的内存单元; 系统保证该单元不作它用; 表示指针变量的值没有意义。 #define NULL 0 int *p=NULL; 例 int *p; ...... while(p!=NULL) { ...… } p=NULL与未对p赋值不同 用途: 避免指针变量的非法引用 在程序中常作为状态比较

6. 空类型指针 一般形式: void *类型指针; 例如: void *p; 例 char *p1; void *p2; p1=(char *)p2; p2=(void *)p1; TC中分配内存空间的函数返回一个空类型的指针。 void *malloc(int n); 例如:int *p= (int *) malloc(2);

例6.3 按先大后小的顺序输出a和b两个整数。 main() { int *p1,*p2,*p,a,b; a=5;b=9; …... 指针变量p1 指针变量p 2000 2010 2002 2004 2008 指针变量p2 整型变量b 整型变量a main() { int *p1,*p2,*p,a,b; a=5;b=9; p1=&a; p2=&b; if(a<b) { p=p1; p1=p2; p2=p;} cout<<a<<b; cout<<"max="<<"min="<<*p1<<*p2; } 2008 2010 2008 2010 2008 5 9 运行结果: 5,9<CR> a=5,b=9 max=9,min=5

7. 多重指针 一个指针变量的内容就是内存中某个存储区域的地址,这个存储区域中存放的值可以是一个基本数据类型的数据,也可以是另一个存储区域的地址。我们把这种类型的指针叫做多重指针。 二重指针(指向指针的指针)的一般说明形式为: 类型说明符 **指针变量名; 二重指针的使用。 main() { int *p1, **p2, i = 10; p1=&i; p2=&p1; }

6.3 函数之间地址值的传递 1. 形参为指针变量:传递的是指针变量的值----地址。 特点:共享内存, 相当于“双向”传递! 1. 形参为指针变量:传递的是指针变量的值----地址。 特点:共享内存, 相当于“双向”传递! 例6.5 将数从大到小输出(用变量作函数的参数) …... 2000 2008 200A 2002 2004 2006 void swap(int x,int y) { int temp; temp=x; x=y; y=temp; } void main() { int a=10,b=20; if(a<b) swap(a,b); cout<<a<<b; 变量a 变量b (main) 10 10 20 20 COPY 变量temp 变量y 变量x (swap) 值传递 20 10 10 运行结果:10, 20 不能达到预期的结果!

例6.5 将数从大到小输出(用指针作函数的参数) void swap(int *p1, int *p2) { int p; p=*p1; *p1=*p2; *p2=p; } main() { int a,b; int *pointer_1,*pointer_2; a=5; b=9; pointer_1=&a; pointer_2=&b; if(a<b)swap(pointer_1,pointer_2); cout<<a<<b; …... 2000 2008 200A 2002 2004 2006 200C 200E 2010 ... 整型变量a 整型变量b (main) 指针pointer_1 指针pointer_2 9 5 5 9 2000 2000 2002 2002 COPY (swap) 指针p1 指针p2 整型p 5

例6.5 将数从大到小输出(用指针作函数的参数)续 void swap(int *p1, int *p2) { int p; p=*p1; *p1=*p2; *p2=p; } main() { int a,b; int *pointer_1,*pointer_2; a=5; b=9; pointer_1=&a; pointer_2=&b; if(a<b)swap(pointer_1,pointer_2); cout<<a<<b; …... 2000 2008 200A 2002 2004 2006 200C 200E 2010 ... 整型变量a 整型变量b (main) 指针pointer_1 指针pointer_2 9 5 5 9 地址值传递 2000 2002 运行结果:9,5

例10.5 注意:指针变量要先赋值后,才能进行指针运算! …... 2000 2008 200A 2002 2004 2006 200C 200E 2010 ... void swap(int *p1, int *p2) { int *p; *p=*p1; *p1=*p2; *p2=*p; } main() { int a,b; int *pointer_1,*pointer_2; a=5; b=9; pointer_1=&a; pointer_2=&b; if(a<b) swap(pointer_1,pointer_2); cout<<a<<b; 整型变量a 整型变量b (main) 指针pointer_1 指针pointer_2 加两语句改正 int x; int *p=&x;x; 5 9 9 9 2000 2000 2002 编译警告! 结果有时也正确! 但也有错的时候! 2002 COPY (swap) 指针p1 指针p2 指针p **** 假设2000 指针变量在使用前 必须赋值! 运行结果:9,9

例6.5 错误程序之二 swap(int x,int y) { int t; t=x; x=y; y=t; } main() 例6.5 错误程序之二 …... 2000 2008 200A 2002 2004 2006 200C 200E 2010 ... swap(int x,int y) { int t; t=x; x=y; y=t; } main() { int a,b; int *pointer_1,*pointer_2; cin>>a>>b; pointer_1=&a; pointer_2=&b; if(a<b) swap(*pointer_1,*pointer_2); cout<<a<<b; 整型a 整型b (main) pointer_1 pointer_2 5 值传递 9 2000 5 2002 9 COPY (swap) 整型x 整型b 整型t 9 5 5 运行结果:5,9 也不能达到预期的结果!

例6.5 错误程序之三 swap(int *p1, int *p2) { int *p; p=p1; p1=p2; p2=p; } 例6.5 错误程序之三 swap(int *p1, int *p2) { int *p; p=p1; p1=p2; p2=p; } main() { int a,b; int *pointer_1,*pointer_2; cin>>a>>b; pointer_1=&a; pointer_2=&b; if(a<b) swap(pointer_1,pointer_2); cout<<a<<b; …... 2000 2008 200A 2002 2004 2006 200C 200E 2010 ... 整型a 整型b (main) pointer_1 pointer_2 5 地址传递 9 2000 2000 2002 2002 COPY (swap) 指针p1 指针p2 指针p **** 2002 2000 2000 运行结果:5,9 也不能达到预期的结果!

6.3 数组和指针 一维数组和数组元素的地址 一个整数在内存中占两个连续的存储单元,排在前面的那个存储单元的地址就是这个整数的地址;长整数、实数…… 数组元素的地址同上。 数组中的若干个数组元素在内存中是依次连续存放的,占一片连续的内存单元,其中排在前面的那个数组元素的地址就是这个数组的地址。 array[0] array[1] array[2] array[3] array[9] ... 整型指针p &array[0] p 数组名是表示数组首地址的地址常量!

例6.7 数组以及各个数组元素在内存中的地址 void main() 程序运行结果如下(VC): { int i, a[10]; cout<< "index, Address, size:\n" ; for( i = 0; i < 10; i++ ) cout<< " &a[" <<i<< "], " <<&a[i]<<" "<<sizeof( a[i])<<endl ; cout<< "Address of a ="<<a<<endl; cout<< "size of a ="<<sizeof(a)<<endl; } 程序运行结果如下(VC): index, Address, size: &a[ 0 ], 0x12ff54, 4 &a[ 1 ], 0x12ff58, 4 &a[ 2 ], 0x12ff5c, 4 &a[ 3 ], 0x12ff60, 4 &a[ 4 ], 0x12ff64, 4 &a[ 5 ], 0x12ff68, 4 &a[ 6 ], 0x12ff6c, 4 &a[ 7 ], 0x12ff70, 4 &a[ 8 ], 0x12ff74, 4 &a[ 9 ], 0x12ff78, 4 Address of a = 0x12ff54 size of a = 40 在C++语言中,一维数组的任何一个元素的地址,都可以用其数组名加上一个偏移量来表示。 即: &a[i]a+i *&a[i]  a[i]*(a+i)

a[i]  p[i]  *(p+i) *(a+i) 2. 通过指针引用数组元素 int a[10],*p=&a[0]; a[i]  p[i]  *(p+i) *(a+i) a[0] a[1] a[2] a[3] a[9] ... a a+9 a+1 a+2 地址 元素 下标法 a[0] a[1] a[2] a[3] a[9] ... p p+9 p+1 p+2 地址 元素 指针法 *p *(p+1) *(p+2) *(p+9) *a *(a+1) *(a+2) *(a+9) p[0] p[1] p[2] p[9] a=a+1; × a++;× p=p+1; √ p++; √

例 数组元素的引用方法 void main() {int a[5],*pa,i; for(i=0;i<5;i++) a[i]=i+1; 例 数组元素的引用方法 void main() {int a[5],*pa,i; for(i=0;i<5;i++) a[i]=i+1; pa=a; cout<<"*(pa+"<<i<<"):"<<*(pa+i)<<endl; cout<<"*(a+"<<i<<"):"<<*(a+i)<<endl; cout<<"pa["<<i<<"]:"<<<<pa[i]<<endl; cout<<"a["<<i<<"]:"<<a[i]<<endl; } a[0] a[1] a[2] a[3] a[4] pa 1 2 3 4 5

3. 数组名或指针作形参 数组名作函数参数,实参与形参的对应关系 实参 形参 数组名 指针变量

t=x[i]; x[i]=x[j]; x[j]=t; } main() 例 将数组a中的n个整数按相反顺序存放 void inv(int x[], int n) { int t,i,j,m=(n-1)/2; for(i=0;i<=m;i++) { j=n-1-i; t=x[i]; x[i]=x[j]; x[j]=t; } main() { int i,a[10]={3,7,9,11,0,6,7,5,4,2}; inv(a,10); cout<<"The array has been reverted:\n"; for(i=0;i<10;i++) cout<<a[i]; cout<<endl; m=4 i j i j i j i j j i 3 7 9 11 0 6 7 5 4 2 0 1 2 3 4 5 6 7 8 9 2 3 4 7 5 9 11 7 6 1. 实参与形参均用数组

for(;i<=p;i++,j--) { t=*i; *i=*j; *j=t; } } main() 例 将数组a中的n个整数按相反顺序存放 void inv(int *x, int n) { int t,*p,*i,*j,m=(n-1)/2; i=x; j=x+n-1; p=x+m; for(;i<=p;i++,j--) { t=*i; *i=*j; *j=t; } } main() { int i,a[10]={3,7,9,11,0,6,7,5,4,2}; inv(a,10); cout<<"The array has been reverted:\n"; for(i=0;i<10;i++) cout<<a[i]; cout<<endl; } 2. 实参用数组,形参用指针变量

for(;i<=p;i++,j--) { t=*i; *i=*j; *j=t; } } main() 例 将数组a中的n个整数按相反顺序存放 void inv(int *x, int n) { int t,*i,*j,*p,m=(n-1)/2; i=x; j=x+n-1; p=x+m; for(;i<=p;i++,j--) { t=*i; *i=*j; *j=t; } } main() { int i,a[10],*p=a; for(i=0;i<10;i++,p++) cin>>*p; p=a; inv(p,10); cout<<"The array has been reverted:\n"; for(p=a;p<a+10;p++) cout<<*p; } 3. 实参与形参均用指针变量

t=x[i]; x[i]=x[j]; x[j]=t; } main() { int i,a[10],*p=a; 例 将数组a中的n个整数按相反顺序存放 void inv(int x[], int n) { int t,i,j,m=(n-1)/2; for(i=0;i<=m;i++) { j=n-1-i; t=x[i]; x[i]=x[j]; x[j]=t; } main() { int i,a[10],*p=a; for(i=0;i<10;i++,p++) cin>>*p; p=a; inv(p,10); cout<<"The array has been reverted:\n"; for(p=arr;p<arr+10;p++) cout<<*p; 4. 实参用指针变量,形参用数组

一级指针变量与一维数组的关系 int *p 与 int q[10] 数组名是指针(地址)常量 p=q; p+i 是q[i]的地址 则 p[i]  q[i]  *(p+i)  *(q+i) 形参数组实质上是指针变量,即int q[ ]  int *q 在定义指针变量(不是形参)时,不能把int *p 写成int p[]; 系统只给p分配能保存一个指针值的内存区(一般2字节);而给q分配2*10字节的内存区

6.4.5 指针与二维数组 1. 二维数组和数组元素的地址 a a+1 a+2 2000 a[0][0] a[0] 2002 6.4.5 指针与二维数组 1. 二维数组和数组元素的地址 a[0] a[1] a[2] 2000 2008 2016 2002 2010 2018 a[0][0] a[0][1] a[1][0] a[1][1] a[2][0] a[2][1] a[0][2] a[0][3] a[1][2] a[1][3] a[2][2] a[2][3] a a+1 a+2 对二维数组 int a[3][4],有 a-----二维数组的首地址,即第0行的首地址 a+i-----第i行的首地址 a[i]  *(a+i)------第i行第0列的元素地址 a[i]+j  *(a+i)+j -----第i行第j列的元素地址 *(a[i]+j)  *(*(a+i)+j)  a[i][j] a+i=a[i]=*(a+i) =&a[i][0], 值相等,含义不同 a+i 表示第i行首地址,指向行 a[i]  *(a+i)  &a[i][0],表示第i行第0列元素地址,指向列

int a[3][4]; 地址表示: (1) a+1 (2) &a[1][0] (3) a[1] (4) *(a+1) 行指针 列指针 地址表示: (1) &a[1][2] (2) a[1]+2 (3) *(a+1)+2 (4)&a[0][0]+1*4+2 二维数组元素表示形式: (1)a[1][2] (2)*(a[1]+2) (3)*(*(a+1)+2) (4)*(&a[0][0]+1*4+2)

*(a[1]+2),*(*(a+1)+2),a[1][2] 表示形式 含义 地址 a 二维数组名,数组首地址 a[0],*(a+0),*a 第0行第0列元素地址 a+1 第1行首地址 a[1],*(a+1) 第1行第0列元素地址 a[1]+2,*(a+1)+2,&a[1][2] 第1行第2列元素地址 *(a[1]+2),*(*(a+1)+2),a[1][2] 第1行第2列元素值 2000 2008 2012 13

例 用指针变量指向二维数组的数组元素 p main() 例 用指针变量指向二维数组的数组元素 int a[3][4]; a[0][0] a[0][1] a[1][0] a[1][1] a[2][0] a[2][1] a[0][2] a[0][3] a[1][2] a[1][3] a[2][2] a[2][3] p main() {int a[3][4]={1,3,5,7,9,11,13,15,17,19,21,23}; int *p; for(p=a[0];p<a[0]+12;p++) { if((p-a[0])%4==0) cout<<endl; cout<<*p; } p=*a; p=&a[0][0]; p=(int *)a; p=a;

2. 通过建立指针数组和行指针引用二维数组() 2. 通过建立指针数组和行指针引用二维数组() 定义形式: 数据类型 (*指针名)[一维数组的元素个数]; 例 int (*p)[4]; int a[3][4]; a[0][0] a[0][1] a[1][0] a[1][1] a[2][0] a[2][1] a[0][2] a[0][3] a[1][2] a[1][3] a[2][2] a[2][3] a a+1 a+2 p p+1 p+2 ( )不能少 (*p)说明p是一个指针变量! p[0]+1或 *p+1 p[1]+2或 *(p+1)+2 *(*p+1)或 (*p)[1] *(*(p+1)+2) (*p)[4]说明p的值是某个包含4个元素的一维数组的首地址,p是行指针 可让p指向二维数组某一行 如 int a[3][4], (*p)[4]; p=a; p指向的一维数组的元素个数和 二维数组列数必须相同 指针数组: 如 int a[3][4], *q[4]; q[0]=&a[0][0]; q[1]=&a[1][0];

for(p=a,p<a+3;p++) 例 指向一维数组的指针变量(行指针)应用 int a[3][4]; a[0][0] a[0][1] a[1][0] a[1][1] a[2][0] a[2][1] a[0][2] a[0][3] a[1][2] a[1][3] a[2][2] a[2][3] p main() { static int a[3][4]={1,3,5,7,9,11,13,15,17,19,21,23}; int i,j,(*p)[4]; for(p=a,i=0;i<3;i++,p++) for(j=0;j<4;j++) cout<<*(*p+j); cout<<endl; } for(p=a,p<a+3;p++) p  p[0][j] p p=a[0]; p=*a; p=&a[0][0]; p=a;  p=&a[0]; a+3

若int a[3][4]; int (*p1)[4]=a; int *p2=a[0]; 3. 二维数组名或行指针作函数的形参 通过指针引用二维数组的几种形式: 实参 形参 数组名int x[][4] 指针变量int (*q)[4] 指针变量int (*q)[4] 数组名a 指针变量p1 若int a[3][4]; int (*p1)[4]=a; int *p2=a[0]; 指针变量p2 指针变量int *q

例 3个学生各学4门课,计算总平均分,并输出第n个学生成绩 函数说明 void average(float *p,int n) 2019/4/24 例 3个学生各学4门课,计算总平均分,并输出第n个学生成绩 函数说明 void average(float *p,int n) { float *p_end, sum=0,aver; p_end=p+n-1; for(;p<=p_end;p++) sum=sum+(*p); aver=sum/n; cout<<"average=“<<aver; } void search(float (*p)[4], int n) { int i; cout<<" No:“<<n; for(i=0;i<4;i++) cout<<*(*(p+n)+i); main() { void average(float *p,int n); void search(float (*p)[4],int n); float score[3][4]= {{65,67,79,60},{80,87,90,81}, {90,99,100,98}}; average(*score,12); search(score,2); } 列指针 p 行指针 float p[][4] p 65 52 79 60 80 87 90 81 99 100 98 *(*(p+n)+i)  p[n][i]

例 3个学生各学4门课,计算总平均分,并查找一门以上课 不及格学生, 输出其各门课成绩 例 3个学生各学4门课,计算总平均分,并查找一门以上课 不及格学生, 输出其各门课成绩 void search(float (*p)[4], int n) { int i,j,flag; for(j=0;j<n;j++) { flag=0; for(i=0;i<4;i++) if(*(*(p+j)+i)<60) flag=1; if(flag==1) { printf("No.%d is fail,his scores are:\n",j+1); printf("%5.1f ",*(*(p+j)+i)); printf("\n"); } main() { void search(float (*p)[4], int n); float score[3][4]={{...},{...},{...}}; search(score,3); 65 52 79 60 80 87 90 81 99 100 98 p *(*(p+j)+i)  p[j][i]

二维数组与指向一维数组的指针变量的关系 如有: int a[5][10],(*p)[10]; p = a ; p=a+i 使 p指向二维数组的第i行; *(*(p+i)+j)  a[i][j] ; 二维数组形参实际上是一个指向一维数组的指针变量, 即: fun(int x[ ][10])  fun(int (*x)[10]) 在函数fun中两者都可以有x++;x=x+2;等操作! 但在变量定义(不是形参)时,两者不等价;

指针数组与二级指针的关系 int **p 与 int *q[10] 系统只给p分配能保存一个指针值的内存区;而给q分配10个内存区,每个内存区均可保存一个指针值 ; 指针数组名是二级指针常量; p=q; p+i 是q[i]的地址; 指针数组作形参,int *q[ ]与int **q完全等价;但作为变量定义两者不同。

6.4 指针与字符串 1. 字符串表示形式 (1) 用字符数组实现 例 main( ) l o v e C h i string[0] string[1] string[2] string[3] string[4] string[5] string[6] string[7] string[8] string[9] string string[10] string[11] string[12] string[13] n ! a \0 例 main( ) { char string[]=“I love China!”; cout<<string<<endl; cout<<string+7; }

字符指针初始化:把字符串首地址赋给string 相当于以下两个语句: char *string; (2) 用字符指针实现 字符指针初始化:把字符串首地址赋给string 相当于以下两个语句: char *string; string="I love China!"; I l o v e C h i string n ! a \0 例 main( ) { char *string="I love China!"; cout<<string<<endl; string+=7; while(*string) { putchar(string[0]); string++; } string *string!=0 *string

2. 用指向字符串的指针作函数参数 例 字符串复制 void copy_string(char from[],char to[]) 2019/4/24 2. 用指向字符串的指针作函数参数 例 字符串复制 void copy_string(char from[],char to[]) { int i=0; while(from[i]!='\0') { to[i]=from[i]; i++; } to[i]='\0'; main() { char a[]="I am a teacher."; char b[]="You are a student."; cout<<"string_a="<<a<<" string_b="<<b; copy_string(a,b); cout<<"string_a="<<a<<" string_b="<<b;} (1)用字符数组 作参数

(2) 用字符指针变量作参数 例10.19 实现字符串复制 void copy_string(char *from,char *to) 2019/4/24 (2) 用字符指针变量作参数 例10.19 实现字符串复制 void copy_string(char *from,char *to) { for(;*from!='\0';from++,to++) *to=*from; *to='\0'; } void main() { char *a="I am a teacher.123456789"; char b[80]="You are a student."; cout<<"string_a="<<a<<endl; cout<<" string_b="<<b<<endl; copy_string(a,b); 注意:数组b要有足够的存储空间!

3. 字符指针变量与字符数组的分别 char *cp; 与 char str[20]; 字符数组str由若干元素组成,每个元素放一个字符;而指针变量cp中只能存放一个地址值。 char str[20]; str= "I love China!"; () char *cp; cp= "I love China!"; () str是地址常量;cp是地址变量。 cp接受键入字符串时,必须先开辟存储空间。 char str[20]= "……"; () cp++; () str++; () str+1; () 例 char str[10]; cin>>str () 而 char *cp; cin>> cp; () 改为: char *cp,str[10]; cp=str; cin>>cp; ()

4. 字符串与数组的关系 字符串用一维字符数组存放; 一维字符数组中若有一个元素的值为0,则该数组可当字符串用; 字符数组具有一维数组的所有特点; 数组名是指向数组首地址的地址常量; 数组元素的引用方法可用指针法和下标法; 数组名作函数参数是地址传递等; 区别 存储格式:字符串结束标志; 赋值方式与初始化; 输入输出方式:%s %c char str[80]; scanf(“%s”,str); printf(“%s”,str); gets(str); puts(str); char str[]={“Hello!”}; () char str[]=“Hello!”; () char str[]={‘H’,‘e’,‘l’,‘l’,‘o’,‘!’}; () char *cp=“Hello”; () int a[]={1,2,3,4,5}; () int *p={1,2,3,4,5}; () char str[10],*cp; int a[10],*p; str=“Hello”; () cp=“Hello!”; () a={1,2,3,4,5}; () p={1,2,3,4,5}; ()

例 对字符串排序(简单选择排序) 例 对字符串排序 main() 例 对字符串排序(简单选择排序) 例 对字符串排序 main() { void sort(char *name[],int n), print(char *name[],int n); char *name[]={"Follow me","BASIC", "Great Wall","FORTRAN","Computer "}; int n=5; sort(name,n); print(name,n); } void sort(char *name[],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(name[k],name[j])>0) k=j; if(k!=i) { temp=name[i]; name[i]=name[k]; name[k]=temp;} void print(char *name[],int n) { int i=0; char *p; /*p=name[0];*/ while(i<n) { p=*(name+i++); printf("%s\n",p); }

char *name[]={"hello","good","world","bye",""}; p=name+1; 例 用二级指针处理字符串 用*p可输出地址(%o或%x), 也可用它输出字符串(%s) #define NULL 0 void main() { char **p; char *name[]={"hello","good","world","bye",""}; p=name+1; printf("%o : %s ", *p,*p); p+=2; while(**p!=NULL) printf("%s\n",*p++); } *(p++)右结合 运行结果: 644 : good bye

6.7 指针与函数 函数指针:函数被存放在内存中一片连续的存储单元内,其中排在最前面的那个存储单元的地址就是这个函数的地址,也叫函数指针,用函数名表示,它是一个地址常量。 max …... 指令1 指令2 指向函数的指针变量 定义形式: 数据类型 (*指针变量名)(); 如 int (*p)( ); 函数指针变量赋值:如p=max; ( )不能省 int (*p)() 与 int *p()不同 专门存放函数入口地址 可指向返回值类型相同的不同函数 函数返回值的数据类型 函数调用形式: c=max(a,b);  c=(*p)(a,b);  c=p (a,b); 对函数指针变量pn, p++, p--无意义 函数指针变量指向的函数必须有函数说明

1. 用指向函数的指针变量调用函数 main() { int max(int ,int); int a,b,c; scanf("%d,%d",&a,&b); c=max(a,b); printf("a=%d,b=%d,max=%d\n",a,b,c); } int max(int x,int y) { int z; if(x>y) z=x; else z=y; return(z); main() { int max(int ,int), (*p)(); int a,b,c; p=max; scanf("%d,%d",&a,&b); c=(*p)(a,b); printf("a=%d,b=%d,max=%d\n",a,b,c); } int max(int x,int y) { int z; if(x>y) z=x; else z=y; return(z);

2. 用指向函数的指针变量作函数参数 例 用函数指针变量作参数,求最大值、最小值和两数之和 void main() 例 用函数指针变量作参数,求最大值、最小值和两数之和 void main() { int a,b,max(int,int), min(int,int),add(int,int); void process(int,int,int (*fun)()); scanf("%d,%d",&a,&b); process(a,b,max); process(a,b,min); process(a,b,add); } void process(int x,int y,int (*fun)()) { int result; result=(*fun)(x,y); printf("%d\n",result); max(int x,int y) { printf(“max=”); return(x>y?x:y); min(int x,int y) { printf(“min=”); return(x<y?x:y); add(int x,int y) { printf(“sum=”); return(x+y);

3. 返回指针值的函数 函数定义形式: 例 用指针函数实现:有若干学生成绩,要求输入学生序号后,能输出其全部成绩。 2019/4/24 3. 返回指针值的函数 例 用指针函数实现:有若干学生成绩,要求输入学生序号后,能输出其全部成绩。 函数定义形式: 类型标识符 *函数名(参数表); 例 int *f(int x, int y) main() { float score[][4]={{60,70,80,90}, {56,89,67,88},{34,78,90,66}}; float *search(float (*pointer)[4],int n), *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++) printf("%5.2f\t",*(p+i)); } float *search(float (*pointer)[4], int n) { float *pt; pt=*(pointer+n); return(pt); p pointer pointer+1 34 78 90 66 56 89 67 88 60 70 80 score数组

6.6 有关指针操作的小结 1.指针变量是把其它变量的地址作为内容的变量。指针变量的内容可以是0、NULL和一个确定的地址。 2. 地址运算符(&) 返回其操作数的地址。 地址运算符的操作数必须是一个变量(或数组元素)。 3. 指针运算符(*) 又称为“间接引用运算符” ,它表示从相应的存储单元中获取某种类型的数据值。 4. 指针±整数 5. 指针1-指针2 6. 指针的关系运算,如:指针1<指针2 7. 在调用带有参数的函数时,如果调用函数要求被调用函数修改参数的值,应该把参数的地址传递给被调用函数,被调用函数用间接引用运算符(*)修改调用函数中的参数的值。

指针的数据类型 指针的数据类型 定义 含义 int i; 定义整型变量i p为指向整型数据的指针变量 int *p; int a[n]; int *p[n]; int (*p)[n]; int f(); int *p(); int (*p)(); int **p; 定义整型变量i p为指向整型数据的指针变量 定义含n个元素的整型数组a n个指向整型数据的指针变量组成的指针数组p p为指向含n个元素的一维整型数组的指针变量 f为返回整型数的函数 p为返回指针的函数,该指针指向一个整型数据 p为指向函数的指针变量,该函数返回整型数 p为指针变量,它指向一个指向整型数据的指针变量 指针的数据类型

第十章 作业 例 下列定义的含义 (1)int *p[3]; (2)int (*p)[3]; (3)int *p(int); 例 下列定义的含义 (1)int *p[3]; (2)int (*p)[3]; (3)int *p(int); (4)int (*p)(int); (5)int *(*p)(int); (6)int (*p[3])(int); (7)int *(*p[3])(int); 指针数组 指向一维数组的指针 返回指针的函数 指向函数的指针,函数返回int型变量 指向函数的指针,函数返回int 型指针 函数指针数组,函数返回int型变量 函数指针数组,函数返回int型指针 第十章 作业