数组C语言大学实用教程课件.ppt
第6章 数组,哈尔滨工业大学计算机科学与技术学院苏小红,C语言大学实用教程,内容提要,数组类型;向函数传递一维数组和二维数组;常用算法:排序、查找、求最大最小值等;用字符数组存取字符串;使用字符串处理函数处理字符串,C提供了一组基本类型:int、double等。除了基本数据类型,还有一些组合的数据类型,称为构造数据类型。(书上18页)构造机制包括数组、指针、结构、联合。可用它们组合数据对象,作为整体使用。,组合的数据对象称为复合数据对象。复合对象形成的类型称为复合数据类型,组成部分称为成分/成员/元素。可创建能存放复合类型数据的变量。这种变量可作为整体使用,通过名字可以访问整个复合对象。也可以访问复合数据对象的成分,如:使用成分的值或给成分赋值。本章介绍数组就是常见的组合机制。,数组的用处,保存大量同类型的相关数据的问题-例如,输入全班30个学生的成绩,并排出名次。-例如,矩阵运算,表格数据等。,为什么使用数组,例子:要读入某班全体50位同学某科学习成绩,然后进行简单处理(求平均成绩、最高分、最低分)若用简单变量,需50个不同变量名,要用很多个scanf命令 int score1,score2,score50;scanf(%d,%d,%d,保存大量同类型的相关数据,6.1 数组的概念、定义和使用数组(array)是多个同类型数据对象的组合。一个数组汇集了多个数据项,数组元素。可从数组出发处理各元素,以统一方式处理一批/所有元素,是数组和一组独立变量的主要区别。,为此需要:数组描述,数组变量定义数组使用,包括通过数组变量使用其元素数组实现,数组的存储方式,数组变量定义定义数组变量(定义数组)时需说明:数组元素类型数组(变量)的元素个数 元素个数也称数组大小或长度。定义数组变量时,方括号内整型表达式说明元素个数,表达式应用静态确定值,可用字面量或枚举常量。,例,定义两个数组:int a10;double a1100;数组定义可以与其他变量定义写在一起,如:int a216,n,a325,m;,定义 存储类型 数据类型 数组名 整数1 整数2 整数n;,a9,a8,a7,a1,a0,int a10;定义一个有10个int型元素的数组系统会在内存分配连续的10个int空间给此数组直接对a的访问,就是访问此数组的首地址使用a0、a1、a2、a9这样的形式访问每个元素。可以像使用普通变量一样使用他们。,数组(Array)的实现,数组大小最好用宏来定义,以适应未来可能的变化#define SIZE 10int aSIZE;数组大小定义好后,将永远不变,#include#define SIZE 10main()int aSIZE;,也可定义外部数组和局部静态数组(用static)。作用域与存在期与简单变量相同。数组的外部说明不必描述数组大小。例:extern int a;extern double a1;,下面函数里数组定义不合法:void f(int m,int n)int bn;/*非法,编译时无法确定大小*/.,新 C99 标准支持这种定义,满足 C99 的编译器很少,根据数组的数据类型,为每一元素安排相同长度的存储单元根据数组的存储类型,将其安排在内存的动态、静态存储区或寄存器区用sizeof(a)来获得数组a所占字节数,数组的存储结构,一维数组占用字节数=数组长度sizeof(基类型),数组使用 基本操作是元素访问。元素顺序编号,首元素序号0,其余顺序编号。n元数组元素编号是0到n-1。定义:int b100;元素编号为0、1、2、。称为下标或指标。元素访问通过运算符,优先级最高,运算对象是数组名和括号里表示下标的表达式。表达式、语句里的 b3 称为下标表达式。,例:有上面定义后,可写:b0=1;b1=1;b2=b0+b1;b3=b1+b2;,99,数组意义在于能以统一方式描述对一组数据的处理。下标表达式可用一般的整型表达式。如:bi=bi-1+bi-2;访问哪个元素由i值确定。同一语句可访问不同元素,可用在循环里访问一批元素。,for(i=0;i 100;+i)bi+=a1i*a2i;/*假设数组都有定义*/循环中涉及到300个基本数据对象。,对数组的多个或全部元素操作,常用for语句。令变量遍历数组下标:for(n=0;n 数组长度;+n).,问题:fib是30个元素的数组,假设程序里写:for(n=2;n=30;+n)fibn=fibn-1+fibn-2;循环中试图访问fib30,实际无此元素。,用超范围的下标访问称为越界访问,是数组使用中最常见的错误。使用大于最大下标的下标,将访问数组以外的空间。那里的数据是未知的。下标值超范围是运行中的问题。,C不检查数组元素访问的合法性,运行中出现越界不会报错。超范围访问是严重错误,后果无法预料。,在一些系统里越界访问可能导致动态错,系统强行终止出错的程序。DOS 不检查非法访问,越界可能破坏本程序的数据/程序本身/其他软件,甚至 DOS 系统。编程者要保证数组下标值的合法性,保证不越界。,数组定义后的初值仍然是随机数,一般需要我们来初始化 定义数组时可直接初始化。外部、局部静态或自动数组都可在定义时进行初始化。定义时初始化的例子:int b4=1,1,2,3;double ax6=1.3,2.24,5.11,8.37,6.5;int a5=0;int a=11,22,33,44,55;初值表达式必须是常量表达式。对自动数组也一样。,数组初始化,这种写法只能用于数组初始化,不能用在语句里。若定义时未初始化,外部和局部静态数组的元素自动初始化为0;自动数组不自动初始化。,可只为部分元素提供初值,其余元素将自动置0。初始化表元素个数不得超过数组元素个数。例:int b14=1,2;b12、b13将给初值0。,若给了所有元素的初值,可以不写数组大小而只写方括号,元素个数由初值个数确定。例:int fib=1,1,2,3,5,8,13,21,34,55;这种写法能减少维护负担,有利于程序修改。,快速地随机访问一旦定义,不能改变大小,数组的特点,只能逐个对数组元素进行操作(字符数组例外),输入方法:,int a10,i;,输入第i个数组元素:,scanf(%d,输入整个数组元素:,for(i=0;i10;i+)scanf(%d,输出方法:,输出第i个数组元素:,printf(%d,ai);,输出整个数组元素:,for(i=0;i10;i+)printf(%d,ai);,一维数组的输入和输出,举例:请登记某班级数学成绩,再输出,#include#define ARR_SIZE 40main()float scoreARR_SIZE;int n,i;long numARR_SIZE;printf(Please enter total number:);scanf(%d,一维数组和多维数组,一维数组用一个下标确定各元素在数组中的顺序可用排列成一行的元素组来表示如 int a5;二维数组用两个下标确定各元素在数组中的顺序可用排列成i行,j列的元素组来表示如 int b23;n维数组用n个下标来确定各元素在数组中的顺序如 int c324;n3时,维数组无法在平面上表示其各元素的位置,二维数组的定义,数据类型 数组名常量表达式常量表达式;,int a23;,a0a1,a,-a00 a01 a02,-a10 a11 a12,【例一】以下程序的运行结果是什么?main()int a3=1,2,3,4,5,6,0;printf(%d,%d,%dn,a11,a21,a31);,1 2 34 5 06 0 00 0 0,结果:5,0,0,【例二】若int a 3=1,2,3,4,5,6,7,则a数组的第一维大小是多少?,1 2 34 5 67 0 0,二维数组的初始化示例,数组的引用,数组名 下标1 下标2 下标n下标都是从0开始,养成从0开始查数的职业病使用a0、a1、a2、a9这样的形式访问每个元素数组下标(index)既可以是常量,也可以是整型表达式,允许快速地随机访问.可以像使用普通变量一样使用他们,数组的引用,数组名 下标1 下标2 下标n下标越界是大忌!编译程序不检查是否越界下标越界,将访问数组以外的空间那里的数据是未知的,不受我们掌控,可能带来严重后果,二维数组的存储结构,short int a23;,a10,a11,a12,a00,a01,a02,存放顺序:先顺序存放第0行的元素再存放第1行的元素,所以需要知道数组的每一行 有多少列,这样从起始地址开始,才能正确的读出数组的元素,按行存放,二维数组占用字节数=第一维长度第二维长度 sizeof(基类型),二维数组所占的存储空间的计算:,二维数组的输入和输出,数组的输入和输出只能逐个对数组元素进行操作(字符数组例外),int a23,i,j;,如何使两个数组的值相等,main()int a4=1,2,3,4,b4;b=a;,解决方法法1:逐个元素赋值 b0=a0;b1=a1;b2=a2;b3=a3;法2:通过循环赋值 int i;for(i=0;i4;i+)bi=ai;,原因:数组名表示数组的首地址,其值不可改变!,如何使两个数组的值相等,如何使两个二维数组的值相等?,通过双重循环赋值 int a42=1,2,3,4,5,6,7,8;int b42;int i,j;for(i=0;i4;i+)for(j=0;j2;j+)bij=aij;,例6.1,兔子繁殖问题打印每个月和年底时的总的兔子对数Fibonacci数列 123581321345589144233,,图中蓝色实线表示大兔仍是大兔,红色实线表示小兔长成大兔;绿色虚线表示大兔生小兔。不难看出:年末有大兔子144对,小兔子89对,总共144+89=233对深入观察:上月有几对大兔子,这月就有几对小兔子,即:每月小兔子对数=上月大兔子对数每月大兔子对数=上月大兔子对数+上月小兔子对数综合有:每月大兔子对数=前两月大兔子对数之和,例6.1,#include#define YEAR_MONTH 12main()int fYEAR_MONTH+1=0,1,2;int month;for(month=3;month=YEAR_MONTH;month+)fmonth=fmonth-1+fmonth-2;for(month=1;month=YEAR_MONTH;month+)printf(%dt,fmonth);printf(nsum=%dn,fYEAR_MONTH);,max(i=0),max(i=2),max(i=3),计算最大值算法,数组编号:,学号:,成绩:,maxScore:,maxNum:,因为8875,所以88保留,因为9088,所以用90替换88,由于90分所在的数组编号是2,记下该编号,去找到学号数组中的数组编号,并替换,88,200801,200803,90,例6.2 打印最高分,从键盘输入学生人数n;从键盘输入所有学生的学号和成绩分别存入数组num和score假设其中的一个学生成绩为最高maxScore=score0;对所有学生成绩进行比较,即 for(i=1;i maxScore则修改maxScore值为scorei 打印最高分maxScore,.main().for(i=0;i maxScore)maxScore=scorei;printf(maxScore=%.0fn,maxScore);,例6.2 打印最高分,.main().for(i=0;i maxScore)maxScore=scorei;maxNum=numi;printf(maxScore=%.0f,maxNum=%ldn,maxScore,maxNum);,例6.2 打印最高分及其学生序号,用函数实现?,#include#define ARR_SIZE 40float FindMax(float arr,int n);main()float scoreARR_SIZE,maxScore;int n,i;printf(Please enter total number:);scanf(%d,float FindMax(float arr,int n)float max;int i;max=arr0;for(i=1;i max)max=arri;,现场编程用函数实现打印最高分,关于函数的参数传递:对于一般变量作为函数的形式参数,调用函数的时候,用“单项值传递”的方法来将实参的值复制给形参,形参有值后,参与计算,得出需要的值,而后随着调用的结束,形参变量消失。,实参,形参,形参值在此处完成函数运算,并消失,但是如果用数组作为函数的形式参数:由于每次调用函数,作为形式参数的数组,每次都要重新开辟一块连续的存储空间,每次复制一堆的实参值,用完又马上将内存还给系统。需要的系统开销太大。因此,C程序设计语言规定,数组作形式参数时,不重新开辟存储空间,而是用实际参数已有的空间。,float FindMax(float arr,int n)float max;int i;max=arr0;for(i=1;i max)max=arri;,数组名作函数参数,传递整个数组到另一个函数内,实际上是将数组的首地址作为参数传过去用数组名作为函数参数只拷贝一个地址自然比拷贝全部数据效率高由于首地址相同,故实参数组与形参数组占用同一段内存在该函数内,不仅可以读这个数组的元素,还可以修改它们,简单变量和数组作函数参数的区别,#include#define ARR_SIZE 40float FindMax(float arr,int n);main()float scoreARR_SIZE,maxScore;int n,i;printf(Please enter total number:);scanf(%d,float FindMax(float arr,int)float max;int i;max=arr0;for(i=1;i max)max=arri;,现场编程用函数实现打印最高分,向函数传递一维数组时,最好同时再用一个参数传递数组的长度,n,作业,P2286.46.76.9,现场演示排序算法,交换法排序选择法排序,交换法排序,交换法排序,交换法排序,交换法排序 for(i=0;i scorei)交换成绩scorej和scorei,交换学号numj和numi;,如何实现两数交换?如下方法是否可行:scorej=scorei;scorei=scorej;试想一下,一个瓶子装酱油,一个瓶子装醋,现在将这两个瓶子交换装的东西,如何交换?,答案:必须再拿一个空瓶子,用来腾空其中一个瓶子。,选择法排序,k=1,k=2,k=0,k=1,选择法排序,k=3,k=4,k=3,k=4,选择法排序,选择法排序 for(i=0;i scorek)记录此轮比较中最高分的元素下标 k=j;若k中记录的最大数不在位置i,则 交换成绩scorek和scorei,交换学号numk和numi;,现场演示查找算法,顺序查找折半查找,顺序查找,int Search(long a,int n,long x)int i;for(i=0;in;i+)if(ai=x)return(i);return(-1);,哈,找到了!,折半查找,哈,找到了!,折半查找,唉,没找到!,int BinSearch(long a,int n,long x)int low,high,mid;low=0;high=n-1;while(low amid)low=mid+1;else if(x amid)high=mid-1;else return(mid);return(-1);,向函数传递二维数组,实际传送的是指向数组第一个元素的地址在声明二维数组形参时,不能省略数组第二维的长度,为什么?,例6.8 计算每门课程的总分和平均分,void Total(int scoreCOURSE,int sum,float aver,int n)int i,j;for(j=0;jCOURSE;j+)sumj=0;for(i=0;in;i+)sumj=sumj+scoreij;averj=(float)sumj/n;,可以省略数组第一维的长度不能省略数组第二维的长度,字符串(String)与字符数组,字符串一串以0结尾的字符在C语言中被看作字符串用双引号括起的一串字符是字符串常量,C语言自动为其添加0终结符C语言并没有为字符串提供任何专门的表示法,完全使用字符数组和字符指针来处理字符数组每个元素都是字符类型的数组char string80;,字符数组的初始化,用字符型数据对数组进行初始化 char str6=C,h,i,n,a,0;char str=C,h,i,n,a;用字符串常量直接对数组初始化 char str6=China;char str6=China;char str5=China;,仅为字符型一维数组,不是字符串,仅为字符型一维数组,不是字符串,二维字符数组初始化char weekday710=”Sunday”,”Monday”,”Tuesday”,”Wednesday”,”Thursday”,”Friday”,”Saturday”;char weekday10=”Sunday”,”Monday”,”Tuesday”,”Wednesday”,”Thursday”,”Friday”,”Saturday”;但不可写成:char weekday=”Sunday”,”Monday”,”Tuesday”,”Wednesday”,”Thursday”,”Friday”,”Saturday”;,逐个输入输出,for(i=0;si!=0;i+)putchar(si);putchar(n);,一次性输入输出,scanf(%s,s);printf(%s,s);,char s10;,字符数组的输入输出,gets(s);puts(s);,scanf(),char str10;scanf(%s,str);字符数组名本身代表该数组存放的字符串首地址,不需用地址符。不能读入带空格、回车或跳格符(Tab)的字符串,遇到这些字符时,系统认为字符串输入结束。gets()可以 应确保输入的字符串长度不超过数组所能容纳的空间大小。当用户的输入多于10个(含10个),str数组将越界,字符串处理函数,在中定义了若干专门的字符串处理函数strcpy:string copystrcpy(目的字符串,源字符串);strlen:string lengthstrlen(字符串);返回字符串的实际长度,不包括0strcat:string combinationstrcat(目的字符串,源字符串);strcmp:string comparisonstrcmp(字符串1,字符串2);当出现第一对不相等的字符时,就由这两个字符决定所在字符串的大小返回其ASCII码比较的结果值,字符串处理函数,str1=str2;/*错误*/strcpy(str1,str2);/*正确*/if(str1 str2)/*错误*/if(strcmp(str1,str2)0)/*正确*/,字符串不能直接整体复制!也不能用关系运算符比较大小,例6.9,从键盘任意输入5个学生的姓名,编程找出并输出按字典顺序排在最前面的学生姓名 等价于求最小字符串,#include#include#define ARRA_SIZE 80main()int n,num;char strARRA_SIZE,minARRA_SIZE;printf(Please enter five names:n);gets(str);/输入字符串strcpy(min,str);/将得到的字符串复制到min字符数组里for(n=1;n5;n+)gets(str);/每次输入一个字符串 if(strcmp(str,min)0)/比较两个字符串的大小,若str较小strcpy(min,str);/将字符串str复制给min printf(The min is:);puts(min);,这一章我们学习了,了解了在什么情况下使用数组这种数据类型 向函数传递一维数组和二维数组的方法 用数组名作为函数参数和用简单变量作为函数参数的不同之处 常用算法:求最大值,排序字符数组,作业,P2232296.16.36.116.13,