大学课件语言大一上第5章_第1页
大学课件语言大一上第5章_第2页
大学课件语言大一上第5章_第3页
大学课件语言大一上第5章_第4页
大学课件语言大一上第5章_第5页
已阅读5页,还剩61页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、2022-3-51C语言程序设计 2022-3-52第五章 一级指针与一维数组主讲主讲: : 计算机学院计算机学院 吴敏吴敏天使与魔鬼的化身指针 指针: 铁杆C/C+程序员最挚爱的武器 指针造就了C/C+的高效和强大,很多不可能的任务由指针完成 黑客攻击服务器利用的bug绝大部分都是指针和数组造成的这 “该程序执行了非法操作,即将关闭”种错误几乎全是由指针和数组导致的2010年5月10日星期一内存地址内存:计算机内的存储部件,活动中程序指令和数据都保存在内存中速度快、但是掉电即失内存中的每个字节都有唯一的一个地址, 地址是一个无符号整数(通常用16进制数)只要指明要访问的内存单元的地址,就可以

2、立即访问到该单元可以认为:地址和指针是同义词,变量的指针就是变量的地址2010年5月10日星期一指针的故事 地下工作者阮小二接到上级指令,要去寻找打开密电码的密钥,这是一个整数。几经周折,才探知如下线索,密钥藏在一栋三年前就被贴上封条的小楼中。一个风雨交加的夜晚,阮小二潜入了小楼,房间很多,不知该进哪一间,正在一筹莫展之际,忽然走廊上的电话铃声响起。阮小二抓起听筒,只听一个陌生人说:“去打开211房间,那里有线索”。阮小二疾步上楼,打开211房门,用电筒一照,桌上隐约显现:1000。阮小二眼睛一亮,迅速找到1000房间,取出重要数据66,完成了任务。2010年5月10日星期一故事说明重要数据藏

3、在一个内存地址单元中,地址是1000。地址1000又由另一单元P所指认,P单元的地址为211。66的直接地址是1000;66的间接地址是211,因为211单元中存的是直接地址1000。我们称P为指针变量,1000是指针变量的值,实际上是有用数据藏在地址为1000的存储器中。. .10002116610002010年5月10日星期一指针的概念 指针变量:用来存放另一变量地址的变量(内存地址),简称指针 指针是对一种特殊变量的称呼,其特殊性表现在类型(运算)和值上。变量数组字符串函数指针常量2010年5月10日星期一指针既然是变量,所以也具有变量的三个要素:变量的名称。命名规则与一般变量一样,是由

4、英文字符或下划线开始的。变量的类型。“X型指针”、“指向X类型的指针”。变量的值。有特殊含义-是某个内存地址。指针定义类型 *标识符int *pi, *pc;2010年5月10日星期一这里的&是取地址运算符,&i表示取变量i的地址int *pi = &i;表示定义一个指向int型的指针变量pi,并用i的地址来初始化pipi是变量, int *是类型变量占用内存空间,pi的大小是sizeof(int *)指针所指变量int i = 0;int *pi = &i;char c =a;char *pc = &c;c:97i:0.pc:0 x804a0024pi

5、:0 x804a00200 x804a00240 x804a00200 x804a00140 x804a00102010年5月10日星期一示例#include /*演示指针的定义*/int main( ) int i=0;char c=a; int*pi; char *pc;pi = &i;pc = &c;printf(变量t内容tt地址n);printf(-n);printf(it%dtt%pn,i, &i);printf(ct%ctt%pn,c, &c);printf(pit%pt%pn,pi, &pi);printf(pct%pt%pn,pc, &

6、amp;pc);printf(-n);printf(pi=%dtpc=%cn, *pi, *pc);return 0; pointer1.c2010年5月10日星期一NULL是一个等于0的常量,在头文件stddef.h中定义, 它是唯一的一个允许直接赋值给指针的整数值空指针int *p = NULL; 表示指针不指向任何内存地址 防止其指向任何未知的内存区域 把指针初始化为 NULL 是好习惯, 可以避免产生难以预料的错误发生2010年5月10日星期一指针的作用与意义 指针的最根本意义在于:使程序可以通过地址访问数据和函数。2010年5月10日星期一关于指针的原则 学习原则 一定要学会 其实通

7、常的应用很简单,就是一个变量 复杂的应用也不建议使用 使用原则 永远要清楚每个指针指向了哪里 远要清楚指针指向的位置是什么2010年5月10日星期一指针运算2010年5月10日星期一取地址运算符& &运算符用来取被操纵对象的地址 例如: &x表示变量x在内存的存放地址,若x的地址0 xbfff0010, 则&x的值就是0 xbfff0010。 &的优先级是14。2010年5月10日星期一取值运算符* *运算访问指针所指变量。 例如: x=*p是将指针p所指变量的值赋给x *p=5是将5送入指针p所指变量中 *的优先级也为142010年5月10日星期一&a

8、mp; 与 * 的关系#include /*演示指针的定义*/int main( )int * p = NULL;int i = 0;int a5=0,0,0,0,0;p = &i;*p = 1;printf(i = %dn, i);p = a;*p = 2;printf(a0 = %dn, a0);p = &a0;*p = 3;printf(a0 = %dn, a0);p = &a4;*p = 4;printf(a4 = %dn, a4);return 0; &和*互为逆运算 &是取地址运算符,操作对象是变量,&运算的结果指向该变量的指针 *是

9、取值运算符,操作对象是地址,*运算访问地址表达式所指变量pointer2.c2010年5月10日星期一 指针变量中只能存放地址,因此,在使用中不要将一个整数赋给一指针变量指针赋值#include /*演示指针的赋值*/int main( ) int a = 66; int *p=NULL; int *q=NULL; p = a; q = 66; p = &a; /将变量 a 的地址赋给 p q = p; / 将 p 的值赋给 q printf(%d %d %dn, a, *p, *q); return 0;pointer3.c2010年5月10日星期一如果已执行了语句 pointer_

10、;对对“”和和“* *”运算符说明:运算符说明:n存在的存在的等价关系:等价关系: n(1 1)pointer_1= =&a; pointer_1= =&a; n(2 2) * * pointer_1pointer_1 =a ; =a ; n(3 3)& &* * pointer_1 pointer_1 = pointer_1 ; = pointer_1 ; n(4 4) * *& pointer_1& pointer_1 = pointer_1 = pointer_1 n(5 5) * *&a=a&a=an但是:但是:&

11、 &* *a=a; a=a; 却是错误的,却是错误的,因为因为a a不代表地址,所以不代表地址,所以* *a a无意义无意义。int i,*p;p=&i; int *p;float *q;p=q;int i;float *p;p=&i;int *p;p=100;指针变量只指针变量只存放地址存放地址!一个指针变量不能一个指针变量不能指向与其类型不同指向与其类型不同的变量的变量!我是真的,我是真的,你猜对了吗?你猜对了吗?应在类型相应在类型相同的指针变同的指针变量之间赋值量之间赋值指针运算法则 只能进行加减和关系运算 +、- =!= 只能同类型指针之间或指针与整数之间运算2

12、010年5月10日星期一数组下标范围数组下标范围0-0-4 4 C语言为这些数据,提供了一种构造数据类型:语言为这些数据,提供了一种构造数据类型:数组。所谓数组。所谓数组就是一组具有相同数据类型的数据数组就是一组具有相同数据类型的数据的有序集合。的有序集合。n一个班学生的学习成绩一个班学生的学习成绩n一行文字一行文字n一个矩阵一个矩阵这些数据的特点是:这些数据的特点是:- -批量处理数据批量处理数据1.1.具有相同的数据类型具有相同的数据类型2.2.使用过程中需要保留原始数据使用过程中需要保留原始数据一维数组11年4月6日星期三注意:表达式表示数组元素的个数,下标从0开始C89中表达式必须是常

13、数,不允许为常量或变量(VC6, VS2005)C99中允许表达式为常量或变量,即支持动态数组 (gcc4, dev-cpp)一维数组声明类型 数组名表达式int a10;/* 定义包含10个整数元素的数组 */#define NUM 10int arrayNUM;int count = 0;scanf(%d, &count);int bcount;11年4月6日星期三0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000定义数组就是定义了一块连续的空间,数组元素按

14、序存放在这块空间中。数组名字是数组首元素的内存地址。注意数组名是一个常量,不能被赋值。空间的大小等于元素数*每个元素所占的空间大小,如定义int a10,将占用了40个字节空间,aa0a1a2数组的本质1 Byte= 8 bit因为每个整型数占4个字节。11年4月6日星期三火眼金睛看一看#include #define NUM 10/* 演示一维数组元素存储和访问 */int main() int aNUM; int i; for(i=0; iNUM; i+) ai=i; printf(变量t地址tt内容n); printf(-n); for(i=0; iNUM; i+) printf(a%d

15、t%pt%dn,i, &ai, ai); printf(-n); printf(at%pt%dn, a, *a);access.c return 0;11年4月6日星期三一维数组的初始化直接在定义时初始化定义后通过循环完成赋值11年4月6日星期三直接在定义时初始化 声明数组时可以对数组初始化 初始化表的长度短于要被初始化的数组元素数目,那么剩余元素被初始化为0 带有初始化的数组可以不定义长度,如:int x5 = 2,3,5,1,4;int x5 = 2,3;int x = 2,3,5,1,4;11年4月6日星期三示例#include /*演示直接在定义的时候初始化*/int main

16、()int x5=2,3,5,1,4;int i =0;for(i=0; i5; i+)printf(%d ,xi); return 0;init1.c 11年4月6日星期三请点评#include int main()int i;int x5;x5 = 2,3,5,1;for(i=0; i5; i+)printf(%d ,xi); return 0;init2.c 11年4月6日星期三数组赋值问题不允许对数组进行整体赋值操作,只能使用循环逐一复制元素int a8, b8;a = b; 例:将数组a和数组b的差送入数组c中,实现方法如下:c = a - b;for(i=0; i8; i+) ci

17、 = ai - bi;11年4月6日星期三#includeInt main()int i;int x5;for(i=0; i5; i+)scanf(%d ,&xi);return return 0 0; ; init2.c定义后通过循环完成赋值数组的输入和输出 数组输入int array3; int i;for(i = 0; i 3; i+) scanf(%d, &arrayi);int array3;int i; scanf(%d %d %d, &array); 数组输出int array3;int i; for(i = 0; i 3; i+)printf(%d, a

18、rrayi); int array3;int i; printf(%d, array); 11年4月6日星期三数据下标越界问题 C语言不检查数组下标的越界。如果定义数组 int a10,合法的下标范围是0 9,但如果你引用a10,系统不会报错,但是程序非常容易出现异常 解决方法:程序员在对下标变量进行操作前,仔细检查下标的合法性11年4月6日星期三请点评#include int main()int i;int a3 = 111, 222, 333;for (i = 1; i = 3; i+) ai = 0; printf(%dn, ai);return(0);overflow.c11年4月6日

19、星期三指针与数组2010年5月10日星期一指针与数组 指针与数组有着密切的关系 数组名是数组的首地址,指针值也是一个地址则p与a表示 如果指针指向数组的首地址,例p指向a0,的是同一个对象 事实上,在C中把数组名可以看作常量指针 指针也可当作数组名使用2010年5月10日星期一指针与数组等价之处 注意: ai,pi, *(a+i), *(p+i)等价#include /*演示指针标识数组*/int main( ) int i=0; int *p = NULL; int a5=0,1,2,3,4; p = a; for(i=0; i5; i+) printf(a%d = %d %d %d %dn

20、, i, ai, pi, *(a+i), *(p+i); pointer4.c return 0;2010年5月10日星期一表表5.2 5.2 数组元素及元素地址的表示(数组元素及元素地址的表示(数组定义:数组定义:int a5;int a5;)表示表示 意义意义 等价表示等价表示 a a 数组第一个元素的地址,是指针常量数组第一个元素的地址,是指针常量 &a0&a0a+i(0i4) a+i(0i4) 第第i+1i+1个元素的地址,是指针常量表个元素的地址,是指针常量表达式,不可被修改达式,不可被修改 &ai &ai &ai(0i4)&ai(0i

21、4)a+i a+i * *(a+i)(0i4)(a+i)(0i4) 第第i+1i+1个元素的间接引用表达,是基个元素的间接引用表达,是基类型的变量类型的变量 ai ai ai(0i4)ai(0i4)第第i+1i+1个元素的下标(索引)表达,个元素的下标(索引)表达,是基类型的变量是基类型的变量 * *(a+i) (a+i) 总结:总结:一维数组元素的一维数组元素的地址地址有两种等价表示:有两种等价表示:a+i= =&aia+i= =&ai;一维;一维数组数组元素元素有两种等价表示:有两种等价表示:* *(a+i)= ai(a+i)= ain1 1、只在、只在sizeofsize

22、of(数组名)和(数组名)和& &数组名这两种表达式的时数组名这两种表达式的时候表示候表示“数组数组”这个整体概念这个整体概念, ,n2 2、表示该数组的位置,即数组第一个元素的地址,此、表示该数组的位置,即数组第一个元素的地址,此时时a a的值等于的值等于a0a0这个元素的物理地址,此时这个元素的物理地址,此时a+ia+i的数值的数值等于等于aiai这个元素的物理地址,这个元素的物理地址,* *(a+i)(a+i)表示表示aiai这个元这个元素的间接表示方法,如下图示意:素的间接表示方法,如下图示意:指针与数组不同之处 指针是一个变量 数组名不是一个变量,是一个常量指针 定义

23、数组分配空间由类型和下标决定,定义指针仅仅分配指针类型空间int *p;int a=1,2,3;a = p;a+;int *p;int a=1,2,3;p = a;p+;2010年5月10日星期一n从键盘上输入从键盘上输入1010个整数,输出这些元素及其中正数和负个整数,输出这些元素及其中正数和负数的个数(请用数组实现)数的个数(请用数组实现)#include #include int main()int main() int a10,i; int a10,i; int positive=0,negative=0; int positive=0,negative=0; printf(Pleas

24、e input 10 elements:n);printf(Please input 10 elements:n);for (i=0;i10;i+) for (i=0;i10;i+) scanf(%d,&ai); scanf(%d,&ai); for (i=0;i10;i+)for (i=0;i0) positive+; if(ai0) positive+; else if (ai0) negative+ ;else if (ai0) negative+ ;for (i=0;i10;i+) for (i=0;i10;i+) printf(%d,ai);printf(%d,ai)

25、;printf(n positive number are %d,negative number are printf(n positive number are %d,negative number are %dn,positive,negative);%dn,positive,negative);return 0;return 0; n程序程序5.35.3从键盘上输入从键盘上输入n(1n10)n(1n10)个整数,求出最大值个整数,求出最大值n思路思路:(1 1)首先需要定义数组以存储)首先需要定义数组以存储n n个整数,再用一层循环输出元素值个整数,再用一层循环输出元素值(2 2)然后用

26、一层循环作统计、找最大值)然后用一层循环作统计、找最大值(3 3)最后输出结果)最后输出结果 #include #include int main()int main() int a10,i,n; int a10,i,n; int max; int max; dodo printf(Please input n(1=n=10):n);printf(Please input n(1=n=10):n);scanf(%d,&n);scanf(%d,&n);while (n10);while (n10);printf(Please input %d elements:n,n);prin

27、tf(Please input %d elements:n,n);for (i=0;in;i+) for (i=0;in;i+) max=a0 ;max=a0 ; for (i=1;in; i+) for (i=1;imax) max=(a+i)max) max=* *(a+i);(a+i); printf(max element=%dn,max);printf(max element=%dn,max);return 0;return 0; 数组首元素地址可以传给?数组首元素地址可以传给?基类型相同的指针变量基类型相同的指针变量地址传递地址传递 例:例:int a5;int a5; int i

28、nt * *p=a;p=a;注意:注意: p p是变量,是变量,也可以获得任意元素的地址值,也可以获得任意元素的地址值,例:例:p=&a2 p=&a2 此时此时:p0:p0等价于等价于* *p p或或a2a2, p2p2等价于等价于* *(P+2)P+2)或或a2a2 a0a1a2a3a3a4a413ff58app0p1p2p3p3p4p413ff58n当当p=ap=a后,有下列等价关系存在:后,有下列等价关系存在:n(1)(1)数组元素的表示:数组元素的表示:n 下标法:下标法:pi pi 、aiain 间接引用法:间接引用法:* *(p+i) (p+i) 、* *(a+i)

29、(a+i)n(2)(2)数组元素地址的表示数组元素地址的表示: :n 指针表达式法:指针表达式法:p+ip+i、a+i a+i n 元素取地址法:元素取地址法:&pi&pi、&ai&ain程序程序5.5:5.5:用一级指针访问一维数组元素示例用一级指针访问一维数组元素示例 a0a1a2a3a3a4a413ff58app0p1p2p3p3p4p413ff5813ff5cp0p1p1p2p2n移动下标与移动指针访问数组的元素例示移动下标与移动指针访问数组的元素例示: :n程序程序5.8 5.8 请将一个初值分别为请将一个初值分别为1 1、2 2、3 3、4 4、5

30、5、7 7、8 8、9 9、1010的整的整形数组形数组逆置存放,并输出逆置后数组元素。逆置存放,并输出逆置后数组元素。 n分析:逆置数组,即从两边向中间对应位置的元素两两分析:逆置数组,即从两边向中间对应位置的元素两两互换互换。n方法一:方法一:采用移动下标法采用移动下标法, ,用用i i和和j j分别指示待交换的两分别指示待交换的两个元素的下标,个元素的下标,i i从从0 0开始递增,开始递增,j j从从9 9开始递减,循环条开始递减,循环条件为件为ijij。n方法二:方法二:采用移动指针法,设两个指针采用移动指针法,设两个指针p p和和q q分别指向第分别指向第一个元素和最后一个元素,一

31、个元素和最后一个元素,交换对应的交换对应的* *p p和和* *q q,然后,然后p+p+同时同时q-q-,循环条件为循环条件为pqpq。n程序程序5.8 5.8 方法一核心代码方法一核心代码nfor (i=0,j=9;ij;i+,j-) nntemp=ai;nai=aj;naj=temp;nn等效于等效于:(只用只用 i 控制下标控制下标)nfor (i=0;i10/2;i+) ntemp=ai;nai=a10-1-i;na10-1-i=temp;n n程序程序5.8 5.8 方法二核心代码方法二核心代码nfor (p=a,q=a+9;pq;p+,q-)nntemp=*p;n*p=*q;n*

32、q=temp;nn等效于等效于:(只用只用 p 控制指针变化控制指针变化)nfor (p=a;pa+10/2;p+)ntemp=*p;n*p=*(a+10-1-(p-a);n*(a+10-1-(p-a)=temp;n n程序程序5.9 5.9 从键盘上输入从键盘上输入n(1n10)n(1n10)个整数作为数组个整数作为数组a a的元素值,的元素值,再读入一个待查找的整数再读入一个待查找的整数x x,在,在a a数组中查找数组中查找x x,如果存在输出它,如果存在输出它的下标,否则提示:的下标,否则提示:“Not present!Not present!” n提示:提示:本程序完整的循环条件:本

33、程序完整的循环条件:in&x!=*(p+i) p=a;p=a; / /使使p p回到数组开头回到数组开头while(in)while(in) if (x=if (x=* *(p+i)(p+i)break;break;i+; i+; if(in) if(in) printf(value=%d, index=%dn,x,i);printf(value=%d, index=%dn,x,i);elseelseprintf(Not present!n);printf(Not present!n);n程序程序5.12 5.12 从键盘上输入从键盘上输入n(1n10)n(1n10)个整数,首先输出这些元素,个整数,首先输出这些元素,再用选择法排序,最后输出排序后的元素。再用选择法排序,最后输出排序后的元素。n提示:将数组分为左右两个

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论