




已阅读5页,还剩72页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第十六章指针和数组,指针,指针就是一个如变量之类的存储对象的地址使用指针,可以间接地访问这些对象可以构建一个修改调用者传递的参数的函数可以构建一些复杂的在程序执行过程中可以增长和缩短的数据组织,数组,数组是在存储器中被连续排列的一列数据把一个字符文档表示成在存储器中连续排列的字符序列这些连续排列的字符被称为字符数组允许方便地处理一组数据,诸如向量、矩阵、列表和字符串,这些都自然的表示了现实世界的某些特定的对象,交换两个参数值的Swap函数,intmain()intvalueA=3;intvalueB=4;Swap(valueA,valueB);printf(valueA=%dandvalueB=%dn,valueA,valueB);voidSwap(intfirstVal,intsecondVal)inttempVal;tempVal=firstVal;firstVal=secondVal;secondVal=tempVal;传给Swap的两个变元仍然保留着原来的值,Swap,01Swap:subir29,r29,#402sw0(r29),r16;压入R16(寄存器的保存)0304addir16,r4,#0;tempVal=firstVal;05addir4,r5,#0;firstVal=secondVal;06addir5,r16,#0;secondVal=tempVal;0708lwr16,0(r29);R16出栈09addir29,r29,#40Aret在C中,变元总是以值的形式从调用函数传递到被调用函数,运行时栈,R17,R29,x00000000,xFFFFFFFF,main,R16,Swap,运行时栈,R16,(a),指针变量,指针变量包含了一个存储对象的地址,比如一个变量的地址与指针变量有关的是它所指的对象的类型一个整数指针变量指向一个整数变量声明int*ptr;声明了一个名为ptr的变量,它指向一个整数星号“*”表明后面的标识符是一个指针变量也可以说ptr是int星号类型,地址运算符,符号“,假设声明两个的变量都是局部变量,ptr使用R16保存,object需要被分配到栈中,偏移量为-3,R30,object,4,R16,R30,R31,ptr=,addir8,r0,#4;R8=4sw-12(r30),r8;object=4;subir16,r30,#-12;ptr=,间接运算符,或者解除参照运算符符号是星号“*”允许间接操作一个存储对象里的值表达式“*ptr”指的是被指针变量ptr指向的值intobject;int*ptr;object=4;ptr=,“*ptr”根据它出现在赋值运算符的哪一边来表示不同的意思在赋值运算符的右边,它指的是出现在那个单元中的值(这个例子中是数值4)在赋值运算符的左边,它指明了要作修改的单元(这个例子中是object的地址),*ptr=*ptr+1;,lwr8,0(r16);R8*ptraddir8,r8,#1;*ptr+1sw0(r16),r8;*ptr=*ptr+1;,object=*ptr+1;,lwr8,0(r16);R8*ptraddir8,r8,#1;*ptr+1sw-12(r30),r8;object=*ptr+1;,交换两个参数值的NewSwap函数,intmain()intvalueA=3;intvalueB=4;NewSwap(,NewSwap(,valueA,valueB,R29,x00000000,xFFFFFFFF,main,运行时栈,R16,(b),Swap,NewSwap,01NewSwap:subir29,r29,#402sw0(r29),r16;压入R16(寄存器的保存)0304lwr8,0(r4);*firstVal05addir16,r8,#0;tempVal=*firstVal;06lwr9,0(r5);*secondVal07sw0(r4),r9;*firstVal=*secondVal;08sw0(r5),r16;*secondVal=tempVal;090Alwr16,0(r29);R16出栈0Baddir29,r29,#40Cret,NewSwap,4,3,valueA,valueB,R16,运行时栈,(a),4,4,运行时栈,(b),3,4,运行时栈,(c),x7FFFFFE8,x7FFFFFE4,x7FFFFFEC,R16,R16,按引用传递变元,在NewSwap中,通过使用地址运算符“ptr=NULL;在C中,NULL是一个特别定义的预处理宏,它包含一个没有任何指针可以包含的值,除非指针包含空值例如,在一个特定的系统中,NULL可能等于0,因为没有一个有效的存储对象可以存储在单元0中,函数的返回值,函数的返回值也可以被声明为指针类型int*CmpSwap(int*firstVal,int*secondVal)inttempVal;tempVal=*firstVal;*firstVal=*secondVal;*secondVal=tempVal;if(*firstVal=*secondVal)returnfirstVal;elsereturnsecondVal;,使用指针的例子,编写一个程序:给定一个整数除数与一个整数被除数,计算商与余数难点:通过一个C函数计算商和除数为了给调用函数提供多个值,需要使用指针变量,通过引用机制进行调用,IntDivide,intIntDivide(intx,inty,int*quoPtr,int*remPtr)if(y!=0)*quoPtr=x/y;/*修改商*/*remPtr=x%y;/*修改余数*/return0;elsereturn-1;/*防御性编程实践*/,main,intmain()intdividend;/*被除数*/intdivisor;/*除数*/intquotient;/*商*/intremainder;/*余数*/interror;error=IntDivide(dividend,divisor,数组,当程序运算的数据被自然的表达为一个连续的数值序列时,数组是一种很有用的数据结构因为许多现实世界的数据都属于这个类别(比如某门课程的学生考试成绩)例如,从键盘输入100个数字,并对它们按升序排列数组是对于在存储器中存储这些数字的自然的选择如果使用在这之前用过的简单变量来写这个程序几乎是不可能的,数组的声明,和其他变量一样,数组必须有一个相关的类型这个类型表明了存储在数组里的数值的属性对一个包含10个整数的数组的声明:intx10;关键词int表明声明的是整数类型的事物数组的名称是x中括号表明声明的是一个数组,10则表示这个数组包含10个将被按顺序放在存储器中的整数,数组x在存储器中的分配,第一个元素x0被分配在最低的存储地址,而最后一个元素x9在最高的地址如果数组x是一个局域变量,那么它的存储空间将被分配于运行时栈中,访问数组中不同的值,数组的第一个元素实际上编号为0为了访问某一特定元素,采用在中括号中提供下标的方式,例如:x5=x0+1;运算符,DLX代码,假设x是分配在运行时栈中的唯一的局域变量,且x0相对于栈底指针R30的偏移量为12subir8,r30,#48;将x的基址给R8lwr9,0(r8);R9x0addir9,r9,#1;R9x0+1sw20(r8),r9;x5=x0+1;,基址+偏移量,数组的基址通常是数组的第一个元素的地址通过将要访问的元素的下标与元素所占存储单元的数目相乘,结果再与基址相加,访问数组中的任意元素数组的强大功能来自于数组的下标可以是任意的合法的C语言整数表达式这一事实xi+5=xi+1;,DLX代码,假设i被分配给R16subir8,r30,#48;将x的基址给R8sllir9,r16,#2;R9i*4addr9,r8,r9;计算xi的地址lwr10,0(r9);R10xiaddir10,r10,#1;R10xi+1addir9,r16,#5;R9i+5sllir9,r9,#2;R9(i+5)*4addr9,r8,r9;计算xi+5的地址sw0(r9),r10;xi+5=xi+1;,示例1,每个学生的总评成绩=“exam110%+exam230%+exam360%”假设该门课程有50个学生修读,#include#defineNUM_STUDENTS50intmain()inti;intexam1NUM_STUDENTS;intexam2NUM_STUDENTS;intexam3NUM_STUDENTS;inttotalNUM_STUDENTS;/*输入平时成绩*/for(i=0;iNUM_STUDENTS;i+)printf(Inputexam1scoreforstudent%d:,i);scanf(%d,/*输入期中考试成绩*/for(i=0;iNUM_STUDENTS;i+)printf(Inputexam2scoreforstudent%d:,i);scanf(%d,/*计算总评成绩*/for(i=0;iNUM_STUDENTS;i+)totali=exam1i*0.1+exam2i*0.3+exam3i*0.6;/*输出总评成绩*/for(i=0;iNUM_STUDENTS;i+)printf(Totalscoreforstudent%d=%dn,i,totali);,编程风格,对于数组的大小,使用预处理宏是好的程序设计实践如果想增加数组的大小,例如学生修读人数发生变化,只需改变宏的定义(改变一处),并重新编译该程序即可如果不使用宏,那么改变数组的大小就需要在很多处修改代码这些改变可能很难跟踪,忘记某一处都可能导致程序无法正确运行,打印杨辉三角形,杨辉三角形如:11112113311464115101051,n=6,#include#defineNUMBER6intmain()inti,n;intaNUMBER;/*当前行的数*/intbNUMBER;/*下一行的数*/a0=1;/*当前行第一个数为1*/b0=1;/*下一行第一个数为1*/,for(n=1;n=NUMBER;n+)/*每一行*/for(i=0;iNUMBER-n;i+)/*打印空白*/printf();for(i=0;in;i+)printf(%2d,ai);/*打印ai*/*“%2d”表示整数占两位,如果不足两位,则左边补空格*/printf(n);,if(nNUMBER)/*计算下一行*/for(i=1;i=n;i+)if(i=n)bi=1;/*每行最后一个数为1*/elsebi=ai-1+ai;/*上一行相邻两数之和*/for(i=0;i=0?,s=-s,否,是,参数:顶点坐标,返回值:面积,初始化循环计数器i,面积,是,否,i=0)returns;elsereturn-s;,main,intmain()intn;/*N*/doublexaMAX_NUMS;/*多边形各顶点x坐标*/doubleyaMAX_NUMS;/*多边形各顶点y坐标*/doublex3;/*三角形各顶点x坐标*/doubley3;/*三角形各顶点y坐标*/doublearea=0.0;/*面积*/inti,j;/*输入N及各顶点坐标*/printf(Enterthesidesnumberofpolygon(=%d):,MAX_NUMS);scanf(%d,for(i=0;in;i+)printf(EnterthecoordinatesofvertexA%d:,i+1);scanf(%lf%lf,数组的名字,在C语言中,一个数组的名字指的是数组的基址名字x等价于声明一个最多可以存储10个字符的数组字符串的结尾用ASCII码值为0的空字符标记它是标识字符串结尾的一个标记0是对应于空字符的特殊序列,赋值,word0=H;word1=e;word2=l;word3=l;word4=o;word5=0;数组将包含字符串“Hello”注意字符串尾部的字符本身也是占用一个数组元素的字符比九个字符长的字符串不能被存储在这个数组中,%s,printf(%s,word);“%s”,这个说明从对应的参数所指的字符开始,以字符串末尾字符0结尾,打印出一个字符串,在声明时初始化,charword10=Hello;printf(%s,word);注意两点:第一,字符串使用双引号“”与单个字符区分开来(单引号用于单个字符,像A)第二,注意,编译器会在字符串的末尾自动加上一个空字符,计算字符串长度,#include#defineMAX_STRING20intStringLength(charstring);intmain()charinputMAX_STRING;intlength=0;printf(Inputaword(lessthan20characters):);scanf(%s,input);length=StringLength(input);printf(Thewordcontains%dcharactersn,length);,intStringLength(charstring)intindex=0;while(stringindex!=0)index=index+1;returnindex;,scanf(%s,input);,“%s”,从输入流中扫描一个字符串它将从一个非空白符开始,到下一个空白字符之间的所有字符,存储于以地址input开始的存储器中一个0字符被自动的添加进来以表明字符串的结束由于参数input是一个数组,它自动的通过引用传递,也就是说,数组第一个元素的地址被传给scanf,%s,所以如果用户输入:Dontforget.只有Dont被存进数组input中文本行中余下的被保留,用于后面的scanf来读入所以如果再执行一个“scanf(%s,input);”,单词forget会被存入数组input中注意:空白是被说明%s自动丢弃的,如果单词长度超过20个字符,注意单词最大长度是20个字符,那么如果第一个词更长一些会发生什么呢?函数scanf并不会检验数组input的大小,而是把字符存储进它提供的数组地址中,直到遇到空白为止如果第一个词长度超过20个字符,被分配在main函数中的数组input后面的单元内容将会被改写,比较两个字符串,intStrCmp(char*firstStr,char*secondStr)inti=0;intres;while(!(res=firstStri-secondStri),string.h,C的标准库提供了很多关于字符数组的预先写好的函数复制字符串结合字符串比较字符串计算字符串长度对这些函数的声明可以通过头文件被包含进来,数组与指针之间的关系,charword10;char*cptr;cptr=word;可以通过使用“word3”或“*(cptr+3)”访问字符串中的第四个字符,区别,cptr是一个变量,从而可以被重新赋值而另一个数组标识符word不能被重新赋值,问题求解:冒泡排序,将一个整数数组按升序排列算法思想:依次比较相邻的两个数,将小数放在前面,大数放在后面即首先比较第1个和第2个数,将小数放在前面,大数放在后面。然后比较第2个数和第3个数,将小数放在前面,大数放在后面,如此继续,直至比较完最后两个数。这样,第一趟比较结束后,最大的一个数就被交换到最后。然后再重复以上过程,仍从第一对数开始比较,将小数放在前面,大数放在后面,一直比较到最大数前的一对相邻数,第二趟结束,在倒数第二个数中得到一个新的最大数如此下去,直至最后仅需比较第一个数和第二个数,就可完成排序因此,总趟数应为需要排序的数的个数减1,由于在排序过程中总是小数往前放,大数往后放,就像水中的气泡往上冒的情景,所以称作冒泡排序对此算法进行系统分解,可以看到程序的核心包括对数组的相邻元素进行比较和交换这个过程将重复进行,直到没有需要比较的相邻元素为止,BubbleSort,voidBubbleSort(intlist)inti,j;inttemp;for(j=1;jlisti+1)temp=listi;listi=listi+1;listi+1=temp;,数组的常见错误,C语言不提供防止超出数组大小(或边界)的保护措施这是C语言程序设计用到数组时常见的一个错误编译器盲目的为表达式“ai”生成代码,即使下标i访问了一个超出数组尾部的存储单元,防御性编程,为了防止类似问题的出现,在使用数组时,有经验的C程序员通常会使用一些特殊的防御性编程技术:在程序中加入范围检查,以警告数组的大小是否足够,C89,C89规定,数组(特别是像已经见过的静态声明的数组)必须有一个固定的大小当编译程序时,必须知道数组的大小C89不支持使用变量表达式的数组声明,非法的C代码:voidSomeFunction(intnum_elements)inttempnum_elemments;/*生成语法错误*/为了处理这个限制,C程序员仔细分析代码将要被使用的情形,然
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- (正式版)DB15∕T 3404.3-2024 《全民所有自然资源资产清查技术指南 第3部分:森林资源》
- 鲁滨逊漂流记的人物塑造:外国文学课程教案
- (正式版)DB15∕T 3364-2024 《沙蒿籽多糖含量测定分光光度法》
- 电器学考试题及答案
- 电解工考试题及答案
- 电大申论考试题及答案
- 灯光专业考试题及答案
- (正式版)DB15∕T 3270-2023 《北苍术生态种植技术规程》
- 德国机械考试题及答案
- 报考护理学面试题库及答案
- 发展汉语-初级读写-第一课-你好
- 韩国《寄生虫》电影鉴赏解读
- 人教版四年级数学上册《课堂作业设计》全套
- TTT系列课程-结构化思考力
- Cpk 计算标准模板
- 封起DE日子博文 2006
- 锂离子电池生产安全讲座
- 眼科学-眼科检查(课件)
- 产品碳足迹课件
- 部编人教版六年级道德与法治上册全册教学课件
- 美国地图高清中文版
评论
0/150
提交评论