940 likes | 1.06k Views
第四章 简单构造数据类型. 短整型 short int. 整型 int. 整型. 长整型 long int. 单精度 float. 实型. 基本类型. 双精度 double. 字符型 char. 数组类型. C 数据类型. 结构体类型. 构造类型. 共用体类型. 枚举型. 指针类型. 空类型. 引例:输入全班 30 名同学的成绩,求平均分,并将 30 名同学的成绩由高到低排序。. for(i=1;i<=30;i++) {scanf(“%f”,&x); s=s+x; } aver=s/30;.
E N D
短整型 short int 整型int 整型 长整型 long int 单精度 float 实型 基本类型 双精度 double 字符型 char 数组类型 C数据类型 结构体类型 构造类型 共用体类型 枚举型 指针类型 空类型
引例:输入全班30名同学的成绩,求平均分,并将30名同学的成绩由高到低排序。引例:输入全班30名同学的成绩,求平均分,并将30名同学的成绩由高到低排序。 for(i=1;i<=30;i++) {scanf(“%f”,&x); s=s+x; } aver=s/30; • 问题:30名同学的成绩没有同时保留下来,无法进行排序。 • 一批变量的特点:类型相同(float),意义相同(成绩)
数组的概念和含义 数组是一批具有相同数据类型的变量的集合。 例:float score[30]; 数组的特点 • 数组各元素在内存中的存储单元是连续的。 • 数组元素通常批量操作。
4.1 一维数组 4.2 二维数组 4.3 字符数组 4.4 数组与指针 4.5 数组及指针作为函数参数 目录
一、定义和使用: 1、定义形式: 数据类型 数组名[元素个数] int a[10]; float b[6]; char c[10];
2、元素引用: × 数组元素的下标从0开始。例如:int a[5]; 其元素的表示为a[0]、 a[1]、 a[2]、 a[3]、 a[4]。 如果用a[5]则是错误的。
3、补充说明: ①、数组名由用户定义,命名规则和变量名相同。 ②、元素个数为常量表达式而不能是变量表达式。 如下错误:int n; scanf(“%d”,&n); int a[n]; ③、每一个元素相当于一个变量。
数组类型的编程,通常和循环程序紧密联系在一起。数组类型的编程,通常和循环程序紧密联系在一起。 例:输入10个数,求它们的和。 用数组类型来解决。 二、数组的编程使用特色
总结: 1、循环变量的起始和终值; 2、循环中元素的表达。 例:输入10个数,求它们的和。 main() {int a[10]; int i,s=0; for(i=0;i<=9;i++) {printf(“enter %d number:”,i+1); scanf(“%d”,&a[i]); s=s+a[i]; } printf(“the total is %d:”,s); } 或 i<10
注意:对下标的引用不要超过下标的最大值。尽管超过最大值时不出现编译错误,但数组越界,取的是下一个单元的值,这个单元有可能存放的是其它的变量值,运算结果错误,甚至出现严重错误。
学生练习 定义一个长度为5的一维整型数组,将一个5位数的各个位存入该一维数组中,然后将各个位数逆序输出。 例:一个5位数为12345,将其各个位数求出来,并依次存入数组各元素中后,将各元素逆序输出,结果应该为54321。要求该数应由用户从键盘上输入。 编程提示: 1、数据类型的准备 2、算法的设计:输入数据→循环结构求取位数并存入数组中→循环结构输出数组中各元素值。 3、如何求取各个位数?
main() { } int x, a[5], i; printf(“enter a 5 bits number:”); scanf(“%d”,&x); for(i=0;i<=4;i++) { } a[i]=x%10; x=x/10; for(i=4;i>=0;i++) printf(“the revert number is:”,a[i]);
三、一维数组初始化:在程序运行之前,使数组各下标变量有一个初值。三、一维数组初始化:在程序运行之前,使数组各下标变量有一个初值。 1、在数组定义的同时对数组元素初始化。 int a[5]={1,2,3,4,5}; 2、可以仅对一部分下标元素赋初值。 如:static int a[5]={1,2,3}; 如果不对某些下标元素赋初值,则对于数值型元素初值均为0,对于字符型元素均为空操作符’\0’. 3、如果想对所有的元素全部赋初值,可以省略定义元素个数。如:static int aa[ ]={1,2,3,4,5};
四、一维数组程序举例 题目:对输入到数组中的6个整数升序排序。 1、最原始的排序算法——比较法。 38 23 17 78 6 1 从数组的第一个元素开始,依次和后面的元素比较,如果比当前元素值小则互换值。 1: 6 38 23 78 17 17 38 23 78 1 38 23 78 17 6 23 38 17 38 23 2: 1 6 38 78 23 17 3: 1 617 78 38 23 4: 1 617 23 78 38 5: 1 617 2338 78
main() { int a[6],i,j,t; printf("Please input 6 numbers :\n"); for (i=0;i<6;i++) scanf("%d",&a[i]); for (i=0;i<5;i++) { for (j=i+1;j<6;j++) { if (a[i]>a[j]) { t=a[i]; a[i]=a[j]; a[j]=t; } } } for (i=0;i<6;i++) printf("%d ",a[i]); } 比较法排序算法简单易于实现,但是算法执行效率低,排序过程中有多次数据交换的操作。
2、冒泡排序法 38 23 17 17 6 1 23 17 23 6 1 6 17 38 6 1 17 17 78 6 1 23 23 23 6 1 38 38 38 38 1 78 78 78 78 78
思想:将相邻两个数比较,将小的调到前头。 每趟比较,小数上升,大数下沉。 如果有n个数,就要进行n-1趟比较。 17 1 23 6 38 78 第二趟 1 17 6 23 38 78 第三趟 1 6 17 23 38 78 第四趟 1 6 17 23 38 78 第五趟 17 23 38 1 78 6 初始 17 23 1 38 6 78 第一趟
main() { int a[6],i,j,t; printf("Please input 6 numbers :\n"); for (i=0;i<6;i++) scanf("%d",&a[i]); for (i=0;i<5;i++) { for (j=0;j<5-i;j++) { if (a[j]>a[j+1]) { t=a[j]; a[j]=a[j+1]; a[j+1]=t; } } } for (i=0;i<6;i++) printf("%d ",a[i]); } 冒泡法排序比较和交换数据次数减少,算法执行效率有所提高。
选择法排序,每轮比较后只交换一次数据,因此算法执行效率最高。选择法排序,每轮比较后只交换一次数据,因此算法执行效率最高。 3、自学:选择法排序 分析:设min为每轮比较的最小值元素的下标值, 第一轮先假设a[0]为最小值,min=0;用a[min]和a[1],a[2],…,a[n-1]比较,出现比a[min]小的值,让min=j;比较完毕,a[min]为第一轮最小值,将a[0]与a[min]互换,此时a[0]里存放最小值。 第二轮假设a[1]为最小值,min=1;用a[min]和a[2],…,a[n-1]比较,出现比a[min]小的值,让min=j;比较完毕,a[min]为第二轮最小值,将a[1]与a[min]互换,此时a[1]里存放次小值。 重复以上操作。外循环为n-1次,内循环比较n-i次.
问题引出: 如果统计全班同学总分,并求总分最高者。假设全班40名同学成绩,而每个同学的成绩共有6门课,那么怎么定义数组呢? 此处应定义为二维数组:第一维表示班级人数,第二维表示每人共有6门课成绩,定义形式如下: float score[40][6]; 总结:二维数组由两个[ ]组成,前面为第一维,后面为第二维。
提问: 二维数组各元素如何表达? score[0][0]、 score[0][1]、……、 score[0][5]、 score[1][0]、 score[1][1]、……、 score[1][5]、 …… score[39][0]、 score[39][1]、……、 score[39][5] 共有40×6=240个元素
提问: 二维数组各元素在内存中如何存储? 按照先行后列的顺序,如下: score[0][0]、 score[0][1]、……、 score[0][5]、 score[1][0]、 score[1][1]、……、 score[1][5]、 …… score[39][0]、 score[39][1]、……、 score[39][5]
main() { float s[40][6],sum[40],x,max; int i,j; max=0; for(i=0;i<40;i++) { printf("input three course score of student%d\n:",i+1); x=0; for(j=0;j<6;j++) { printf("course1 is:"); scanf("%f",&s[i][j]); x=x+s[i][j]; } sum[i]=x; if(sum[i]>max) max=sum[i]; } for(i=0;i<40;i++) printf("student%d is %.f\n",i+1,sum[i]); } 程序4-5.c 编程方法总结: 二维数组的编程通常用循环嵌套来解决,外循环由数组的一维长度控制,内循环由数组的二维长度控制,依次遍历数组各元素。
二维数组定义格式 类型 数组名[行数][列数]; 如:int aa[2][3]; 表示整型数组aa共2行,每行3列,共2×3=6个下标元素,每一个元素相当于一个整型变量。 二维数组通常用于处理矩阵问题
二维数组元素的引用: • aa[行号][列号] • 行号和列号都是从0开始的,并注意行号和列号不要超过数组定义的范围。 • 二维数组在内存中,是按行存放的。数组的存储是按先行后列的顺序,各个元素的存储顺序:aa[0][0],aa[0][1],aa[0][2],aa[1][0],aa[1][1],aa[1][2]。 • 每行相当于一个一维数组,如上例相当于由2个一维数组组成。
二维数组元素的初始化 • 1、按行给二维数组赋初值。 • 如:static int aa[2][3]={{0,0,1},{1,0,0}}; • 2、也可以把数值写在一块: • static int aa[2][3]={0,0,1,1,0,0} • 则 • aa[0][0]=0, aa[0][1]=0, aa[0][2]=1, • aa[1][0]=1, aa[1][1]=0, aa[1][2]=0,
3、给部分下标变量赋初值,其它的元素值默认为0,3、给部分下标变量赋初值,其它的元素值默认为0, • 如:static int a[4][5]={{1,2},{ },{0,1,3}} • 则各值为:1 2 0 0 0 • 0 0 0 0 0 • 0 1 3 0 0 • 0 0 0 0 0 • 说明:a.一行中的最后几列元素赋初值为0,这些元素可省。 • b.一行中的前一列或n列元素赋初值为0,这些元素不能省。 • c.一整行元素都赋初值0,若该行是最后一行,整行 • 的赋值可省。如不是最后一行,则必须用一个空大 • 括号表示。
如果对二维数组的所有元素都赋值,则数组的第一维可以省略。如果对二维数组的所有元素都赋值,则数组的第一维可以省略。 • 如:int m[ ][3]={1,2,3,4,5,6,7,8,9};则默认的第一维的值是3。 • 如仅对部分元素赋初值,要想省略数组的行数,则必须分行赋值,如: • static int a[ ][5]={{1,2},{ },{0,1,3}} 建议使用分行赋值的方法。
牢记 二维数组的编程特点:使用双重循环,外循环控制“行”,内循环控制“列”。
四、二维数组程序举例: 1、对以下矩阵进行转置: 1 2 3 4 5 6 7 8 9 10 11 12 说明:该矩阵是非对称矩阵,所以利用两个二维数组进行存储原矩阵和转置矩阵。 源程序4-8.c • 1 5 9 • 2 6 10 • 7 11 • 8 12
2、P84页例5.5:有四个学生,每个学生学3门课程,已知所有学生的各门课成绩,分别求每门课的平均成绩和每个学生的平均成绩。2、P84页例5.5:有四个学生,每个学生学3门课程,已知所有学生的各门课成绩,分别求每门课的平均成绩和每个学生的平均成绩。 cour1 cour2 cour3 stu1 78 86 92 stu2 62 73 65 stu3 90 93 95 stu4 82 73 86 源程序4-7.c
重点内容回顾 • 一维数组定义:int a[10]; • 数组下标:从0到N-1; • 元素按顺序存放。 • 常用循环操纵: • for(i=0;i<N;i++)
二维数组定义:int a[3][10]; • 元素按先行后列的顺序存放。 • 常用循环操纵: • for(i=0;i<N;i++) • for(j=0;j<M;j++)
4.3.1 字符数组的引出 字符数组主要是用于处理字符串信息的。 C语言中没有字符串类型,只有char单字符类型。如果存放并处理一个字符串(由多个字符组成的字符序列)信息,就需要定义字符数组。 字符数组中每一个元素存放一个字符信息,若干个元素的信息连在一起就表达了一串字符序列,通常就是字符串。 在实际使用使许多数据都是字符型的,如姓名、单位、用户名、密码、英文单词、简介等。
1、定义格式: char 数组名[字符个数]; 回忆字符串常量的特点:“China” 末尾有一个系统自动加上的‘\0’结束标记,因此存储时占用的实际字节数是6个。 注意:字符串数据的特点: 实际存储的字符个数通常是实际字符数+1。这是在定义时需要考虑的特征。
char 数组名[字符个数]; 思考一个问题:实际输入时,输入字符串长度可能不固定,怎么定义数组的长度呢? 考虑实际可能的最大长度,尽量定义的长度大些,如50、80、100等,防止丢失部分数据。
字符数组初始化; char s[6]={‘C’,”h’,’i’,’n’,’a’,’\0} char s[6]=“China”; 思考以下两种初始化形式有什么不同?char s[ ]=“China”; char s[ ]={‘C’,”h’,’i’,’n’,’a’} 后一种是普通的字符数组,其中存放的字符序列不能作为一个字符串对待,因为没有‘\0’结束标记。
注意:一个字符数组存放的一串字符型数据,只有当它末尾有‘\0’时才能称之为字符串。否则只能是普通的字符数组,里面的数据不能成串的使用,也不能使用字符串操作函数,例如gets()、puts()注意:一个字符数组存放的一串字符型数据,只有当它末尾有‘\0’时才能称之为字符串。否则只能是普通的字符数组,里面的数据不能成串的使用,也不能使用字符串操作函数,例如gets()、puts()
有许多专门的字符串操作函数。 • 字符串的整体输入/输出函数:gets(a)、puts(a) • 字符串比较是否相等的函数:strcmp(a,b); • 字符串拷贝或整体赋值函数:strcpy(a,”name”); 注意:字符数组不能定义后整体赋值,如下是错误的:char s[10]; s=“China” × 正确的赋值方法:strcpy(s,”China”); √
[例4.7] 用户预先设置一个N位长度的密码,密码由数字、字母、符号等组成。当计算机开机时要求用户输入密码。3次之内,按用户输入的密码正确与否,输出“欢迎!”、“密码错误!”;超过3次后输出“退出!”。
[分析] 解决这个问题,首先要预设一个长度为N的密码,一个密码为一串的字符,这样就需要定义字符数组来存放这些字符串信息。 那么定义的字符数组长度多大呢? 考虑到字符串还有一个结束标记,也需要占据一个字节的存储空间。因此字符数组的长度需要定义成N+1。
[程序设计过程解析] 用户预先设置一个N位长度的密码,密码由数字、字母、符号等组成。当计算机开机时要求用户输入密码。3次之内,按用户输入的密码正确与否,输出“欢迎!”、“密码错误!”;超过3次后输出“退出!”。 1、定义数组并初始化密码字符串。 2、让用户输入密码字符串。 3、判断两个串是否相等(双分支) 4、循环输入,因此应从步骤2前设置循环,并记录循环次数,当出错3次,结束程序运行。
观察程序,回答如下问题: 1、字符数组的定义及如何赋初始字符串值? 2、新字符串的值是怎样输入的? 3、两个字符串是如何比较相等或不等的。? 4、循环次数的累加和判断位置在哪里?
注意:一个字符数组存放的一串字符型数据,只有当它末尾有‘\0’时才能称之为字符串。否则只能是普通的字符数组,里面的数据不能成串的使用,也不能使用字符串操作函数,例如gets()、puts()注意:一个字符数组存放的一串字符型数据,只有当它末尾有‘\0’时才能称之为字符串。否则只能是普通的字符数组,里面的数据不能成串的使用,也不能使用字符串操作函数,例如gets()、puts()
字符数组与普通数值型数组的使用区别: • 定义时长度控制不同。 • char ch[100]; int a[15]; • 2. 赋初值的形式不同: • char ch[100]=“china”; • int a[15]={1,2,3,6,5}; • 3. 输入/输出数据不同 • gets(ch); puts(ch); (整体操作) • 或scanf(“%s”,ch); printf(“%s”,ch); • for(i=0;i<15;i++) scanf(“%d”,&a[i]); • (单个操作)
4. 循环控制不同。 for(i=0;ch[i]!=‘\0’;i++) …… for(i=0;i<n;i++) …… 5. 数组赋值不同。 字符数组:strcpy(str1,str2); 整型数组不能整体赋值,只能用循环逐个赋值:for(i=0;i<n;i++) b[i]=a[i];