版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、1第8章数组本章要点数组的由来一维数组数组的初始化多维数组常量数组2例子:计算10个同学的成绩:计算平均成绩、输出低于平均成绩的同学成绩。#include void main() float grade1,grade2,grade3, grade10; /*定义10个变量*/ float average; scanf(“%f”,&grade1); /*输入10个数据*/ scanf(“%f”,&grade2); scanf(“%f”,&grade10); average=(grade1+grade2+grade10)/10; /*求平均值*/ /*打印低于平均成绩的同学成绩*/ if (gra
2、de1average) printf(“%fn”,grade1); if (grade2average) printf(“%fn”,grade2); if (grade10average) printf(“%fn”,grade10); 数据类型相同的若干个数#include void main() float grade10; /*定义一个实型数组存放10个成绩*/ float average; int i; for (i=0;i10;i+) /*输入10个数据*/ scanf(%f,&gradei); for(i=1,average=0;i10;i+) /*求平均值*/ average=av
3、erage+gradei; average=average/10; for (i=0;i10;i+) /*打印低于平均成绩的同学成绩*/ if (gradeiaverage) printf(“grade=%d=%fn”,i+1,gradei); 从上面两个例子的比较中,我们可以看到用数组解决这类问题:程序简洁、思路清楚明了。这就是数组带给我们的好处。标量与聚合变量标量(scalar):具有保存单一数据项能力的变量。C语言也支持聚合(aggregate)变量,这类变量可以存储数值的集合。C语言中有两种常用的聚合类型:数组(array)和结构(structure) 。5一维数组数组(array)是
4、含有多个数据值的数据结构,并且每个数据值具有相同的数据类型。这些数据值被称为元素(element),数组内可以根据元素所处的位置对其进行单独选择。最简单的数组类型就是一维数组。一维数组中的元素一个接一个地编排在单独一行(或者一列)内:6一维数组的定义一维数组的定义形式: 数据类型 数组名常量表达式合法标识符数组元素个数,数组长度数组元素的类型2004 a0 a1 a2 a920002008内存2036例 int a10;一批相同类型的变量使用同一个数组名,用下标来相互区分。一维数组为了声明数组,需要说明数组元素的类型和数量:int a10;数组的元素可以是任何类型;数组的长度可以用任何(整数)
5、常量表达式说明。较好的方法是用宏来定义数组的长度:#define N 10int aN;8数字访问利器-数组下标为了存取特定的数组元素,可以在写数组名的同时在后边加上一个用方括号围绕的整数值。这被称为对数组进行下标(subscripting)或索引(indexing)。长度为n的数组,其元素的索引是从0到 n-1。如果a 是一个长为10的数组,则其元素可标记为 a0, a1, , a9:9数字访问利器-数组下标ai的表达式格式是左值,所以数组元素可以和普通变量一样使用。a0 = 1;printf(%dn, a5);+ai;一般来说,如果一个数组所包含元素的类型为T,则数组的每个元素都可以被当做
6、一个类型为T的变量来对待。int a3;/a0,a1,a2可以看做3个int 型变量10数组下标许多程序所采用for循环对数组中的每个元素执行一些操作。下面是关于长度为N的数组的一些典型操作示例:for (i = 0; i N; i+) ai = 0; /* clears a */for (i = 0; i N; i+) scanf(%d, &ai); /* reads data into a */for (i = 0; i N; i+) sum += ai; /* sums the elements of a */11数组下标C语言不要求检查下标的范围;当下标超出范围时,程序可能执行不可预知
7、的行为。一个典型的错误:忘记了对n个元素数组的索引是从0到n-1,而不是从1到n。 int a10, i;for (i = 1; i = 10; i+) ai = 0;12数组下标数组下标可以是任何整数表达式:ai+j*10 = 0;表达式甚至可能会有副作用:i = 0;while (i N) ai+ = 0;13数组下标当数组下标有副作用时一定要注意:i = 0;while (i N) ai = bi+;表达式 ai = bi+ 访问了 i的值并且修改了 i,结果导致不可预知的行为。通过从下标中移走自增操作的方法可以很容易避免此类问题的发生:for (i = 0; i N; i+) ai =
8、 bi;14程序:数列反向reverse.c 程序要求用户录入一串数,然后按反向顺序输出这些数:Enter 10 numbers: 34 82 49 102 7 94 23 11 50 31In reverse order: 31 50 11 23 94 7 102 49 82 34程序在读入数时将其存储在一个数组中,然后通过数组反向开始一个接一个地显示出数组元素。15reverse.c/* Reverses a series of numbers */#include #define N 10int main(void) int aN, i; printf(Enter %d numbers:
9、 , N); for (i = 0; i = 0; i-) printf( %d, ai); printf(n); return 0;16数组初始化像其他变量一样,数组也可以在声明时获得一个初始值。数组初始化式(array initializer)最通用的格式是一个常量表达式列表,列表用大括号括起来,并且内部数值用逗号进行分隔:int a10 = 1, 2, 3, 4, 5, 6, 7, 8, 9, 10;17数组初始化如果初始化式比数组短,那么数组中剩余的元素赋值为0:int a10 = 1, 2, 3, 4, 5, 6;/* initial value of a is 1, 2, 3, 4
10、, 5, 6, 0, 0, 0, 0 */利用这一特性,可以很容易地给全部数组元素初始化为零:int a10 = 0;/* initial value of a is 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 */初始化式完全为空是非法的,所以要在大括号内放上一个单独的0。初始化式长过要初始化的数组也是非法的。18数组初始化如果显示一个初始化式,那么可以忽略掉数组的长度:int a = 1, 2, 3, 4, 5, 6, 7, 8, 9, 10;编译器利用初始化式的长度来确定数组的大小。19程序:检查数中重复出现的数字程序repdigit.c用来检查数中是否有出现多于一次的数字
11、。用户输入数后,程序显示信息Repeated digit 或者 No repeated digit:Enter a number: 28212Repeated digit数28212有一个重复的数字(2);而数9357则没有。20程序:检查数中重复出现的数字如何剥离出每一个数字?不知道用户输入几位数!剥离数字可以采用除10取余数,从低位开始剥离;下次再使用除10后的商重新进行剥离;21如何记录下来数字出现与否?可以给每个数码设置一个标志位,出现过为1,否则为零。程序:检查数中重复出现的数字程序采用布尔型值的数组跟踪数中出现的数字。最初的时候,digit_seen中每个元素的值都为假。当给出数n
12、时,程序一次一个地检查n的数字,并且把每次的数字存储在变量digit中。如果digit_seendigit为真,那么表示 digit至少在n中出现了两次。如果digit_seendigit为假,那么表示digit那么表示,因此程序会把 digit_seendigit设置为真并且继续执行。220000000000230123456789digit_seen10数组28212%10001000000001100000002821%10282%100110000000开始repdigit.c/* Checks numbers for repeated digits */#include /* C99
13、 only */#include int main(void) bool digit_seen10 = false; int digit; long n; printf(Enter a number: ); scanf(%ld, &n); while (n 0) digit = n % 10; if (digit_seendigit) break; digit_seendigit = true; n /= 10; 24 if (n 0) printf(Repeated digitn); else printf(No repeated digitn); return 0;25思考:如何统计数字在
14、输入的数中出现的次数?对数组使用sizeof运算符运算符sizeof可以确定数组的大小(字节数)。如果数组a有10个整数,那么sizeof(a)可以代表40(假设每个整数用4字节存储)。还可以用sizeof来计算数组元素的大小,比如a0。26对数组使用sizeof运算符用数组的大小除以数组元素的大小可以得到数组的长度: sizeof(a) / sizeof(a0)当需要数组长度时,可采用上述这个表达式。数组a的清零操作可以写成:for (i = 0; i sizeof(a) / sizeof(a0); i+) ai = 0;数组长度在日后需要改变,也不需要改变循环。27对数组使用sizeof运
15、算符有些编译器会对i sizeof(a) / sizeof(a0)表达式给出一条警告信息。变量 i的类型可能是 int (有符号类型),而 sizeof返回值的类型是size_t (一种无符号类型)。将有符号整数和无符号整数比较是很危险的,尽管在本例中这样做没问题。28对数组使用sizeof运算符为避免这一警告,可以把 sizeof(a) / sizeof(a0) 强制转化成有符号整数:for (i = 0; i (int) (sizeof(a) / sizeof(a0); i+) ai = 0;定义一个宏来表示上述表达式常常是很有帮助的:#define SIZE (int) (sizeof(
16、a) / sizeof(a0)for (i = 0; i SIZE; i+) ai = 0;29程序:计算利息程序interest.c打印出一个表格,这个表格显示了在几年时间内100美金投资在不同利率上的价值。用户将输入利率和要投资的年数。假设整合利息一年一次,表格将显示出一年间在此输入利率下和后边4个更高利率下投资的价值。30程序:计算利息下面是程序运行时的情况:Enter interest rate: 6Enter number of years: 5Years 6% 7% 8% 9% 10% 1 106.00 107.00 108.00 109.00 110.00 2 112.36 11
17、4.49 116.64 118.81 121.00 3 119.10 122.50 125.97 129.50 133.10 4 126.25 131.08 136.05 141.16 146.41 5 133.82 140.26 146.93 153.86 161.0531程序:计算利息第二行的数值要依赖于第一行的数,解决方案是把第一行的数存储在数组中。数组中的这些值将用于计算第二行的内容。从第三行到最后一行可以重复这个过程。程序使用了嵌套的for语句。外层循环将从1计数到用户要求的年数。内层循环将从利率的最低值自增到最高值。32interest.c/* Prints a table of
18、compound interest */#include #define NUM_RATES (int) (sizeof(value) / sizeof(value0)#define INITIAL_BALANCE 100.00int main(void) int i, low_rate, num_years, year; double value5; printf(Enter interest rate: ); scanf(%d, &low_rate); printf(Enter number of years: ); scanf(%d, &num_years);33 printf(nYea
19、rs); for (i = 0; i NUM_RATES; i+) printf(%6d%, low_rate + i); valuei = INITIAL_BALANCE;/矩阵初始化 printf(n); for (year = 1; year = num_years; year+) printf(%3d , year); for (i = 0; i 38,交换位置原数据和序号序号12345678数据4938659776132749第一趟排序的步骤:序号12345678数据3849659776132749序号12345678数据3849659776132749序号12345678数据384
20、9659776132749序号12345678数据3849657697132749序号12345678数据3849657613972749序号12345678数据3849657613279749序号12345678数据3849657613274997经过第一趟排序,把最大的数沉到最底了!4965, 保持不变6576, 交换位置9713, 交换位置9727, 交换位置9749, 交换位置经过第二趟排序,实现了什么目的?经过第二趟排序,把第二大的数沉到倒数第二个位置了!9749271376654938数据87654321序号3849,保持不变第一趟排序后的数据和序号第二趟排序的步骤:序号12345
21、678数据38496576132749974965, 保持不变6513, 交换位置7627, 交换位置7649, 交换位置序号12345678数据3849657613274997序号12345678数据3849657613274997序号12345678数据3849657613274997序号12345678数据3849651376274997序号12345678数据3849651327764997序号12345678数据38496513274976977697, 保持不变序号12345678数据3849651327497697观察原数据与第一、二趟排序后的数据序号12345678数据3849
22、657613274997序号12345678数据3849651327497697序号12345678数据4938659776132749按照此法,不断将当前剩余数中最大者“沉底,”重复下去,最后就得到了一个从小到大的排列。数组编程实例冒泡排序从算法原理可见,冒泡排序需要对数组扫描许多遍,每趟让一个数“沉底”,那么要扫描多少遍? 答:N-1遍。那么每一遍都需要扫描整个数组吗? 答:不需要。因为已经沉底的元素不需要再扫描。41数组编程实例冒泡排序从实现来看:既然要扫描N-1遍,显然要使用循环;而在每一次扫描中,需要将相邻元素两两比较,显然这个也需要使用循环;因此,需要使用两层循环来实现冒泡排序。4
23、2数组编程实例冒泡排序那么循环的次数如何确定?对于外层循环,显然次数为N-1次。对于内层循环,次数为多少? 此时的思路是考虑一般化的情况:设当前是第j次扫描(即外循环正处于j次时),那么此时已经有j-1个元素沉底了,所以只需在剩下的N-(j-1)个元素中做相邻两两比较操作,共需比较N-(j-1)-1=N-j次。43数组编程实例冒泡排序因此得到核心的循环结构及操作描述: for(j=0;jN-1;j+) for(k=0;kk+1号元素) 交换k号元素和k+1号元素位置;注意:由于循环变量j,k是从0开始,所以内循环结束条件为kN-j-1,或写为k=N-j-2亦可。44完整程序冒泡排序(10个数为
24、例)void main() int a10,k,j,t; printf(输入10个整数:n); for( k = 0; k 10; k + ) scanf(%d,&a k ); /依次输入10个整数 for( j = 0; j 9; j + ) /进行9轮排序 即n1次 for( k = 0; k a k + 1 ) t=ak; ak=ak+1; ak+1=t; /小的沉底,大的上浮 printf(排序结果:); for( k = 0; k 10; k + ) /依次输出排序结果 printf(%dt,a k ); printf(n); 45思考:程序的改进可以使用#define N 10这种
25、方式,使得程序可以处理任意个数的元素排序,或者在C99中使用变长数组;46思考:程序的改进程序算法本身的改进: 冒泡排序中最基本的操作是比较和交换。在某些(甚至是很多)情况下,并不需要扫描完N-1次,数组就已经有序了(极端情况:数组一开始就是由小到大排好的)。如果这时仍旧继续扫描,显然不明智。 所以,需要有一种方法,能自动地察觉到数组已经有序的状态。怎么做?47思考:程序的改进48假设当某一次扫描完成后,数组中的所有元素都没有交换过位置,这时就意味着数组已经有序了!此时就可以退出,不用再进行后续扫描了。因此,可以定义一个变量flag,在每一趟扫描之前,令其为0,在这趟扫描中一旦出现交换操作,那
26、么就改变其值为1。每次扫描结束后,判断flag值还是不是0。如果是0,意味着这趟扫描压根没有做交换操作,所以你懂的。请大家仔细体会flag变量的作用。flag被称之为标志变量,这种用法是很常见的一个编程技巧。程序代码的改进,同学们自己完成。5个学生,5门课程,求每个学生的5门课程的平均成绩,求每门课程的5个同学的平均成绩,如何处理? int stu15,stu25,stu45;思考:求每门课程的平均成绩遇到什么问题? 二维数组问题的提出多维数组数组可以有任意维数。下面的声明产生了一个二维数组(或者按数学概念称为矩阵matrix):int m59;m有5行9列。数组的行和列下标都是从0开始索引:
27、50多维数组为了存取数组i行j列的元素,需要写成mij的形式。表达式mi指明了数组m的第i行,mij才是选择了此行中的第j个元素。抵制把mij替换写成mi,j的诱惑。在此处,C语言把逗号看成是逗号运算符,所以mi,j等同于 mj。51多维数组虽然以表格形式显示二维数组,但是实际上它们在计算机的内存中不是这样存储的。C语言是按照行主序存储数组的,也就是从第0行开始,接着第1行,如此下去。下面显示了数组m是如何存储的:52多维数组嵌套的for循环是处理多维数组的理想选择。考虑用作单位矩阵(identity matrix)的数组的初始化问题。一对嵌套的for循环可以很好地完成这项工作:#define
28、 N 10double identNN;int row, col;for (row = 0; row N; row+) for (col = 0; col N; col+) if (row = col) identrowcol = 1.0; else identrowcol = 0.0;53多维数组初始化通过嵌套一维初始化式的方法可以产生二维数组的初始化式:int m59 = 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1,
29、 1, 0, 1, 0, 0, 1, 1, 1;构造高维数组的初始化式采用类似的方法。54多维数组初始化如果初始化式不大到足以填满整个多维数组,那么把数组中剩余的元素赋值为0。下面的初始化式只填满了数组m的前三行;后边的两行将赋值为0:int m59 = 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0;55多维数组初始化如果内层的列表不大到足以填满数组的一行,那么把此行剩余的元素初始化为0:int m59 = 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1
30、, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1;56多维数组初始化甚至可以忽略掉内层的大括号:int m59 = 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1;因为一旦编译器发现足够的数值填满一行,它就开始填充下一行。在多维数组中忽略掉内层的大括号可
31、能是很危险的,因为额外的元素(或者甚至更糟的是丢失的元素)将会影响剩下的初始化式。57多维数组初始化C99的指定初始化式对多维数组也有效。例如:可以这样创建 2 2 的单位矩阵:double ident22 = 00 = 1.0, 11 = 1.0;像通常一样,没有指定值的元素都默认置为0。58常量数组无论一维数组还是多维数组,可以通过把单词const作为数组声明开始这种方法,将任何数组变为“常量”:const char hex_chars = 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F;程序不应该对声明为const的数组进行修改。59常量数组
32、声明数组是const的好处:它表明程序不会改变数组。对编译器发现错误也很有帮助。Const的使用不仅限于数组,但用于定义数组是特别有用的。60程序:发牌程序deal.c说明了二维数组和常量数组的用法。程序负责随机发一副标准纸牌。标准纸牌的花色有梅花、方块、红桃或黑桃(clubs, diamonds, hearts, or spades) ,而且纸牌的等级有2, 3, 4, 5, 6, 7, 8, 9, 10, J, Q, K或A)。61程序:发牌程序需要用户指明手里应该握有几张牌:Enter number of cards in hand: 5Your hand: 7c 2s 5d as 2h
33、需要解决的问题有:如何从一副牌中随机抽取纸牌?如何避免两次抽到同一张牌?62程序:发牌为了随机抽取纸牌,可以采用一些C语言的库函数:time (来自于) 返回当前的时间,且这个时间是被编码成单独的数。srand (来自于) 初始化C语言的随机数生成器。rand (来自于) 在每次调用时会产生一个明显随机的数。通过采用运算符%,可以标量来自rand函数的返回值,这样可以使得这个值落在03(为了表示牌的花色)的范围内,或者是落在012(为了表示纸牌的等级)的范围内。63程序:发牌程序中采用一个二维数组in_hand来跟踪已经选择好的牌。数组有4行(每行表示一种纸牌的花色)和13列(每一列表示纸牌的
34、一种等级)。在程序开始时,所有数组元素都将为0(假)。每次随机抽取一张纸牌时,将检查数组in_hand的元素与此牌是否相对应,对应就为真,不对应则为假。如果判定结果为真,那么就需要抽取其他纸牌;如果判定结果为假,则将把数值1(真)存储到与此张纸牌相对应的数组元素中,这样做是为了以后提醒此张纸牌已经抽取过了。64程序:发牌一旦证实纸牌是“新”的,也就是说还没有选取过此张纸牌,就需要把牌的等级和花色数值翻译成字符,然后显示出来。为了把纸牌的等级和花色翻译成字符格式,程序将设置两个字符数组,一个用于纸牌的等级,而另一个用于纸牌的花色,然后利用数对数组进行下标。这两个字符数组在程序执行期间不会发生改变,所以可以把它们声明为const。65deal.c/* Deals a random hand of cards */#include /* C99 only */#include #include #include #define NUM_SUITS 4#define NUM_RANKS 13int main(void) bool in_handNUM_SUITSNUM_RANKS = false; int num_cards, r
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 线槽标准施工方案(3篇)
- 基建类财务管理制度(3篇)
- 执法部门因管理制度(3篇)
- 2026北京人民邮电出版社校园招聘备考考试题库及答案解析
- 护理信息技术应用实训课件
- 2026湖北荆州市荆州区事业单位人才引进57人备考考试题库及答案解析
- 2026广东珠海市妇幼保健院(珠海市妇女儿童医院)、华南理工大学附属珠海妇儿医院面向应届毕业生招聘事业单位人员2人备考考试试题及答案解析
- 2026贵州贵阳市息烽县卫生健康局公益性岗位招聘2人参考考试题库及答案解析
- 右手机器绞伤的紧急处理方法
- 2026福建福州市水路运输应急保障中心编外人员招聘1人参考考试题库及答案解析
- 2025四川省土地租赁合同范本
- GB/T 5709-2025纺织品非织造布术语
- 光伏发电项目风险
- 企业微信使用手册
- 绿化养护验收实施方案1
- 2024年理财行业高质量发展白皮书-农银理财
- 危险化学品经营单位(安全生产管理人员)考试题及答案
- UL498标准中文版-2019插头插座UL标准中文版
- 《非物质文化遗产》课程教学大纲
- 小学英语名师工作室工作总结
- 居民自建桩安装告知书回执
评论
0/150
提交评论