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

Slides:



Advertisements
Similar presentations
《C语言程序设计》复习
Advertisements

第九章 指针 西安工程大学.
第六章 指针 指针的概念 指针变量 指针与数组 指针与函数 返回指针值的函数.
电子成绩单项目实现.
C语言程序设计教程 单位:德州学院计算机系.
第一章 C语言概述 计算机公共教学部.
第8章 指针 ● 8.1 指针简介 ● 8.2 指针变量的操作 ● 8.3 数组与指针 ● 8.4 二维数组与指针 ●本章小结 ●本章练习.
C语言基础——指针的高级应用 Week 05.
第六节 二维数组和指针 二维数组的地址 对于一维数组: (1)数组名array表示数组的首地址, 即array[0]的地址;
专题研讨课二: 数组在解决复杂问题中的作用
第九章 指针 目录 指针与指针变量的概念 变量的指针和指向变量的指针变量 数组的指针和指向数组的指针变量
第8章 字元與字串處理 8-1 C語言的字元檢查函數 8-2 C語言的字串 8-3 字串的輸入與輸出 8-4 指標與字串
第5章 函数与模块化设计 学习目的与要求: 掌握函数的定义及调用方法 理解并掌握参数的传递方法 理解函数的嵌套与递归调用
复习与总结.
程序设计基础.
第六章 数 组 主讲教师 贾月乐 联系电话:
由C程序结构所知,一个完整的C语言程序是由一个且只能有一个main()函数(又称主函数)和若干个其他函数组合而成的。而前面各章仅学习main()函数的编程,本章将介绍其他函数的编程,包括其他函数的定义、调用、参数传递及变量的作用域等。
選擇排序法 通訊一甲 B 楊穎穆.
目录 10.1 指针的基本概念 10.2 指向变量的指针变量 10.3 指向数组的指针变量 10.4 指向函数的指针变量和指针型函数
项目六 用指针优化学生成绩排名 项目要求 项目分析
C 程式設計— 指標 台大資訊工程學系 資訊系統訓練班.
目录 第八章 数组 1 简单学生成绩管理系统的开发 2 一维数组 3 多维数组 4 字符数组 5 数组作函数参数.
第七章 函数 目录 有参的加法函数的开发 函数定义的一般形式 函数参数和函数的值 函数的调用
第三章 C++中的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章 函数 学习的意义.
6.4.1指针与二维数组 1、二维数组结构的分析 设有数组定义为:int a[3][4]; 则有: a表示数组在内存中的首地址。
第二章 C++对C 在非面向对象方面的改进 更简洁,更安全.
C语言 程序设计基础与试验 刘新国、2012年秋.
第8章 指针.
第八章 使用指针.
谭浩强 编著 中国高等院校计算机基础教育课程体系规划教材 C++程序设计.
第十章 指针.
第六章 指针、引用和动态空间管理 6.1 指针的概念 指针的概念 指针变量的定义和初始化
数组 梁春燕 华电信息管理教研室.
第1章 概述 本章要点: C语言程序结构和特点 C语言程序的基本符号与关键字 C语言程序的编辑及运行 学习方法建议:
六、函数 教学目标: 函数的概念、定义、调用和返回 带自定义函数的程序设计 递推算法 递归思想及算法实现 函数的参数传递方式 C语言程序设计.
第8章 函数 函数参数和函数的值 概述 函数定义的一般形式 函数的调用(嵌套调用、递归调用) 数组作为函数参数
C语言大学实用教程 第5章 函数与程序结构 西南财经大学经济信息工程学院 刘家芬
C语言复习3----指针.
第1章 绪论 北京师范大学 教育技术学院 杨开城.
第一章 程序设计和C语言 主讲人:高晓娟 计算机学院.
C语言程序示例: 1.输入10个数,按从小到大的顺序排序。 2.汉诺塔问题。.
C语言大学实用教程 第6章 数组 西南财经大学经济信息工程学院 刘家芬
函数 概述 模块化程序设计 基本思想:将一个大的程序按功能分割成一些小模块, 特点: 开发方法: 自上向下,逐步分解,分而治之
第八章 指標 (Pointer).
C语言的特点 1. C程序由许多函数组成 2. C程序必须有且只有一个主函数main( ) 3. 函数用“{”和“}”表示起点和终点
第六章 指针 C++程序设计中使用指针可以: 使程序简洁、紧凑、高效 有效地表示复杂的数据结构 动态分配内存 得到多于一个的函数返回值.
7.1 C程序的结构 7.2 作用域和作用域规则 7.3 存储属性和生存期 7.4 变量的初始化
第十四章 若干深入问题和C独有的特性 作业: 函数指针 函数作参数 函数副作用 运算 语句 位段 存储类别 编译预处理
第十章 指针 指针是C语言的重要概念,是C语言的特色,是C语言的精华。 10.1 地址和指针的概念 内存中的每一个字节都有一个地址。
C程序设计.
第一章 C语言概述 教师:周芸.
C语言程序设计 李祥 QQ:
C程序设计.
第九章 指针.
实验七 数 组 第21讲 C程序设计 Main() { int x,y; X=10; y=x*x+1;
C程序设计.
挑戰C++程式語言 ──第9章 函數.
本节内容 指针类型.
Chap 7 数 组 7.1 排序问题 7.2 找出矩阵中最大值所在的位置 7.3 进制转换.
基本資料型態 變數與常數 運算子 基本的資料處理 授課:ANT 日期:2014/03/03.
第六章 复合数据类型 指针的声明与使用 数组的声明与使用 指针与数组的相互引用 字符串及相关库函数 new与delete
本节内容 指针类型 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
C程序设计 复习 1、计算机系统的组成 外部设备:输入、输出设备(同人打交道《十进制》)
C语言基础学习 从外行到入门.
Presentation transcript:

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

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

指针:可根据变量地址找到变量的存储单元,地址起到指示性作用,一个变量的地址称为该变量的指针 地址:内存中每一个字节有一个编号 指针:可根据变量地址找到变量的存储单元,地址起到指示性作用,一个变量的地址称为该变量的指针 指针变量:专门存放变量地址的变量叫~ 指针 …... 2000 2004 2006 2005 整型变量i 10 变量i_pointer 2001 2002 2003 变量的内容 变量的地址 2000 指针变量 指针变量 变量 变量地址(指针) 变量值 指向 地址存入

i_pointer &i &(*i_pointer) i *i_pointer *(&i) &与*运算符 含义 含义: 取变量的地址 单目运算符 优先级: 2 结合性:自右向左 含义: 取指针所指向变量的内容 单目运算符 优先级: 2 结合性:自右向左 两者关系:互为逆运算 理解 2000 10 i_pointer *i_pointer &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 = &i = &(*i_pointer) i = *i_pointer = *(&i) i_pointer-----指针变量,它的内容是地址量 *i_pointer----指针的目标变量,它的内容是数据 &i_pointer---指针变量占用内存的地址

指针变量与其所指向的变量之间的关系 在C程序中用*表示"指向" i *i_pointer  2000 3 &i  i_pointer 则*i_pointer是i_pointer所指向的变量 i *i_pointer  2000 i_pointer *i_pointer 3 i 2000 &i  i_pointer i=3;  *i_pointer=3;

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

10 <例> k=i; k=*i_pointer; <例> k=i; --直接访问 指针变量 …... 2000 2004 2006 2005 整型变量i 10 变量i_pointer 2001 2002 2003 整型变量k 10

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

指针变量的初始化 一般形式:[存储类型] 数据类型 *指针名=初始地址值; <例> int i; int *p=&i; 一般形式:[存储类型] 数据类型 *指针名=初始地址值; <例> int i; int *p=&i; 赋给指针变量, 不是赋给目标变量 变量必须与已说明过的 类型应一致 <例> int i; int *p=&i; int *q=p; <例> int *p=&i; int i; 用已初始化指针变量作初值 <例> main( ) { int i; static int *p=&i; .............. } () 不能用auto变量的地址 去初始化static型指针

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

零指针与空类型指针 p指向地址为0的单元,这意味着,指针并不指向任何地址。 零指针:(空指针) #define NULL 0 定义:指针变量值为零 表示: int * p=0; p指向地址为0的单元,这意味着,指针并不指向任何地址。 #define NULL 0 int *p=NULL: <例> int *p; ...... while(p!=NULL) { ...… } <例>char *p1; void *p2; p1=(char *)p2; p2=(void *)p1; p=NULL与未对p赋值不同 用途: 避免指针变量的非法引用 在程序中常作为状态比较 表示不指定p是指向哪一种 类型数据的指针变量 void *类型指针 表示: void *p; 使用时要进行强制类型转换

<例> 指针的概念 main() { int a; int *pa=&a; 10 a=10; …... f86 f8a f8c f8b 整型变量a 10 指针变量pa f87 f88 f89 运行结果: a:10 *pa:10 &a:f86(hex) pa:f86(hex) &pa:f88(hex) main() { int a; int *pa=&a; a=10; printf("a:%d\n",a); printf("*pa:%d\n",*pa); printf("&a:%x(hex)\n",&a); printf("pa:%x(hex)\n",pa); printf("&pa:%x(hex)\n",&pa); }

<例> 输入两个数,并使其从大到小输出 <例> 输入两个数,并使其从大到小输出 main() { int *p1,*p2,*p,a,b; scanf("%d,%d",&a,&b); p1=&a; p2=&b; if(a<b) { p=p1; p1=p2; p2=p;} printf("a=%d,b=%d\n",a,b); printf("max=%d,min=%d\n",*p1,*p2); } …... 指针变量p1 指针变量p 2000 2008 2002 2004 2006 指针变量p2 整型变量b 整型变量a 2006 2008 2006 2008 2006 5 9 运行结果:a=5,b=9 max=9,min=5

指针变量作为函数参数——地址传递 特点:共享内存,“双向”传递 <例> 将数从大到小输出 swap(int x,int y) 5 …... 2000 2008 200A 2002 2004 2006 变量a 变量b (main) swap(int x,int y) { int temp; temp=x; x=y; y=temp; } main() { int a,b; scanf("%d,%d",&a,&b); if(a<b) swap(a,b); printf("\n%d,%d\n",a,b); 5 5 9 9 变量temp 变量y 变量x (swap) COPY 9 5 5

指针变量作为函数参数——地址传递 特点:共享内存,“双向”传递 <例> 将数从大到小输出 swap(int x,int y) …... 2000 2008 200A 2002 2004 2006 变量a 变量b (main) swap(int x,int y) { int temp; temp=x; x=y; y=temp; } main() { int a,b; scanf("%d,%d",&a,&b); if(a<b) swap(a,b); printf("\n%d,%d\n",a,b); 5 9 值传递 运行结果:5, 9

也可以这样描述: <例> 交互两数。 swap(int x,int y) { int temp; temp=x; x=y; y=temp; } main() { int a,b; a=5;b=9; if(a<b) swap(a,b); printf("\n%d,%d\n",a,b); a 5 5 b 9 9 x 9 y 5 temp 形参、实参是简单变量时,单向值传递

形参、实参是指针变量时,实现“双向”传递 实参本身没有改变,改变的是实参所指向的对象 <例>交换两数。 地址传递 swap(int *q1, int *q2) { int q; q=*q1; *q1=*q2; *q2=q; } main() { int a,b; int *p1,*p2; a=5; b=9; p1=&a; p2=&b; if(a<b)swap(p1,p2); printf("\n%d,%d\n",a,b); p1 a p2 b 5 &a 9 &b 9 5 q2 q1 &a &b 形参、实参是指针变量时,实现“双向”传递 q 5 实参本身没有改变,改变的是实参所指向的对象 运行结果:9,5

改变的是形参本身,并不能影响实参,当然也不能影响实参所指向的对象 <例> 交换两数。 swap(int *q1, int *q2) { int *q; q=q1; q1=q2; q2=q; } main() { int a,b; int *p1,*2; a=5; b=9; p1=&a; p2=&b; if(a<b)swap(p1,p2); printf("\n%d,%d\n",a,b); p2 p1 a b 5 &a &b 9 q2 q1 &b &b &a &a q &a 改变的是形参本身,并不能影响实参,当然也不能影响实参所指向的对象 运行结果:5,9

但是,指针q未赋值,就取*运算,*q=….. <例> 交换两数。 swap(int *q1, int *q2) { int *q; *q=*q1; *q1=*q2; *q2=*q; } main() { int a,b; int *p1,*2; a=5; b=9; p1=&a; p2=&b; if(a<b)swap(p1,p2); printf("\n%d,%d\n",a,b); a p2 p1 b 5 &a 9 &b 9 5 q2 q1 q 但是,指针q未赋值,就取*运算,*q=….. 危险 运行结果:9,5

(1) swap(int *q1, int *q2) { int *q; q=q1; q1=q2; q2=q; } (2) swap(int *q1, int *q2) { int *q; *q=*q1; *q1=*q2; *q2=*q; } 或者更改:int k, *q=&k; main() { int a,b; int *p1,*p2; a=5; b=9; p1=&a; p2=&b; if(a<b)swap(p1,p2); printf("\n%d,%d\n",a,b); } (3) swap(int *q1, int *q2) { int q; q=*q1; *q1=*q2; *q2=q; }

9.3 一维数组与指针 指向数组元素的指针变量 例 int array[10]; int *p; p=&array[0]; // p=array; 或 int *p=&array[0]; 或 int *p=array; array[0] array[1] array[2] array[3] array[9] ... 整型指针p &array[0] p 数组名是表示数组首地址的地址常量

指针的运算 如 int i, *p; p=1000; () i=p; () 指针变量的赋值运算 p=&a; (将变量a地址p) p=array; (将数组array首地址p) p=&array[i]; (将数组元素地址p) p1=p2; (指针变量p2值p1) 不能把一个整数p,也不能把p的值整型变量 指针变量与其指向的变量具有相同数据类型

指针的运算 指针变量的赋值运算 指针的算术运算: 1 <例>int a[10]; int *p1=&a[2]; pi  p id (i为整型数,d为p指向的变量所占字节数) p++, p--, p+i, p-i, p+=i, p-=i等 若p1与p2指向同一数组,p1-p2=两指针间元素个数(p1-p2)/d p1+p2 无意义 a[0] a[1] a[2] a[3] a[4] a[5] a[6] a[7] a[8] a[9] a数组 p p+1,a+1 p+i,a+i p+9,a+9 <例> p指向float数,则 p+1  p+1 4 <例> p指向int型数组,且p=&a[0]; 则p+1 指向a[1] 1 <例> int a[10]; int *p=&a[2]; p++; *p=1; <例>int a[10]; int *p1=&a[2]; int *p2=&a[5]; 则:p2-p1=? 3

指针的运算 指针变量的赋值运算 指针的算术运算 指针变量的关系运算 若p1和p2指向同一数组,则 p1<p2 表示p1指的元素在前 p==NULL或p!=NULL

a[i]  p[i]  *(p+i) *(a+i) 数组元素表示方法 [] 变址运算符 a[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[i]  p[i]  *(p+i) *(a+i)

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

 <例>int a[]={1,2,3,4,5,6,7,8,9,10},*p=a,i; 数组元素地址的正确表示: (A)&(a+1) (B)a++ (C)&p (D)&p[i]  数组名是地址常量 p++,p-- () a++,a-- () a+1, *(a+2) ()

<例>注意指针变量的运算 例 void main() { int a []={5,8,7,6,2,7,3}; int y,*p=&a[1]; y=(*--p)++; printf(“%d ”,y); printf(“%d”,a[0]); } 5 8 7 6 2 3 1 4 a p 6 p 输出:5 6

for(i=0;i<7;i++,p++) printf("%d",*p); } <例> 注意指针的当前值 main() { int i,*p,a[7]; p=a; for(i=0;i<7;i++) scanf("%d",p++); printf("\n"); for(i=0;i<7;i++,p++) printf("%d",*p); } 5 8 7 6 2 3 1 4 a p p p p p p=a; p p p 指针变量可以指到数组后的内存单元

数组名作函数参数 数组名作函数参数,是地址传递 数组名作函数参数,实参与形参的对应关系 实参 形参 数组名 指针变量

<例>将数组a中的n个整数按相反顺序存放 void convert(int x[], int n) { int t,i=0,j=n-1; for(i=0;i<j; i++,j--) { 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}; convert(a,10); printf("reverted:\n"); for(i=0;i<10;i++) printf("%d,",a[i]); printf("\n"); i j i j i j i j j i x 3 7 9 11 0 6 7 5 4 2 0 1 2 3 4 5 6 7 8 9 a 2 3 4 7 5 9 11 7 6 实参与形参均用数组

<例>将数组a中的n个整数按相反顺序存放 void convert(int *p, int n) { int t,*q; for(q=p+n-1; p<q; p++, q--) { t=*p; *p=*q; *q=t; } main() { int i,a[10]={3,7,9,11,0,6,7,5,4,2}; convert(a,10); printf("reverted:\n"); for(i=0;i<10;i++) printf("%d,",a[i]); printf("\n"); 3 7 9 11 6 5 4 2 a[0] a[1] a[2] a[3] a[4] a[5] a[6] a[7] a[8] a[9] p a数组 a q a q 2 3 p q p<q; 4 7 p q 5 9 p q 7 11 p 6 q 实参用数组,形参用指针变量

<例>将数组a中的n个整数按相反顺序存放 void convert(int *p, int n) { int t,*q; for(q=p+n-1; p<q; p++, q--) { t=*p; *p=*q; *q=t; } main() { int i,a[10]={3,7,9,11,0,6,7,5,4,2},*pa=a; convert(pa,10); printf("reverted:\n"); for(i=0;i<10;i++) printf("%d,", *(pa+i)); printf("\n"); } 实参与形参均用指针变量 for( ; pa<a+10; pa++) printf(“%d”, *pa); for(i=0; i<10; i++,pa++) printf(“%d”, *pa); for(i=0; i<10; i++) printf(“%d”, *pa++);

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

9.4 多维数组与指针 对于一维数组: (1)数组名array表示数组的首地址,即array[0]的地址; (2)数组名array是地址常量 (3)array+i是元素array[i]的地址 (4)array[i]  *(array+i) array int array[10];

二维数组理解 a[0] <例> int a[3][4]; a[1] a[2] 1 4 5 2 3 a[0][1] a[0][2] 1 4 5 2 3 a[0][1] a[0][2] a[0][3] a[1][0] a[1][1] a[0][0] a[1][3] a[2][0] a[2][1] a[2][2] a[2][3] a[1][2] 6 7 10 11 8 9 a[0] a[1] a[2] 二维数组a是由3个元素组成 <例> int a[3][4]; 2016 17 2018 19 2020 21 2022 23 2008 9 2010 11 2012 13 2014 15 2000 1 2002 3 2004 5 2006 7 a[0] a[1] a[2] 行名 每个元素a[i]由包含4个元素 的一维数组组成

int a[3][4]; a a+1 a+2 行指针与列指针 *(a[0]+1) *(*(a+0)+1) 2000 2000 a[0] 2008 2016 a a+1 a+2 2000 2002 2008 2010 2016 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[0]+1 a[1]+1 a[2]+1 *(a+0)+1 *(a+1)+1 *(a+2)+1 对于二维数组: (1)a是数组名, 包含三个元素 a[0],a[1],a[2] (2)每个元素a[i] 又是一个一维 数组,包含4个 元素 基类型

int a[3][4]; a a+1 a+2 对二维数组 int a[3][4],有 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) =&a[i][0], 值相等,含义不同 a+i  &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]={1,3,5,7,9,11,13,15,17,19,21,23}; 指向二维数组元素的指针变量——列指针变量 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) printf("\n"); printf("%4d ",*p); } p=*a; p=&a[0][0]; p=*(a+0); p=a;

二维数组的指针变量 p的值是一维数组的 首地址,p是行指针 ( )不能少 int (*p)[4]与int *p[4]不同 指向二维数组元素的指针变量——列指针变量 指向一维数组的指针变量——行指针变量 定义形式: 数据类型 (*指针名)[一维数组维数]; 例 int (*p)[4]; 可让p指向二维数组某一行 如 int a[3][4], (*p)[4]=a; p的值是一维数组的 首地址,p是行指针 ( )不能少 int (*p)[4]与int *p[4]不同 一维数组指针变量维数和 二维数组列数应该相同

a a+1 a+2 p p+1 p+2 p[0]+1或 *p+1 p[1]+2或 *(p+1)+2 *(*p+1)或 (*p)[1] 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[0]+1或 *p+1 p[1]+2或 *(p+1)+2 *(*p+1)或 (*p)[1] *(*(p+1)+2)

p p 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() { 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++) printf("%d ",*(*p+j)); printf("\n"); } p  p[0][j] p p=a[0]; p=*a; p=&a[0][0]; p=&a[0];

printf("%d,%d\n",*((int *)p),*q); <例> 二维数组与指针运算 main() { int a[3][4]={{1,2,3,4},{3,4,5,6},{5,6,7,8}}; int i; int (*p)[4]=a,*q=a[0]; for(i=0;i<3;i++) { if(i==0) (*p)[i+i/2]=*q+1; else p++,++q; } printf("%d,",a[i][i]); printf("%d,%d\n",*((int *)p),*q); p q p q p q 1 2 3 4 5 6 7 8 2 下一节 运行结果:2,4,7,5,3

若int a[3][4]; int (*p1)[4]=a; int *p2=a[0]; 二维数组的指针作函数参数 用指向变量的指针变量 用指向一维数组的指针变量 用二维数组名 实参 形参 数组名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) { float *p_end, sum=0,aver; p_end=p+n-1; for(;p<=p_end;p++) sum=sum+(*p); aver=sum/n; printf("average=%5.2f\n",aver); } void search(float (*p)[4], int n) { int i; printf(" No.%d :\n",n); for(i=0;i<4;i++) printf("%5.2f ",*(*(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]

<例>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]

二维数组与一维数组指针变量的关系 如 int a[5][10] 与 int (*p)[10]; 二维数组名是一个指向有10个元素的一维数组的指针常量 p=a+i 使 p指向二维数组的第i行 *(*(p+i)+j)  a[i][j] 二维数组形参实际上是行指针变量, 即 int p[ ][10]  int (*p)[10] 变量定义(不是形参)时两者不等价 系统只给p分配能保存一个指针值的内存区(一般2字节);而给a分配2*5*10字节的内存区

9.5 字符串与指针 字符串表示形式 用字符数组实现 <例>main( ) 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!”; printf(“%s\n”,string); printf(“%s\n”,string+7); }

字符串表示形式 用字符数组实现 用字符指针实现 字符指针初始化:把字符串首地址赋给string  char *string; l o v e C h i string n ! a \0 字符指针初始化:把字符串首地址赋给string  char *string; string=“I love China!”; <例> main( ) { char *string=“I love China!”; printf(“%s\n”,string); string+=7; while(*string) { putchar(string[0]); string++; } string *string!=0

  注意:其它类型的数组,是不能用数组名来一次性输出它的全部元素的,只能逐个元素输出。 int a[5]={1,2,3,4,5}; printf("%d\n",a); ...... char a[]="good"; char *p=a; printf("%s\n",a); printf("%s\n",p);   下面判断正确的是( )。 A. char *s="girl"; 等价于 char *s; *s="girl"; B. char s[10]={"girl"}; 等价于 char s[10]; s[10]={"girl"}; C. char *s="girl"; 等价于 char *s; s="girl"; D. char s[4]= "boy", t[4]= "boy"; 等价于 char s[4]=t[4]= "boy" C

字符串指针作函数参数 void copy_string(char from[],char to[]) { int i=0; e c h \0 r . from b y u a r s t n d e to o . \0 I a e c h \0 r . t m 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."; printf("string_a=%s\n string_b=%s\n",a,b); copy_string(a,b); printf("\nstring_a=%s\nstring_b=%s\n",a,b); <例>用函数调用实现字符串复制 void copy_string(char *from,char *to) { for(;*from!='\0';from++,to++) *to=*from; *to='\0'; } main() { char *a="I am a teacher."; char *b="You are a student."; printf("string_a=%s\nstring_b=%s\n",a,b); copy_string(a,b); printf("\nstring_a=%s\nstring_b=%s\n",a,b); (1)用字符数组作参数 (2)用字符指针变量作参数

字符指针变量与字符数组 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[10]; scanf(“%s”,str); () 而 char *cp; scanf(“%s”, cp); () 改为: char *cp,str[10]; cp=str; scanf(“%s”,cp); ()

字符串与数组关系 字符串用一维字符数组存放 字符数组具有一维数组的所有特点 数组名是指向数组首地址的地址常量 数组元素的引用方法可用指针法和下标法 数组名作函数参数是地址传递等 区别 存储格式:字符串结束标志 赋值方式与初始化 输入输出方式:%s %c 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}; ()

9.6 函数与指针 函数指针:函数在编译时被分配的入口地址,用函数名表示 指向函数的指针变量 定义形式: 数据类型 (*指针变量名)(); 9.6 函数与指针 函数指针:函数在编译时被分配的入口地址,用函数名表示 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--无意义 函数指针变量指向的函数必须有函数说明

<例>用函数指针变量调用函数,比较两个数大小 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);

返回指针值的函数 返回指针值的函数(简称指针函数)的定义格式如下: 函数类型 *函数名([形参表]) 函数类型 *函数名([形参表]) int *f1(int *x,int *y) { if(*x>*y) return x; else return y; } main() { int a=2,b=3; int *p; p=f1(&a, &b); printf("%d\n",*p); a b p 2 3 2002# ×× 2000# 2002# x 2000# 2002# y 输出:3 <例>写一个函数,求两个int型变量中居于较大值的变量的地址

9.7 指针数组 指针数组 定义:数组中的元素为指针变量 定义形式:[存储类型] 数据类型 *数组名[数组长度说明]; 9.7 指针数组 如果在一个数组中,若其中的所有元素均为指针类 型的数据,则称为指针数组。也就是说,指针数组中的 每一个元素都相当于一个指针变量。 指针数组 定义:数组中的元素为指针变量 定义形式:[存储类型] 数据类型 *数组名[数组长度说明]; 例 int *p[4]; int *p[3]; int a[3]={1,3,5}; 区分int *p[4]与int (*p)[4] 指针所指向变量的数据类型 p[0]=&a[0]; p[0] p[1] p[2] 1 3 5 a[0] a[1] a[2] p[1]=&a[1]; p[2]=&a[2];

&a a &b b p[0] p[1] p[2] p[0] p[1] p[2] main() {int *p[3],a=2,b=3; p[1]=&b; p[2]=NULL; ................ } 2 a &a &b p[0] p[1] p[2] 3 b main() {char *p[]={"Follow", "BASIC", "FORTRAN"}; ....................... } p[0] p[1] p[2] F o l w \0 B A S I C O R T N p 指针数组

{ int b[2][3],*pb[ ]={b[0],b[1]}; …….. } 指针数组赋值与初始化 赋值: main() { int b[2][3],*pb[2]; pb[0]=b[0]; pb[1]=b[1]; …….. } int *pb[2] pb[0] pb[1] int b[2][3] 1 2 3 4 6 初始化: main() { int b[2][3],*pb[ ]={b[0],b[1]}; …….. } int *pb[2] pb[0] pb[1] int b[2][3] 1 2 3 4 6

p[0]=a; p[1]=b; p[2]=c; p[3]=NULL; …….. } 或: { char *p[4]; 指针数组赋值与初始化 L i s p \0 F o r t r a n \0 B a s i c \0 p[0] p[1] p[2] p[3] 赋值: main() { char a[]="Fortran"; char b[]="Lisp"; char c[]="Basic"; char *p[4]; p[0]=a; p[1]=b; p[2]=c; p[3]=NULL; …….. } 或: { char *p[4]; p[0]= "Fortran"; p[1]= "Lisp"; p[2]= "Basic"; p[3]=NULL; 初始化: main() { char *p[]={"Fortran", "Lisp", "Basic",NULL}; …….. } L i s p \0 F o r t r a n \0 B a s i c \0 p[0] p[1] p[2] p[3]

printf(“%c”, *p[i]); printf(“%s\n”, p[i]); main() { int i; char *p[4]={“aa”, “bbb”, “c”, “dddd” }; for(i=0;i<4;i++) } printf(“%c”, *p[i]); printf(“%s\n”, p[i]); p[0] p[1] p[2] p[3] a \0 aa b \0 bbb c \0 c dddd a b c d d \0

二维数组与指针数组区别: 指针数组元素的作用相当于二维数组的行名 二维数组存储空间固定 但指针数组中元素是指针变量 char name[5][9]={“gain”,“much”,“stronger”, “point”,“bye”}; g a i n \0 s t r o n g e r \0 p o i n t \0 m u c h \0 b y e \0 g a i n \0 s t r o n g e r \0 p o i n t \0 m u c h \0 name[0] name[1] name[2] name[3] name[4] b y e \0 char *name[5]={“gain”,“much”,“stronger”, “point”,“bye”}; 二维数组存储空间固定 字符指针数组相当于可变列长的二维数组 分配内存单元=数组维数*2+各字符串长度 指针数组元素的作用相当于二维数组的行名 但指针数组中元素是指针变量 二维数组的行名是地址常量

<例>对字符串排序(简单选择排序) 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;} name[0] name[1] name[2] name[3] name[4] name Great Wall FORTRAN Computer Follow me BASIC k k j j j j i=0

<例>对字符串排序(简单选择排序) 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;} name name[0] Follow me k name[1] BASIC j name[2] Great Wall k j name[3] FORTRAN k j name[4] Computer i=1

<例>对字符串排序(简单选择排序) 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;} name name[0] Follow me name[1] BASIC k name[2] Great Wall k j name[3] FORTRAN j name[4] Computer i=2

<例>对字符串排序(简单选择排序) 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;} name name[0] Follow me name[1] BASIC name[2] Great Wall k name[3] FORTRAN k j name[4] Computer i=3

<例>对字符串排序(简单选择排序) 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;} name name[0] Follow me name[1] BASIC name[2] Great Wall name[3] FORTRAN name[4] Computer

C:\TC> copy[.exe] source.c temp.c 指针数组作main函数的参数 命令行:在操作系统状态下,为执行某个程序而键入的一行字符 命令行一般形式:命令名 参数1 参数2………参数n C:\TC> copy[.exe] source.c temp.c 带参数的main函数形式: 有3个字符串参数的命令行 main(int argc, char *argv[]) { ……… } 命令行实参 main(形参) 系统自动调用 main函数时传递 命令行参数传递 元素指向命令行参数 中各字符串首地址 形参名任意 命令行中参数个数 第一个参数: main所在的可执行文件名

main(int argc, char *argv[]) { while(argc-->0) <例> 输出命令行参数 main(int argc, char *argv[]) { while(argc-->0) printf("%s\n",*argv++); } /*test.c*/ main(int argc, char *argv[]) { while(argc>1) { ++argv; printf("%s\n",*argv); --argc; } argv[0] argv[1] argv[2] char *argv[] world test hello argv argc=3 1. 编译、链接test.c,生成可执行文件test.exe 2. 在DOS状态下运行(test.exe所在路径下) 例如: C:\TC> test[.exe] hello world! 运行结果:hello world! 运行结果:test hello world!

9.8多级指针 定义: 指向指针的指针 一级指针:指针变量中存放目标变量的地址 <例>int *p; int i=3; 单级间接寻址 二级指针:指针变量中存放一级指针变量的地址 <例> int **p1; int *p2; int i=3; p2=&i; p1=&p2; **p1=5; p1 &p2 &i 3 P2(指针变量) i(整型变量) 二级指针 一级指针 目标变量 二级间接寻址

定义形式:[存储类型] 数据类型 **指针名; 定义形式:[存储类型] 数据类型 **指针名; 如 char **p; *p是p间接指向对象的地址 **p是p间接指向对象的值 指针本身的存储类型 最终目标变量的数据类型 <例> int i=3; int *p1; int **p2; p1=&i; p2=&p1; **p=5; i p1 p2 3 &i &p1 **p2, *p1 *p2 <例>int i, **p; p=&i; ()//p是二级指针,不能用变量地址为其赋值 多级指针 例 三级指针 int ***p; 四级指针 char ****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++); } name[0] name[1] name[2] name[3] name[4] char *name[5] world bye \0 hello good name p *(p++) p 运行结果: 644 : good bye

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

指针的数据类型 定义 含义 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); (4)int (*p)(int); (5)int *(*p)(int); (6)int (*p[3])(int); (7)int *(*p[3])(int); 指针数组 指向一维数组的指针 返回指针的函数 指向函数的指针,函数返回int型变量 指向函数的指针,函数返回int 型指针 函数指针数组,函数返回int型变量 函数指针数组,函数返回int型指针