null第7章 数组第7章 数组前面各章所使用的数据都属于基本数据类型(整型、实型、字符型),C语言除了提供基本数据类型外,还提供了构造类型的数据,它们是数组类型、结构体类型、共同体类型等。构造数据类型是由基本数据类型的数据按照一定的规则组成,所以也称为“导出类型”。null下面简单介绍一下数组概念:
1、数组:一组具有相同数据类型的数据的有序的集合。
2、数组元素:数组中的元素。数组中的每一个数组元素具有相同的名称,不同的下标,可以作为单个变量使用。在定义一个数组后,在内存中使用一片连续的空间依次存放数组的各个元素。
3、数组的下标:是数组元素的位置的一个索引或指示。
4、数组的维数:数组元素下标的个数。根据数组的维数可以将数组分为一维、二维、三维、多维数组。7.1一维数组的定义和使用7.1一维数组的定义和使用7.1.1 一维数组的定义(先定义后使用)
定义方式:
类型说明符 数组名[整型常量表达式]
例、 int a[10];
定义一个数组,数组名a,有10个元素,每个元素的类型均为int。
这10个元素分别是:a[0]、a[1]、a[2]、a[3]、a[4]、....、a[8]、a[9]。
注意:
(1)C语言中,数组下标从0开始.null(2)C语言不允许对数组的大小做动态定义,如:
int n;
scanf("%d",&n);
int a[n];
因为在编译时,C编译器根据已知数组大小分配内存空间。
说明:
(1)数组名:按标识符规则。本例a就是数组名。null(2)整型常量表达式:表示数组元素个数(数组的长度)。可以是整型常量或符号常量,不允许用变量。
整型常量表达式在说明数组元素个数的同时也确定了数组元素下标的范围,下标从0开始~整型常量表达式-1(注意不是1~整型常量表达式)。
C语言不检查数组下标越界,但是使用时,一般不能越界使用,否则结果难以预料。本例数组元素个数是10个,下标从0-9。null(3)类型说明:指的是数据元素的类型。类型说明确定了每个数据占用的内存字节数。比如整型2字节,实型4字节,双精度8字节,字符1字节。
本例数组元素是整型,每个元素占2个字节,因为有10个数组元素,所以占用20字节。
(4)C编译程序为数组分配了一片连续的空间。
(5)C语言还规定,数组名是数组的首地址。即a=&a[0]7.1.2 一维数组元素的 引用7.1.2 一维数组元素的 引用数组必须先定义后使用。C语言规定只能逐个引用数组元素而不能一次引用整个数组。
数组元素的表示形式:数组名[下标表达式]
下标可以是整型常量或整型表达式。如:
a[0]=a[5]+a[7]-a[2*3]
1个数组元素,实质上就是1个变量,它具有和相同类型单个变量一样的属性,可以对它进行赋值和参与各种运算。null[例] 使数组元素a[0]~a[9]的值为0~9,然后逆序输出。
main()
{
int i,a[10];
for (i=0;i<=9;i++)
a[i] = i;
for(i=9;i>=0; i--)
printf("%d ",a[i]);
}
运行输出: 9 8 7 6 5 4 3 2 1 0
7.1.3 一维数组的初始化7.1.3 一维数组的初始化初始化
:
数据类型 数组名[常量表达式]={初值表}
初始化:在定义时指定初始值,编译器把初值赋给数组变量。
赋值:使用赋值语句,在程序运行时把值赋给数组变量,如a[0] = 2。
1、一般初始化,例:
int a[10]= { 0,1,2,3,4,5,6,7,8,9}
int array[10] = {1,2,3,4,5,6,7,8,9,10}; null2、部分元素初始化,其余元素均为零。
例 :int a[10] = {0,1,2,3,4};
仅前5个元素赋初值,后5个元素未指定初值。
3、全部元素均初始化为0,不允许简写。
int a[10] = {0,0,0,0,0,0,0,0,0,0};或:int a[10]={0};
不能简写为:
int a[10] = {0*10};
4、如果全部元素均指定初值,定义中可以省略元素的个数,例、
int a[5] = {1,2,3,4,5};
可以写为:
int a[ ] = {1,2,3,4,5}; 7.1.4 一维数组程序举例7.1.4 一维数组程序举例[例] 输入10个数,用“冒泡法”对10个数排序(由小到大)。
冒泡法的基本思想:通过相邻两个数之间的比较和交换,使(数值)较小的数逐渐从底部移向顶部,较大的数逐渐从顶部移向底部。就像水底的气泡一样逐渐向上冒,故而得名。
“冒泡法”算法:以六个数9、8、5、4、2、0为例。
第1趟比较(下图1) 第2趟比较(下图2)
null第1趟比较后,剩5个数未排好序;两两比较5次
第2趟比较后,剩4个数未排好序;两两比较4次
第3趟比较后,剩3个数未排好序;两两比较3次
第4趟比较后,剩2个数未排好序;两两比较2次
第5趟比较后,全部排好序;两两比较1次
算法结论:对于n个数的排序,需进行n-1趟比较,第j趟比较需进行n-j次两两比较。
程序流程图:(用两层嵌套循环实现)
null程序:设需排序的数有10个,定义数组大小为11,使用a[1]~a[10]存放10个数,a[0]不用。
main()
{
int a[11]; /* 用a[1]~a[10], a[0]不用*/
int i,j,t; /* i,j作循环控制变量,t作中间变量*/
printf("input 10 numbers:\n");
for(i=1;i<11;i++)
scanf("%d",&a[i]); /* 输入10个整数 */
printf("\n");
for(j=1;j<=9;j++) /* 第j趟比较 */
for(i=1;i<=10-j; i++) /* 第j趟中两两比 较10-j次 */ nullif (a[i] > a[i+1]) /* 交换大小 */
{ t = a[i];
a[i] = a[i+1];
a[i+1] = t;
}
printf("the sorted numbers:\n");
for(i=1;i<11;i++)
printf("%d",a[i]);
}7.2 二维数组的定义和引用7.2 二维数组的定义和引用二维数组:数组元素是双下标变量的数组。
二维数组的数组元素可以看作是排列为行列的形式(矩阵)。二维数组也用统一的数组名来标识,第一个下标表示行,第二个下标表示列。行列下标从0开始。
7.2.1 二维数组的定义
类型说明符 数组名[行常量表达式][列常量表达式]
例 :float a[3][4]; a为3×4(3行4列)的数组
float b[5][10];b为5×10(5行10列)的数组null二维数组的理解:
二维数组a[3][4]理解为:
有三个元素a[0]、a[1]、a[2],每一个元素是一个包含4个元素的数组。null二维数组的元素在内存中的存放顺序:
按行存放,即:先顺序存放第一行的元素,再存放第二行的元素。(最右边的下标变化最快,第一维的下标变化最慢)。null强调:
(1)二维数组中的每个数组元素都有两个下标,且必须分别放在单独的“[ ]”内。如:a[3,4 ]
(2)二维数组定义中的第1个下标表示该数组具有的行数,第2个下标表示该数组具有的列数,两个下标之积是该数组具有的数组元素的个数。
(3)二维数组中的每个数组元素的数据类型均相同。二维数组的存放规律是“按行排列”。
(4)二维数组可以看作是数组元素为一维数组的数组。null7.2.2 二维数组的引用
二维数组元素的表示形式:
数组名[下标表达式][下标表达式]
数组元素可以出现在表达式中,也可以被赋值。例如:
b[1][2]=a[2][3]/2
注意引用数组元素的下标范围,不能越界使用。null7.2.3 二维数组的初始化
1、分行赋值,如:
int a[3][4]= {{1,2,3,4},{5,6,7,8},{9,10,11,12}};
2、全部数据写在一个大括号内赋值,如:
int a[3][4]= {1,2,3,4,5,6,7,8,9,10,11,12};
3、部分元素赋值,如:
int a[3][4] = {{1},{5},{9}};
仅对a[0][0]、a[1][0]、a[2][0]赋值,其余元素未赋值(编译器自动为未赋值元素指定初值0)
4、如果对全部元素赋初值,则第一维的长度可以不指定,但必须指定第二维的长度。例、
int a[3][4]={1,2,3,4,5,6,7,8,9,10,11,12};
与下面定义等价:
int a[ ][4]={1,2,3,4,5,6,7,8,9,10,11,12};
null7.2.4 二维数组应用举例
二维数组的遍历访问(扫描),一般都采用双重循环处理(行循环,列循环)。
[例] 将一个二维数组行和列交换,存到另一个二维数组中。例如、null算法: b[j][i] = a[i][j]
程序:
main()
{ int a[2][3] = {{1,2,3},{4,5,6}};
int b[3][2], i,j;
printf("array a:\n");
for(i=0;i<=1;i++) /* 0~1行 */
{ for(j=0;j<=2;j++) /* 0~2列 */
{ printf("%5d",a[i][j]);
b[j][i] = a[i][j]; /* 行、列交换 */
}
printf("\n");/*输出一行后换行 */
}nullprintf("array b:\n");
for(i=0;i<=2;i++)
{for(j=0;j<=1;j++)
printf("%5d",b[i][j]);
printf("\n"); /*输出一行后换行 */
}
}null[例] 有一个3×4的矩阵,要求编程序以求出其中值最大的那个元素的值及其所在的行号和列号。
算法:首先把第一个元素a[0][0]作为临时最大值max,然后把临时最大值max与每一个元素a[i][j]进行比较,若a[i][j]>max,把a[i][j]作为新的临时最大值,并
下其下标i和j。当全部元素比较完后,max是整个矩阵全部元素的最大值。null流程:null程序:
main()
{ int i,j,row=0,colum=0,max;
int [3][4]={{1,2,3,4},{9,8,7,6},{-10,10,-5,2}};
max = a[0][0];
for(i=0;i<=2;i++) /*用两重循环遍历全部元素 */
for(j=0; j<=3; 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);
}null 7.2.5 多维数组
当数组元素的下标在2个或2个以上时,该数组称为多维数组。其中以2维数组最常用。
定义多维数组:类型说明 数组名[整型常数1] [整型常数2]… [整型常数k];
例如:int a[2][3][3];
定义了一个三维数组a,其中每个数组元素为整型。总共有2x3x3=18个元素。null说明:
(1) 对于三维数组,整型常数1,整型常数2,整型常数3可以分别看作“深”维(或:“页”维)、“行”维、“列”维。可以将三维数组看作一个元素为二维数组的一维数组。三维数组在内存中先按页、再按行、最后按列存放。
(2) 多维数组在三维空间中不能用形象的图形表示。多维数组在内存中排列顺序的规律是:第一维的下标变化最慢,最右边的下标变化最快。
(3) 多维数组的数组元素的引用:数组名[下标1] [下标2]… [下标k]。多维数组的数组元素可以在任何相同类型变量可以使用的位置引用。只是同样要注意不要越界。7.3 字符数组7.3 字符数组字符数组:存放字符数据的数组,每一个元素存放一个字符。
7.3.1 程序中定义字符数组
char c[10]; /* 定义c为字符数组,包含10个元素*/
c[0]='I'; c[1]=' '; c[2]='a'; c[3]='m'; c[4]=' ';
c[5]='h'; c[6]='a'; c[7]='p'; c[8]='p'; c[9]='y';
字符型与整型可以通用,但有区别:
char c[10]; /* 在内存中占10字节 */
int c[10]; /* 在内存中占20字节 */null7.3.2 字符数组的初始化
1.逐个元素初始化
char c[10] = {'I',' ','a','m',' ','h','a','p','p','y'};
2、初始化数据少于数组长度,多余元素自动为“空”('\0',二进制0)。
char c[10] ={'c','','p','r','o','g','r','a','m'};/*9*/
3、指定初值时,若未指定数组长度,则长度等于初值个数。
char c[ ] = {'I',' ','a','m',' ','h','a','p','p','y'};null7.3.3 字符数组的引用
引用一个元素,得到一个字符。
[例] 输出一个字符串。
main()
{char c[10]={'I',' ','a','m',' ','a',' ','b','o','y'};
int i;
for(i=0;i<10;i++)
printf("%c",c[i]);
printf("\n");}
输出结果:
I am a boynull[例] 输出一个钻石图形。
main()
{char diamond[][5]={{' ',' ','*'},{' ','*',' ','*'},{'*',' ',' ',' ','*'},{' ','*',' ','*'}, {' ',' ','*'} };
int i,j;
for(i=0;i<5;i++)
{ for(j=0;j<5;j++)
printf("%c",diamond[i][j]);
printf("\n");
}
} 输出结果(如下)null 7.3.4字符串和字符串结束标志
字符串例子:"I am a boy"
1、C语言中,字符串作为字符数组处理。字符数组可以用字符串来初始化,例、
char c[] = {"I am happy"};
也可以这样初始化:(不要大括号)
char c[] = "I am happy";
2、字符串在存储时,系统自动在其后加上结束标志'\0'(占一字节,其值为二进制0)。但字符数组并不要求其最后一个元素是'\0',例、char c[] = {"China"}; nullchar c[5] = {‘C’,’h’,’i’,’n’,’a’};
char c[10] = {"China"};
null7.3.5 字符数组的输入输出
两种
:
1、用“%c”格式符逐个输入输出。
2、用“%s”格式符按字符串输入输出。
例、char c[6];
scanf("%s",c);
printf("%s",c);
注意:
(1)输出时,遇'\0'结束,且输出字符中不包含'\0'。null(2)“%s”格式输出字符串时,printf()函数的输出项是字符数组名,而不是元素名。
char c[6] = "China";
printf("%s",c); printf("%c",c[0]);
printf("%s",c[0]);
(3)“%s”格式输出时,即使数组长度大于字符串长度,遇'\0'也结束。例、
char c[10] = {"China"};
printf(“%s”,c); /*只输出5个字符 */
(4) “%s”格式输出时,若数组中包含一个以上'\0',遇第一个'\0'时结束。null( 5)输入时,遇回车键结束,但获得的字符中不包含回车键本身,而是在字符串末尾添‘\0’。因此,定义的字符数组必须有足够的长度,以容纳所输入的字符。(如,输入5个字符,定义的字符数组至少应有6个元素)。
(6)一个scanf函数输入多个字符串,输入时以“空格”键作为字符串间的分隔。例、
char str1[5],str2[5],str3[5];
scanf("%s%s%s",str1,str2,str3);
输入数据:How are you?
str1、str2、str3获得的数据见下图。null
例 char str[13];
scanf("%s",str);
输入:How are you?
结果:仅“How”被输入数组str
如要想str获得全部输入(包含空格及其以后的字符),程序应怎样
?
nullchar c[13];
int i;
for(i=0;i<13;i++) c[i] = getchar();
(7) C语言中,数组名代表该数组的起始地址,因此,scanf()函数中不需要地址运算符&。(在Turbo C中,加上&运算符也可以)。例、
char str[13];
scanf("%s",str);
scanf("%s",&str);
(8)不能采用赋值语句将一个字符串直接赋给一个数组。例:char c[10];c[]=“good”;
但是可以初始化:如:char c[ ]= “good”;null7.3.6 字符串处理函数
在C的函数库中,提供了一些字符串处理函数。
在调用字符串处理函数时,在程序前面通常应设置一个相关的文件包含预处理命令。即
#include
#include
1、puts()函数:输出字符串(以‘\0’结尾)。
例 char c[6]=“China”; printf、puts均以‘\0’结尾.
printf("%s\n",c);
printf需要格式控制符%s
puts(c);
puts不需要格式控制符,且自动换行null2.gets()函数:从终端接收一个字符串到字符数组
char str[12];
gets(str);
注意:gets()、puts()一次只能输入输出一个字符串。而scanf()、printf()可以输入输出几个字符串。
3、strcat():连接字符串。
strcat(字符串1,字符串2);
功能:把“字符串2”连接到“字符串1”的后面。从str1原来的’\0’(字符串结束标志)处开始连接。
注意:
字符串1一般为字符数组,要有足够的空间,以确保连接字符串后不越界;
字符串2可以是字符数组名,字符串常量。null 4、strcpy():字符串拷贝。
strcpy(字符串1,字符串2);
功能:将“字符串2”为首地址的字符串复制到“字符串1”为首地址的字符数组中。即把“字符串2”的值拷贝到“字符串1”中。
例如:
char str1[10],str2[ ]={“china”};
strcpy(str1,str2);
执行后str1的状态为:nullstr1-一般为字符数组,要有足够的空间,以确保复制字符串后不越界;
str2-可以是字符数组名,字符串常量。
字符串(字符数组)之间不能赋值,但是通过此函数,可以间接达到赋值的效果。
5、strcmp():字符串比较。
strcmp(字符串1,字符串2);
比较“字符串1”、“字符串2”,例、
strcmp(str1,str2);
strcmp("China", "Korea");
strcmp(str1, "Beijing");null比较规则:逐个字符比较ASCII码,直到遇到不同字符或‘\0’,比较结果是该函数的返回值。
字符串1 < 字符串2, strcmp()返回值<0
字符串1 == 字符串2, strcmp()返回值==0
字符串2 > 字符串2, strcmp()返回值>0
长度不同的字符串也可以进行比较,比较结果当然是“不同”。
长度不同的字符串也可以进行比较,比较结果当然是“不同”。
注意、字符串只能用strcmp函数比较,不能用关系运算符“==”比较。例、
if (strcmp(str1,str2) == 0) printf("yes");
if (!strcmp(str1,str2)) printf("equal");
if (str1 == str2) printf("yes"); null6、求字符串的长度函数strlen(str)
功能:统计str为起始地址的字符串的长度(不包括“字符串结束标志”),并将其作为函数值返回。
7.strlwr”(str)函数:将字符串中大写字母转换成小写字母.
8.strupr(str)函数:将字符串中小写字母转换成大写字母.
注意:在调用字符串处理函数时,在程序前面应设置一个相关的文件包含预处理命令,即#include null7.3.7 字符数组应用举例例:字符串输入。 程序如下:
#include
main( )
{ char s[20],s1[20];
scanf(“%s”,s);
printf(“%s \n”,s);
scanf(“%s%s”,s,s1);
/*从键盘上输入字符串,将How给s,将do给sl*/
printf(“s=%s,sl=%s”,s,s1);null puts(“\n”);
gets(s);
puts(s);
} 程序运行结果:
How do you do? ↙
How
How do you do? ↙
S=How,S1=do
How do you do? ↙
How do you do? 例中使用了scanf( )与gets( )两个函数来实现字符串的输入,要注意它们的差别,根据需要来选用。 null例:从键盘上输入两个字符串,若不相等,将短的字符串连接到长的字符串的末尾并输出。#include
#include
main( )
{
char s1[80],s2[80];
gets(s1);
gets(s2);
if (strcmp(s1,s2)!=0)
if (strlen(s1)>strlen(s2)) null {
strcat(s1,s2);
puts(s1);
}
else
{
strcat(s2,s1);
puts(s2);
}
}输入:you ↙
Thank ↙
输出:Thank younull例:输入三个字符串,并找出其中最大者。
:用strcmp()函数比较字符串的大小。首先比较前两个,把较大者拷贝给字符数组变量string(用strcpy()函数拷贝),再比较string和第三个字符串。
程序:设字符串最长为19个字符。
#include “string.h” /* strcmp、strcpy函数均在string.h中定义 */
#include “stdio.h”nullmain()
{ char string[20]; /* 存最大字符串 */
char str[3][20]; /* 三个字符串 */
int i;
for(i=0;i<3;i++)
gets(str[i]); /* 输入三个字符串 */
if (strcmp(str[0],str[1])>0) strcpy(string,str[0]);
else
strcpy(string,str[1]);
if (strcmp(str[2],string) > 0) strcpy(string,str[2]);
printf("\nthe largest string is: \n%s\n",string);
}null小结:
1、数组(一维和二维,多维)名、数组元素的概念。一维数组常与一重循环配合、二维数组常与二重循环配合,对数组元素依次进行处理。
2、数组必须先定义后使用,数组的初始化方法。
3、数组元素在内存中的存储顺序。
4、数据排序算法。(冒泡排序法)
5、字符串的特点(作为字符数组处理、最后一字节加'\0')。
6、字符串处理函数的应用。