1
第七章 数 组本章内容
1.数组概述
2.一维数组的定义和引用
3.二维数组的定义和引用
4.字符数组的定义和引用
2
在程序设计中,为了处理方便,把具有相同类型的若干变量按有序的形式组织起来 。 这些按序排列的同类数据元素的集合称为数组 。
在C语言中,数组属于构造数据类型 。
一个数组可以分解为多个数组元素,这些数组元素可以是基本数据类型或是构造类型 。
按数组元素的类型不同,数组又可分为数值数组,字符数组,指针数组,结构数组等各种类别 。
概 述
3
一维数组的定义和引用一维数组定义
一般形式为:
类型说明符 数组名 [常量表达式 ],……;
其中,类型说明符是任一种基本数据类型或构造数据类型,
数组名是用户定义的数组标识符;方括号中的常量表达式表示数据元素的个数,也称为数组的长度 。
例如:
int a[10]; 说明整型数组 a,有 10个元素 。
float b[10]; 说明实型数组 b,有 10个元素 。
char ch[20]; 说明字符数组 ch,有 20个元素。
4
1,C语言中规定数组的下标从 0开始,方括号中常量表达式表示数组元素的个数 。
例如,int a[5]表示数组 a有 5个元素 。 因下标从 0开始计算 。 因此 5个元素分别为 a[0],a[1],a[2],a[3],a[4]。
2,数组的类型实际上是指数组元素的取值类型 。 对于同一个数组,其所有元素的数据类型都是相同的 。
3,数组名的书写规则应符合标识符的书写规定 。
说 明:
5
4,数组名不能与其它变量名相同,例如:
void main()
{ int a;
float a[10];
……} 是错误的。
5,允许在同一个类型说明中,说明多个数组和多个变量。
例如,int a,b,c,d,k1[10],k2[20] ;
说 明:
6
6,不能在方括号中用变量来表示元素的个数,但可以是符号常数或常量表达式。
下述说明方式是合法的:
#define FD 5
main()
{ int a[3+2],b[7+FD];
……}
下述说明方式是错误的,
main()
{ int n=5;
int a[n];
…… }
说 明:
7
数组元素是组成数组的基本单元 。
数组元素也是一种变量,其标识方法为数组名后跟一个下标,下标表示了元素在数组中的顺序号 。
数组元素一般引用形式为,数组名 [下标 ]
其中的下标只能为整型常量或整型表达式 。
例如,a[5],a[i+j],a[i++] 都是合法的数组元素 。
一维数组元素的引用
8
注意:C语言中只能通过下标变量使用数组元素,而不能一次引用整个数组。
例如,输出有 10个元素的数组必须使用循环语句逐个输出各下标变量:
for(i=0; i<10; i++) printf("%d",a[i]);
而不能用一个语句输出整个数组,下面的写法是错误的:
printf("%d",a);
一维数组元素的引用
9
数组初始化赋值是指在数组定义时给数组元素赋予初值 。
数组初始化是在编译阶段进行的 。 这样将减少运行时间,提高效率 。
数组初始化的一般形式为:
类型说明符 数组名 [常量表达式 ]={值,值 ……值 };
其中,在 { }中的各数据值即为各元素的初值,各值之间用逗号间隔 。
例如,int a[10]={ 0,1,2,3,4,5,6,7,8,9 };
相当于 a[0]=0; a[1]=1;..,a[9]=9;
一维数组初始化赋值
10
1,可以只给部分元素赋初值 。
当 { }中值的个数少于元素个数,只给前面部分元素赋值 。
例如,int a[10]={0,1,2,3,4};
表示只给 a[0]~ a[4]5个元素赋值,而后 5个元素自动赋 0值 。
2,如给全部元素赋值,则在数组定义中,可以不给出数组元素的个数 。
例如,int a[5]={1,2,3,4,5};
可写为,int a[ ]={1,2,3,4,5};
C语言对数组的初始赋值的几点规定:
11
3,当 { }中值的个数多于元素个数时,系统出错。
4,只能给元素逐个赋值,不能给数组整体赋值。
例如给十个元素全部赋 0值,只能写为:
int a[10]={0,0,0,0,0,0,0,0,0,0};
或者 int a[10]={0};
而不能写为,int a[10]=0;×
C语言对数组的初始赋值的几点规定:
12
冒泡法排序的 算法思想:
(将相邻两个数比较,小的调到前头 )
1) 有 n个数 ( 存放在数组 a[n]中 ),第一趟将每相邻两个数比较,小的调到前头,经 n-1次两两相邻比较后,
最大的数已,沉底,,放在最后一个位置,小数上升
,浮起,;
2) 第二趟对余下的 n-1个数 ( 最大的数已,沉底,)
按上法比较,经 n-2次两两相邻比较后得次大的数;
3) 依次类推,n个数共进行 n-1趟比较,在第 j趟中要进行 n-j次两两比较 。
一维数组程序举例从键盘上任意输入 10个整数,要求按从小到大输出。
13
原始数据 8 6 9 3 2 7
第 1趟交换后 6 8 9 3 2 7
第 2趟交换后 6 8 9 2 3 7
第 3趟交换后 6 8 2 9 3 7
第 4趟交换后 6 8 2 3 9 7
第 5趟无交换 6 8 2 3 7 9
一次冒泡过程
14
冒泡法排序
main()
{ int i,j,temp,data[11];
printf("Please input 10 numbers:\n");
for(i=1; i<11; i++) scanf("%d",&data[i]);
for(i=1; i<=9; i++) /*外循环:控制比较趟数 */
for(j=1; j<=10-i; j++) /*内循环:进行每趟比较 */
if(data[j]>data[j+1])
{temp=data[j]; data[j]=data[j+1]; data[j+1]=temp;};
for(i=1; i<11; i++)
printf("%d ",data[i]);
}
15
选择法排序的算法思想:
1)对有 n个数的序列(存放在数组 a(n)中),从中选出最小(升序)或最大(降序)的数,与第 1个数交换位置;
2)除第 1 个数外,其余 n-1个数中选最小或最大的数,与第 2个数交换位置;
3)依次类推,选择了 n-1次后,这个数列已按升序排列。
选择法排序
16
17
main()
{ int i,j,p,s,a[11];
printf("\n input 10 numbers:\n");
for(i=1;i<11;i++) scanf("%d",&a[i]);
for(i=1;i<10;i++)
{ p=i;
for(j=i+1;j<11;j++)
if(a[p]<a[j]) p=j;
if(i!=p)
{s=a[i]; a[i]=a[p]; a[p]=s; }
}
for(i=1; i<11; i++) printf("%d ",a[i]);
}
选择法排序
18
二维数组类型说明二维数组说明的一般形式是:
类型说明符 数组名 [常量表达式 1][常量表达式 2]…;
其中常量表达式 1表示第一维下标的长度,常量表达式 2
表示第二维下标的长度 。
例如,int a[3][4];
定义了一个 3行 4列的数组,数组名为 a,其下标变量的类型为整型 。 该数组的下标变量共有 3× 4个,即:
a[0][0],a[0][1],a[0][2],a[0][3]
a[1][0],a[1][1],a[1][2],a[1][3]
a[2][0],a[2][1],a[2][2],a[2][3]
二维数组
19
从 C语言二维数组的定义可以看出,一个二维数组也可以分解为多个一维数组 。
C语言允许这种分解,二维数组 a[3][4]可分解为三个一维数组,
其数组名分别为 a[0],a[1],a[2]。
对这三个一维数组不需另作说明即可使用 。
这三个一维数组都有 4个元素 。
例如:一维数组 a[0]的元素为 a[0][0],a[0][1],a[0][2],a[0][3]。
即,a[0][0],a[0][1],a[0][2],a[0][3]
a[1][0],a[1][1],a[1][2],a[1][3]
a[2][0],a[2][1],a[2][2],a[2][3]
说 明:
20
数组在内存中是连续存放的 ;
二维数组是按行排列的,即按行顺次存放,先存放 a[0]
行,再存放 a[1]行,最后存放 a[2]行。
每行中有四个元素也是依次存放。
由于数组 a说明为 int类型,该类型占两个字节的内存空间,所以每个元素均占有两个字节。
注 意:
21
二维数组的元素的引用形式为:
数组名 [下标 ][下标 ]
其中下标应为整型常量或整型表达式 。
例如,a[3][4]表示 a数组的第三行第四列元素 。
下标变量和数组说明在形式中有些相似,但这两者具有完全不同的含义 。
数组说明的方括号中给出的是某一维的长度;而数组元素中的下标是该元素在数组中的位置标识 。 前者只能是常量,
后者可以是常量,变量或表达式 。
例如,int a[3][4]; a[3][4]=10;
二维数组元素的引用
22
一个学习小组有 5个人,每个人有三门课的考试成绩 。
求全组分科的平均成绩和各科总平均成绩 。
姓名 三门课程成绩张 80 75 92
王 61 65 71
李 59 63 70
赵 85 87 90
周 76 77 85
可设一个二维数组 a[5][3]存放五个人三门课的成绩;
再设一个一维数组 v[3]存放所求得各分科平均成绩;
设变量 l为全组各科总平均成绩 。
程序举例
23
main()
{ int i,j,s=0,l,v[3],a[5][3];
for(i=0;i<3;i++)
{ s=0;
for(j=0;j<5;j++)
{ scanf("%d",&a[j][i]);
s=s+a[j][i];}
v[i]=s/5; }
l=(v[0]+v[1]+v[2])/3;
printf("math:%d\nlanguag:%d\ndbase:%d\n",v[0],v[1],v[2]);
printf("total:%d\n",l);
}
程序如下:
24
二维数组初始化是在类型说明时给各下标变量赋以初值 。
二维数组可按行分段赋值,也可按行连续赋值 。
1.按行分段赋值可写为
int[4][3]={{80,75,92},{61,65,71},{59,63,70},{85,87,90}};
2.按行连续赋值可写为
int a[4][3]={80,75,92,61,65,71,59,63,70,85,87,90};
这两种赋初值的结果是完全相同的 。
二维数组的初始化
25
main()
{ int i,j,s=0,l,v[3];
int a[5][3]={ {80,75,92},{61,65,71},{59,63,70},
{85,87,90},{76,77,85} };
for(i=0;i<3;i++)
{ for(j=0;j<5;j++)
s=s+a[j][i];
v[i]=s/5;
s=0;
}
l=(v[0]+v[1]+v[2])/3;
printf("math:%d\nc,%d\ndbase:%d\n",v[0],v[1],v[2]);
printf("total:%d\n",l);
}
程序示例:
26
1.可以只对部分元素赋初值,未赋初值的元素自动取 0值 。
例如,int a[3][3]={{1},{2},{3}}; 是对每一行的第一列元素赋值,未赋值的元素取 0值 。
1 0 0
2 0 0
3 0 0
0 1 0
0 2 0
0 0 3
2.如对全部元素赋初值,则第一维的长度可以不给出 。
例如,int a[3][3]={1,2,3,4,5,6,7,8,9}; 可以写为:
int a[ ][3]={1,2,3,4,5,6,7,8,9};
而,int a [3][3]={{0,1},{0,2,0},{0,0,3}};
赋值后的元素如右图二维数组初始化赋值说明,
27
二维数组程序举例
main()
{ int i,j,row=0,colum=0,max;
int a[3][4]={{1,2,3,4},{9,8,7,6},{-10,15,-5,2}};
max=a[0][0];
for(i=0;i<3;i++)
for(j=0;j<4;j++)
if (a[i][j]>max)
{ max=a[i][j];row=i;colum=j;}
printf("max=%d,row=%d,colum=%d\n",max,row,colum);
}
1 2 3 4
9 8 7 6
-10 15 -5 2求数组中最大元素及它所在的行号和列号
28
用来存放字符量的数组称为字符数组。
字符数组字符数组的定义字符数组类型说明的形式与前面介绍的数值数组相同。
例如,char c[10]; 定义有 10个元素的数组例如,char ch[5][10]; 即为 5*10 的二维字符数组。
29
字符数组可在定义时作初始化赋值。
例如,char c[10]={?c?,,?p?,?r?,?o?,?g?,?r?,?a?,?m?};
赋值后各元素的值为对应字符,其中 c[9]未赋值,由系统自动赋予为空字符 ‘ \0?值。
当对全体元素赋初值时也可以省去长度说明。
又如,char a[ ][5]={{'B','A','S','I','C',},{'d','B','A','S','E'}};
字符数组的初始化
30
main()
{ int i,j;
char a[ ][5]={{'B','A','S','I','C',},{'d','B','A','S','E'}};
for(i=0;i<=1;i++)
{
for(j=0;j<=4;j++)
printf("%c",a[i][j]);
printf("\n");
}
}
字符数组的引用
31
在C语言中没有专门的字符串变量,通常用一个字符数组来存放一个字符串 。
在介绍字符串常量时,已说明字符串总是以 '\0'作为串的结束符 。
因此当把一个字符串存入一个数组时,也把结束符 '\0'存入数组,并以此作为该字符串是否结束的标志 。
有了 '\0'标志后,就不必再用字符数组的长度来判断字符串的长度了 。
字符串和字符串结束标志
32
C语言允许用字符串的方式对数组作初始化赋值。
例如:
char c[ ]={'C',' ','p','r','o','g','r','a','m'};
可写为,char c[ ]={“C program”};
或写为,char c[ ]="C program";
C p r o g a m \0
数组在内存中存放情况字符串和字符串结束标志
33
由于采用了 ‘ \0?标志,所以在用字符串赋初值时一般无须指定数组的长度,而由系统自行处理 。
在采用字符串方式后,字符数组的输入输出将变得简单方便 。
除了上述用字符串赋初值的办法外,还可用 printf函数和
scanf函数中使用,%S”格式控制符一次性输出 /输入一个字符数组中的字符串,而不必使用循环语句逐个地输入输出每个字符 。
字符数组的输入输出
34
注意在本例的 printf函数中,使用的格式字符串为 %s,
表示输出的是一个字符串。
在输出表列中给出数组名则可。
不能写为,printf("%s",c[ ]);
示 例:
main()
{
char c[ ]="BASIC\ndBASE";
printf("%s\n",c);
}
35
main()
{ char st[15];
printf("input string:\n");
scanf("%s",st);
printf("%s\n",st);
}
示 例:
本例中由于定义数组长度为 15,因此输入的字符串长度必须小于等于 15,以留出一个字节用于存放字符串结束标志 `\0`。
应该说明的是,对一个字符数组,如果不作初始化赋值,则必须说明数组长度。
36
还应该特别注意的是,当用 scanf函数输入字符串时,字符串中不能含有空格,否则将以空格作为串的结束符。
例如上例,当输入,this is a book的字符串时,则只有
this 输入到数组 st中。
为了避免这种情况,可多设几个字符数组分段存放含空格的串。
37
本程序分别设了四个数组,输入的一行字符的空格分段分别装入四个数组 。 然后分别输出这四个数组中的字符串 。
程序可改写如下:
main()
{ char st1[6],st2[6],st3[6],st4[6];
printf("input string:\n");
scanf("%s%s%s%s",st1,st2,st3,st4);
printf("%s %s %s %s\n",st1,st2,st3,st4);
}
38
在前面介绍过,scanf的各输入项必须以地址方式出现,
如 &a,&b等。
但在上例中却是以数组名方式出现的,这是为什么呢?
这是由于在C语言中规定,数组名就代表了该数组的首地址。
在执行函数 printf(“%s”,c) 时,按数组名 c找到首地址,
然后逐个输出数组中各个字符直到遇到字符串终止标志
‘ \0’为止 。
注 意:
39
C语言提供了丰富的字符串处理函数,它们可分为字符串的输入,输出,合并,修改,比较,转换,复制,搜索几类 。 使用这些函数可大大减化字符处理的编程 。
用于输入输出的字符串函数,在使用前应包含头文件
"stdio.h" ;
使用其它字符串函数则应包含头文件 "string.h"。
字符串常用函数
40
1.字符串输出函数 puts
Str为数组名或指针变量格式,puts (str) ;
功能:把字符数组中字符串输出到显示器 。
它等价于,printf("%s",str);
#include"stdio.h"
main()
{ char c[ ]="BASIC\ndBASE";
puts(c);
} 等价于:
printf("%s",c);
41
格式,gets (str); Str为数组名或指针变量功能:从键盘上输入一个字符串直到回车键结束 。 将输入的字符串加上结束标志 ‘ \0?,存放到数组或字符指针所指向的一片存储单元 。
2.字符串输入函数 gets
42
#include"stdio.h"
main()
{ char st[15];
printf("input string:\n");
gets(st);
puts(st);
}
示例:
说明:当输入的字符串中含有空格时,输出仍为全部字符串。因 gets函数并不以空格作为字符串输入结束的标志,而只以回车作为输入结束。这是与 scanf函数不同的。
43
格式,strcat (str1,str2)
功能:把字符数组 str2中的字符串连接到字符数组 str1 中字符串的后面,并删去字符串 1后的串标志,\0”。 本函数返回值是符数组 1的首地址 。 例:
3.字符串连接函数 strcat
#include"string.h“
#include "stdio.h "
main()
{ char st1[30]="My name is "; char st2[10];
printf("input your name:\n");
gets(st2);
strcat(st1,st2);
puts(st1);}
44
格式,strcpy (str1,str2)
功能:把字符数组 str2中的字符串拷贝到字符数组 str1中 。
串结束标志,\0”也一同拷贝 。 字符数组名 2,也可以是一个字符串常量 。 这时相当于把一个字符串赋予一个字符数组 。
4.字符串拷贝函数 strcpy
本函数要求字符数组 str1应有足够的长度,否则不能全部装入所拷贝的字符串。
例,#include"string.h"
main()
{ char st1[15],st2[]="C Language";
strcpy(st1,st2);
puts(st1);printf("\n");
}
45
格式,strcmp(str1,str2)
功能:按照 ASCII码顺序比较两个数组中的字符串,并由函数返 回值返回比较结果 。
str1= str2,返回值= 0;
str1 > str2,返回值 >0;
str1 < str2,返回值 <0。
本函数也可用于比较两个字符串常量,或比较数组和字符串常量 。
5.字符串比较函数 strcmp
46
格式,strlen(str)
功能:测字符串的实际长度 (不含字符串结束标志 ‘ \0?) 并作为函数返回值 。
例:
#include"string.h"
main()
{ int k;
static char st[ ]="C language";
k=strlen(st);
printf("The lenth of the string is %d\n",k);
}
6.测字符串长度函数 strlen
47
格式,strlwr(str)
功能:将字符串 str中的大写字母转换为小写字母 。
7,字符大写转小写函数 strlwr
8,字符小写转大写函数 strupr
格式,strupr(str)
功能:将字符串 str中的小写字母转换为大写字母。
48
字符数组应用举例统计输入的一行字符中有多少个单词,单词间用空格分隔开。
算法思想:
单词的数目由空格出现的次数决定(连续空格算一个)。
若某一字符为非空格,而它前面的字符为空格,则表示新单词的开始,此时计数器加 1.
若当前字符为非空格而其前面的也是非空格,说明原单词未结束。
用 word来表示前一字符是否为空格。 Word=1表示前一单词为非空格,word= 0表示前一字符为空格。
49
#include "stdio.h"
main()
{char c,string[80];
int i,num=0,word=0;
gets(string);
for(i=0;(c=string[i])!='\0';i++)
if (c == ' ' ) word=0;
else if(word==0)
{ word=1;
num++;}
printf("There are %d word in the line.\n",num);
}
字符数组应用举例
50
作业,P141 7.4 (参考实验指导书实验六第 3题)
7.5 7.10
实验:
实验指导书上机实验之实验五实验要求:
(1)第 3,7题源代码分别命名为 sy5-1.cpp和 sy5-2.cpp上传;
(2)其余题目自行编写代码上机调试。