第五章数组(Arrays)
【计划课时】授课6课时+上机4课时(预习内容:教材第六章)
一、概述
C数据类型: P10
·基本类(简单类)——字符型/整型/实型/枚举型(enum) ·构造类(组合类)——数组/结构体/共用体 ·指针类
·空类型(void) 对于变量
基本类型——单个出现的变量,每个变量可以代表一个确定的数据(变量值),且具有一定属性。
如 static int x,y;
但变量间不存在确定的相互关系。
构造类型——由基本类型按一定规则组成。其中:
数组:由一组有序数据(数组元素)组成。
每个元素:相同类型,统一数组名,用下标确定其顺序,但可以取各自值。
如 static int a[5];
其中:[ ]表示a是个数组,而不是一个简单变量a。
5表示该数组共有5个元素
元素编号从0开始,a[0]表示第一个元素,a[4]表示第5个元素(最后一个)
数组的用处很多。简单例子:要读入某班全体50位同学某科学习成绩,然后进行简单处理(求平均成绩、最高分、最低分??)
若用简单变量,需50个不同变量名,如stu1,stu2,?stu50,要用很多个scanf命令。 而用数组,可共用一个scanf命令,并利用循环结构读取。 示例程序如下: #define NUM 50; main()
{ int i,score[NUM],highest; float sum,average;
for (i=0;i printf(“全班同学成绩公布如下:\\n”); /*公布全班同学分数*/ for (i=0;i { printf(“%d号同学:] ”,i+1,score[i]); if (i==9) printf(“\\n”); } for (i=0;i printf(“全班平均成绩是:%d\\n”,average); highest=a[0]; for (i=0;i if (score[i]>highest) highest=a[i]; printf(“最高分是:%d\\n”,highest); } 通过#define NUM 50,可使程序更具通用性。 二、数组定义 同变量一样,数组也必须先定义,后使用。 定义内容: ·数组名(同变量名:字母、下划线、数字;字母或下划线开头;长度≤32) ·类型(存储属性/数据类型) ·大小(维数/元素个数) 定义的一般形式: 存储属性 数据类型 数组名[常量表达式][常量表达式]… 常量表达式:常量或符号常量,其值必须为正,不能为变量 错误: 正确: int n=5; #define N 5 int a[n]; int a[N]; 正确: int a[10],b[5][4]; char name[8],ch[2][3]; static float x[8*2+1],table[2][3][4]; #define NUM 40; int a[NUM],b[NUM+2]; 三、数组的存储结构 ·根据数组的数据类型,为每一元素安排相同长度的存储单元 ·根据数组的存储属性,确定将其安排在内存动态、静态存储区或寄存器区 a[0] 2字节 name[0] 1字节 4字节 a[1] ?? a[9] 2字节 ? 2字节 name[1] ?? name[7] 1字节 ? 1字节 4字节 ? 4字节 x[0] x[1] ?? x[7] int a[10] char name[8] static float x[8] 动态存储区 静态存储区 四、数组的初始化(赋初值) ·旧版标准:只允许对外部或静态的数组初始化 ·新版标准:也允许对auto数组初始化(只能用常量表达式) 一般形式: int a[5]={1,2,3,4,5}; int b[2][3]={{1,2,3},{4,5,6}}; 或 int b[2][3]={1,2,3,4,5,6}; 简略形式: 1、省略第一维数组大小。如: int a[ ]={?},b[][3]={?}; 2、省略元素值 如: int x[6]={1,2,3,4}; (x[4]、x[5]自动用0补足) int a[5]={0}; int b[3][2]={0}; (全部元素初始化为0) 【例一】以下程序的运行结果是什么? main(){ 1 2 3 int a[][3]={{1,2,3},{4,5},{6},{0}}; 4 5 0 clrscr(); 6 0 0 printf(\ 0 0 0 } 结果:5,0,0 【例二】若int a[ ][3]={1,2,3,4,5,6,7},则a数组的第一维大小是多少?(3) 说明:静态/外部数组未初始化,默认初值是0(数值)或空格(字符) auto数组未初始化,初值为不可预料的数。 五、数组的引用(使用数组元素) 原则:先定义后引用 只能逐个引用数组元素,不能一次引用整个数组。 引用数组元素要注意下标不要出界(编译程序不检查是否“出界”) 引用示例: a[2][3] a[2-1][2*3-1] a[x] (x为整型表达式) 错误: a[2,3] 比较: 错误 正确 int n; int a[5]; scanf(“%d”,&n); for (i=0;i<5;i++) int a[n]; printf(“%d\\n”,a[i]); 定义时不可用变量作下标 引用时可以用整型变量及表达式作下标 【例一】 下列程序的功能是显示如下图形: 1 0 0 0 0 2 1 0 0 0 3 2 1 0 0 4 3 2 1 0 5 4 3 2 1 main() {int a[5][5],i,j; a[5][5]分析: clrscr(); a00 a01 a02 a03 a04 for (i=0;i<5;i++) a10 a11 a12 a13 a14 {for (j=0;j<5;j++) { if ( 【6】 ) a[i][j]=0; a20 a21 a22 a23 a24 else a[i][j]=【7】; a30 a31 a32 a33 a34 printf(\=\,a[i][j]); a40 a41 a42 a43 a44 } printf(\ } } 答案:【6】i 【分析】这类题的元素值排列很有规律,所以一般要从分析行数i、列数j与元素值的关系着手。分析上图可知,当i 六、数组作为函数参数 1、用数组元素作函数实参 此时可把数组元素看作普通变量(单向值传递)。 特点:主调函数中的实参——数组元素(带下标) 被调函数中的形参——普通变量 调用结果:形参值的变化对实参值无影响(二者分占不同内存)。 【例一】main(){ int a[]={1,2,3,4,5,6}; static int b[6]={2,3,0,4}; 结果:a=1,b=2 int s,i; a=2,b=3 a=3,b=0 a=4,b=4 a=5,b=0 a=6,b=0 system(\for (i=0;i<6;i++) {s=sum(a[i],b[i],i); printf(\ } } sum(int x,int y,int z) {x=z;y=z; /* printf(\} 【讨论】如果将sum函数中注释标记去掉,结果是什么? a[i] x a[i] b[i] i b[i] y ?? i z x 主调函数中 被调函数中 y (调完消失) z 2、用数组名作函数实参 若 int a[6]; 则数组名a表示数组的起始地址。 此时,是把实参数组的起始地址“传给”形参数组。 本质:对应的数组元素(不是形参与实参)共享同一内存单元(所谓“双向的地址传送”)。 特点:主调函数中的实参——数组名(不带下标) 被调函数中的形参——数组名或数组定义式 调用结果:两数组同下标者为同值。 【例二】 main(){ 结果:a=0,b=0 int a[]={1,2,3,4,5,6}; a=1,b=1 static int b[6]={2,3,0,4}; a=2,b=2 int s,i; a=3,b=3 system(\a=4,b=4 for (i=0;i<6;i++) a=5,b=5 {s=sum(a,b,i); printf(\ } } sum(int x[],int y[],int z) {x[z]=z;y[z]=z; } a[i] x[i] a[i] x b[i] y[i] i z[i] b[i] y ?? 调用结束 i 主调函数中 被调函数中 (调完消失) 注意:1、形参数组和实参数组应分别在各自函数中定义; z 自动消失 2、形参数组可不定义大小(用空方格) 3、二者大小可一致或不一致(C编译程序不检查形参) 但注意引用形参时不要超过实参界 【例三】分析以下程序的运行结果。 main() { int a[5]={5,10,-7,3,7},i; sort(a,5); for (i=0;i<5;i++) printf(\} sort(int x[],int n) {int j,t; for (j=0;j if(x[j]>x[j+1] ){ t=x[j];x[j]=x[j+1]; x[j+1]=t; } } 结果:5 –7 3 7 10 【讨论】如何通过数组技术将一列数据中最大或最小的数移前或移后?