数组数组在程序设计中,为了处理方便, 把具备相同类型的若干变量按有序的形式组织起来.这些按序排列的同类数据元素的聚集称为数组. 在C语言中, 数组属于构造数据类型.一个数组可以分解为多个数组元素,这些数组元素可以是根本数据类型或是构造类型.因 此按数组元素的类型不同,数组又可分为数值数组、字符数组、指针数组、构造数组等各种种别.
本章介绍数值数组和字符数组,其余的在以后各章陆续介绍.数组类型说明 在C语言中使用数组必须进步行类型说明. 数组说明的一般形
式为: 类型说明符 数组名 [常量表达式],hh; 其中,类型说明符是任一种基本数据类型或构造数据类型. 数组名是用户定义的数组标识符. 方括号中的常量表达式表示数据元素的个数,也称为数组的长度.
例如:
int a[10]; 说明整型数组a,有10个元素.
float b[10],c[20]; 说明实型数组b,有10个元素,实型数组c,有20个元素.
char ch[20]; 说明字符数组ch,有20个元素.
对于数组类型说明应注意以下几点:
1.数组的类型实际上是指数组元素的取值类型.对统一个数组,其所有元素的数据类型都是相同的.
2.数组名的书写规矩应合乎标识符的书写规定.
3.数组名不能与其它变量名相同,例如:
void main()
int a;
float a[10];
hh
是毛病的.
4.方括号中常量表达式表示数组元素的个数,如a[5]表示数组a有5个元素.然而其下标从0开端盘算.因而5个元素分离为a[0],a[1],a[2],a[3],a[4].
5.不能在方括号中用变量来表示元素的个数, 但是可以是符号常数或常量表达式.例如:
#define FD 5
void main()
int a[3+2],b[7+FD];
hh
是合法的.但是下陈述明方式是错误的.
void main()
int n=5;
int a[n];
hh
6.允许在同一个类型说明中,说明多个数组和多个变量.
例如: int a,b,c,d,k1[10],k2[20];
数组元素的表示方法
数组元素是组成数组的基础单元.数组元素也是一种变量, 其标识方法为数组名后跟一个下标. 下标表示了元素在数组中的顺序号.数组元素的一般形式为: 数组名[下标] 其中的下标只能为整型常量或整型表达式.如为小数时,C编译将自动取整.例如,a[5],a[i+j],a[i++]都是正当的数组元素. 数组元素通常也称为下标变量.必须先定义数组, 才干使用下标变量.在C语言中只能逐个地使用下标变量, 而不能一次援用整个数组. 例如,输出有10 个元素的数组必须使用循环语句逐个输出各下标变量:
for(i=0; i<10; i++) printf("%d",a[i]); 而不能用一个语句输出全部数组,下面的写法是过错的: printf("%d",a);
void main()
int i,a[10];
for(i=0;i<10;i++)
a[i++]=2*i+1;
for(i=9;i>=0;i--)
printf("%d",a[i]);
printf("\n%d %d\n",a[5.2],a[5.8]);
本例顶用一个循环语句给a数组各元素送入奇数值,而后用第二个循环语句从大到小输出各个奇数. 在第一个 for语句中,表达式3省略了.在下标变量中使用了表达式i++,用以修正循环变量.当然第二个for语句 也可以这样作, C语言允许用表达式表示下标. 程序中最后一个printf语句输出了两次a[5]的值, 可以看出当下标不为整数时将自动取整.数组的赋值给数组赋值的办法除了用赋值语句对数组元素逐 个赋值外, 还可采用初始化赋值和动态赋值的方法.数组初始化赋值数组初始化赋值是指在数组说明时给数组元 素赋予初值. 数组初始化是在编译阶段进行的.这样将减少运行时光,进步效力.
初始化赋值的个别情势为: static 类型阐明符 数组名[常量表白式]={值,值hh值}; 其中static表现是静态存储类型, C语言划定只有静态存储数组跟外部存储数组才可作初始化赋值(有关静态存储,外部存储的概念在第五章中先容 ).在{ }中的各数据值即为各元素的初值, 各值之间用逗号距离.例如: static int a[10]={ 0,1,2,3,4,5,6,7,8,9 }; 相称于a[0]=0;a[1]=1...a[9]=9;
C语言对数组的初始赋值还有以下几点规定:
1.可以只给部门元素赋初值.当{ }中值的个数少于元素个数时,只给前面局部元素赋值.例如: static int a[10]={0,1,2,3,4};表示只给a[0]~a[4]5个元素赋值,而后5个元素自动赋0值.
2.只能给元素逐个赋值,不能给数组整体赋值. 例如给十个元素全部赋1值,只能写为: static int a[10]={1,1,1,1,1,1,1,1,1,1};而不能写为: static int a[10]=1;
3.如不给可初始化的数组赋初值,则全部元素均为0值.
4.如给全部元素赋值,则在数组说明中, 可以不给出数组元素的个数.例如: static int a[5]={1,2,3,4,5};可写为: static int a[]={1,2,3,4,5};动态赋值可以在程序履行进程中,对数组作动态赋值. 这时可用循环语句配合scanf函数逐个对数组元素赋值.
void main()
int i,max,a[10];
printf("input 10 numbers:\n");
for(i=0;i<10;i++)
scanf("%d",&a[i]);
max=a[0];
for(i=1;i<10;i++)
if(a[i]>max) max=a[i];
printf("maxmum=%d\n",max);
本例程序中第一个for语句逐个输入10个数到数组a中. 然后把a[0]送入max中.在第二个for语句中,从a[1]到a[9]逐个与max中的内容比较,若比max的值大,则把该下标变量送入max中,因此max老是在已比较过的下 标变量中为最大者.比较结束,输出max的值.
void main()
int i,j,p,q,s,a[10];
printf("\n input 10 numbers:\n");
for(i=0;i<10;i++)
scanf("%d",&a[i]);
for(i=0;i<10;i++){
p=i;q=a[i];
for(j=i+1;j<10;j++)
if(q<a[j]) { p=j;q=a[j]; }
if(i!=p)
{s=a[i];
a[i]=a[p];
a[p]=s; }
printf("%d",
jordan shoes cheap,a[i]);
本例程序中用了两个并列的for循环语句,在第二个for 语句中又嵌套了一个循环语句.第一个for语句用于输入10个元素的初值.第二个for语句用于排序.本程 序的排序采用逐个比较的方法进行.在i次循环时,把第一个元素的下标i赋于p,而把该下标变量 值a[i]赋于q.然落后入小循环,从a[i+1]起到最后一个元素止逐个与a[i]作比较,
ChanelBelts,有比a[i]大者则将其下标送p,元素值送q. 一次循环结束后,p即为最大元素的下标,q则为该元素值.若此时inp,说明p,q值均已不是进入小循环之 前所赋之值,则交流a[i]和a[p]之值. 此时a[i]为已排序结束的元素.输出该值之后转入下一次循环.对i+1当前各个元素排序.
二维数组
前面介绍的数组只有一个下标,称为一维数组, 其数组元素也称为单下标变量.在实际问题中有良多量是二维的或多维的, 因此C语言答应构造多维数组.多维数组元素有多个下标, 以标识它在数组中的位置,所以也称为多下标变量. 本小节只介绍二维数组,多维数组可由二维数组类推而得到.二维数组类型说明二维数组类型说明的 正常形式是:
类型说明符 数组名[常量表达式1][常量表达式2]h;
其中常量表达式1表示第一维下标的长度,常量表达式2 表示第二维下标的长度.例如:
int a[3][4]; 说明了一个三行四列的数组,数组名为a,其下标变量的类型为整型.该数组的下标变量共有 3t4个,即: 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]
二维数组在概念上是二维的,等于说其下标在两个方向上变更, 下标变量在数组中的位置也处于一个平面之中, 而不是象一维数组只是一个向量.但是,实际的硬件存储器却是连续编址的, 也就是说存储器单元是按一维线性排列的. 如何在一维存储器中存放二维数组,可有两种方式:一种是按行排列, 即放完一行之后依次放入第二行.另一种是按列排列, 即放完一列之后再顺次放入第二列.在C语言中,二维数组是按行排列的. 在图4.1中,按行顺次存放,先存放a[0]行,再存放a[1]行,最后存放a[2]行.每行中有四个元素也是依次存放.因为数组a说明为
int类型,该类型占两个字节的内存空间,所以每个元素均占领两个 字节(图中每一格为一字节).
二维数组元素的表示方式
二维数组的元素也称为双下标变量,其表示的形式为: 数组名[下标][下标] 其中下标应为整型常量或整型表达式.例如: a[3][4] 表示a数组三行四列的元素.下标变量和数组说明在形式中有些类似,但这两者存在完全不同的含意 . 数组说明的方括号中给出的是某一维的长度,即可取下标的最大值; 而数组元素中的下标是该元素在数组中的地位标识.前者只能是常量, 后者可以是常量,变量或抒发式.
一个学习小组有5个人,每个人有三门课的测验成绩.求全组分科的平均成绩和各科总平均成绩.
课程 成绩姓名 Math C DBASE
张80 75 92
王61 65 71
李59 63 70
赵85 87 90
周76 77 85
可设一个二维数组a[5][3]存放五个人三门课的成绩.再设一个一维数组v[3]存放所求得各分科平均成绩,设变量l为全组各科总平均成绩.编程如下:
void main()
int i,j,s=0,l,v[3],a[5][3];
printf("input score\n");
for(i=0;i<3;i++){
for(j=0;j<5;j++)
{ scanf("%d",&a[j][i]);
s=s+a[j][i];}
v[i]=s/5;
s=0;
l=(v[0]+v[1]+v[2])/3;
printf("math:%d\nc languag:%d\ndbase:%d\n",v[0],v[1],v[2]);
printf("total:%d\n",l);
程序中首先用了一个双重循环. 在内循环中顺次读入某一门课程的各个学生的成绩,并把这些成绩累加起来, 退出内循环后再把该累加成就除以5送入v[i]之中,这就是该门课程的均匀成绩.外循环共循环三次,分别求出三门课各自的平均成绩并存放在v数组之中.退 出外循环之后,把v[0],v[1],v[2]相加除以3即得到各科总平均成绩.最后按题意输出各个成绩.
二维数组的初始化
二维数组初始化也是在类型说明时给各下标变量赋以初值. 二维数组可按行分段赋值,也可按行连续赋值. 例如对数组a[5][3]:
1.按行分段赋值可写为static int a[5][3]={ {80,75,92},{61,65,71},{59,63,70},{85,87,90},{76,77 ,85} };
2.按行持续赋值可写为static int a[5][3]={ 80,75,92,61,65,71,59,63,70,85,87,90,76,77,85 };
这两种赋初值的成果是完整相同的 .
void main()
int i,j,s=0,l,v[3];
static int a[5][3]={ {80,75,92},{61,65,71},{59,63,70},
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 languag:%d\ndbase:%d\n",v[0],v[1],v[2]);
printf("total:%d\n",l);
对于二维数组初始化赋值还有以下说明:
1.可以只对部分元素赋初值,未赋初值的元素自动取0值.
例如: static int a[3][3]={{1},{2},{3}}; 是对每一行的第一列元素赋值,未赋值的元素取0值. 赋值后各元素的值为: 1 0 02 0 03 0 0
static int a [3][3]={{0,1},{0,0,2},{3}}; 赋值后的元素值为 0 1 00 0 23 0 0
2.如对全体元素赋初值,则第一维的长度可以不给出.
例如: static int a[3][3]={1,2,3,4,5,6,7,8,9}; 可以写为:static int a[][3]={1,2,3,4,5,6,7,8,9};
数组是一种结构类型的数据. 二维数组可以看作是由一维数组的嵌套而形成的.设一维数组的每个元素都又是一个数组, 就组成了二维数组.当然,条件是各元素类型必须雷同.依据这样的剖析,一个二维数组也能够分解为多个一维数 组. 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],a[1],a[2]不能当作下标变量使用,它们是数组名,不是一个单纯的下标变量.
字符数组
用来存放字符量的数组称为字符数组. 字符数组类型说明的形式与前面介绍的数值数组相同.例如: char c[10]; 由于字符型和整型通用,也可以定义为int c[10]但这时每个数组元素占2个字节的内存单元.字符数组也可以是二维或多维数组,例如: char c[5][10];即为二维字符数组. 字符数组也允许在类型说明时作初始化赋值.例如: static char c[10]={`c`,` `,`p`,`r`,o`,g`,r`,`a`,`m`};赋值后各元素的值为: 数组C c[0]c[1]c[2]c[3]c[4]c [5]c[6]c[7]c[8]c[9]其中c[9]未赋值,由系统自动赋予0值. 当对全部元素赋初值时也可以省去长度说明.例如: static char c[]={`c`,` `,`p`,`r`,`o`,
boys polo shirts,`g`,`r`,`a`,`m`};这时C数组的长度自动定为9.
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");
本例的二维字符数组由于在初始化时全部元素都赋以初值, 因此一维下标的长度可以不加以说明.字符串在C语言中不专门的字符串变量, 通常用一个字符数组来存放一个字符串.在2.1.4节介绍字符串常量时,已说明字符串总是以'\0'作为串 的结束符.因此当把一个字符串存入一个数组时, 也把结束符'\0'存入数组,并以此作为该字符串是否结束的标志. 有了'\0'标志后,就不必再用字符数组的长度来断定字符串的长度了.
C语言许可用字符串的方法对数组作初始化赋值.例如 :
static char c[]={'c', ' ','p','r','o','g','r','a','m'}; 可写为:
static char c[]={"C program"}; 或去掉{}写为:
sratic char c[]="C program";
用字符串方式赋值比用字符逐个赋值要多占一个字节, 用于寄存字符串停止标志'\0'.上面的数组c在内存中的实际存放情形为: C program\0`\0'是由C编译体系主动加上的.因为采用了`\0'标记,所以在用字符串赋初值时普 通毋庸指定数组的长度, 而由系统自行处置.在采取字符串方式后,字符数组的输入输出将变得简略便利. 除了上述用字符串赋初值的措施外,还可用printf函数和scanf函数一次性输出输入一个字符数组中的 字符串, 而不用使用轮回语句一一地输入输出每个字符.
void main()
static char c[]="BASIC\ndBASE";
printf("%s\n",c);
留神在本例的printf函数中,使用的格式字符串为"%s", 表示输出的是一个字符串.而在输出表列中给出数组名则可. 不能写为: printf("%s",c[]);
void main()
char st[15];
printf("input string:\n");
scanf("%s",st);
printf("%s\n",st);
本例中由于定义数组长度为15, 因此输入的字符串长度必须小于15,以留出一个字节用于存放字符串结束标志`\0`. 应该说明的是,对一个字符数组,如果不作初始化赋值,则必须说明数组长度.还应当特殊注意的是,当用sca nf函数输入字符串时,字符串中不能含有空格,否则将以空格作为串的结束符.例如运行例4.8,当输入的字 符串中含有空格时,运行情况为: input string:this is a book this 从输出结果可以看出空格以后的字符都未能输出. 为了防止这种情况, 可多设几个字符数组分段存放含空格的串.程序可改写如下:
Lesson
void 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);
本程序分别设了四个数组, 输入的一行字符的空格分段分别装入四个数组.然后分别输出这四个数组中的字符串.在前面介绍过,scanf 的各输入项必须以地址方式呈现,如&a,&b等.但在例4.8中却是以数组名方式涌现的,
paul smith shops,这是为什么呢?这是由于在C语言中规定,数组名就代表了该数组的首地址. 整个数组是以首地址开头的一块连续的内存单元.如有字符数组char c[10],在内存可表示如图4.2.设数组c的首地址为2000,也就是说c[0]单元地址为2000.则数组名c就代表这个首地址.因此在c前面不能再加地址运算符&.如写作scanf( "%s",&c);则是错误的. 在执行函数printf("%s",c) 时,按数组名c找到首地址,然后逐个输出数组中各个字符直到碰到字符串终止标志'\0'为止.
字符串常用函数
C语言供给了丰盛的字符串处理函数, 大抵可分为字符串的输入、输出、合并、修改、比较、转换、复制、搜寻多少类. 使用这些函数可大大减轻编程的累赘.用于输入输出的字符串函数, 在使用前应包含头文件"stdio.h" ; 使用其它字符串函数则应包括头文件"string.h". 下面介绍几个最常用的字符串函数.
1.字符串输出函数 puts 格局: puts (字符数组名) 功效:把字符数组中的字符串输出到显示器. 即在屏幕上显示该字符串
#include"stdio.h"
main()
static char c[]="BASIC\ndBASE";
puts(c);
从程序中可以看出puts函数中可以使用本义字符, 因此输出结果成为两行.puts函数完全可以由printf函数代替. 当须要按必定格式输出时,通常使用printf函数.
2.字符串输入函数gets 格式: gets (字符数组名) 功能:从尺度输入装备键盘上输入一个字符串. 本函数得到一个函数值,即为该字符数组的首地址.
#include"stdio.h"
main()
char st[15];
printf("input string:\n");
gets(st);
puts(st);
可以看出当输入的字符串中含有空格时,输出仍为全部字符串.说明gets函数并不以空格作为字符串输入结束 的标志, 而只以回车作为输入结束.这是与scanf函数不同的.
3.字符串连接函数strcat 格式: strcat (字符数组名1,字符数组名2) 功能:把字符数组2中的字符串衔接到字符数组1 中字符串的后面,并删去字符串1后的串标志"\0".本函数返回值是字符数组1的首地址.
#include"string.h"
main()
static char st1[30]="My name is ";
int st2[10];
printf("input your name:\n");
gets(st2);
strcat(st1,st2);
puts(st1);
本程序把初始化赋值的字符数组与动态赋值的字符串连接起来. 要注意的是,字符数组1应定义足够的长度,否则不能全部装入被连接的字符串
4.字符串拷贝函数strcpy 格式: strcpy (字符数组名1,字符数组名2) 功能:把字符数组2中的字符串拷贝到字符数组1中.串结束标志"\0"也一起拷贝.字符数名2 , 也可以是一个字符串常量.这时相称于把一个字符串赋予一个字符数组.
#include"string.h"
main()
static char st1[15],st2[]="C Language";
strcpy(st1,st2);
puts(st1);printf("\n");
本函数请求字符数组1应有足够的长度,否则不能全部装入所拷贝的字符串.
5.字符串比较函数strcmp 格式: strcmp(字符数组名1,字符数组名2) 功能:依照ASCII码次序比较两个数组中的字符串,并由函数返回值返回比较结果.
字符串1=字符串2,返回值=0;
字符串2〉字符串2,返回值〉0;
字符串1〈字符串2,返回值〈0.
本函数也可用于比较两个字符串常量,或比拟数组和字符串常量.
#include"string.h"
main()
{ int k;
static char st1[15],st2[]="C Language";
printf("input a string:\n");
gets(st1);
k=strcmp(st1,st2);
if(k==0) printf("st1=st2\n");
if(k>0) printf("st1>st2\n");
if(k<0) printf("st1<st2\n");
本程序中把输入的字符串和数组st2中的串比较,比较结果返回到k中,根据k值再输出结果提醒串.当输入为 dbase时,由ASCII 码可知"dBASE"大于"C Language"故k〉0,输出结果"st1>st2".
6.测字符串长度函数strlen 格式: strlen(字符数组名) 功能:测字符串的实际长度(不含字符串结束标志l\0r) 并作为函数返回值.
#include"string.h"
main()
{ int k;
static char st[]="C language";
k=strlen(st);
printf("The lenth of the string is %d\n",k);
程序举例
把一个整数按大小顺序插入已排好序的数组中. 为了把一个数按大小插入已排好序的数组中, 应首先断定排序是从大到小仍是从小到大进行的.设排序是从大到小进序的, 则可把欲插入的数与数组中各数逐个比较, 当找到第一个比插入数小的元素i时,该元素之前即为插入位置.然后从数组最后一个元素开始到该元素为止,逐 个后移一个单元.最后把插入数赋予元素i即可.假如被插入数比所有的元素值都小则插入最后位置 .
main()...