第 5章 数组第 5章 数组
5.1一维数组的定义和引用
5.2 二维数组的定义和使用
5.3 字符数组与字符串
5.4 程序举例第 5章 数组
5.1一维数组的定义和引用
5.1.1一维数组的定义一维数组定义的一般形式为:
类型说明符 数组名 [整型常量表达式 ];
其中,类型说明符指数组中每个元素的类型 。 数组名是一个标识符,和普通变量命名规则一样,它代表了数组中第一个元素的地址 。 整型常量表达式表示数组元素的个数,即数组长度 。
例如语句第 5章 数组
#define M 20
int a[8];
float b[9];
char ch[M];
定义 a是有 8个整型元素的数组,b是有 9个单精度型元素的数组,ch是有 20个字符型元素的数组 。
说明:
(1)数组名后为下标运算符 [ ]而不是圆括号 ( ) 。 下面用法不对:
int a(10);
(2)整型常量表达式可以包括普通常量和符号常量,
第 5章 数组不能包含变量 。 也就是说,C不允许对数组的大小作动态定义,即数组的大小不依赖于程序运行过程中变量的值 。 例如,下面这样定义数组是不行的:
int m;
scanf("%d",&m);
int a[m];
第 5章 数组
5.1.2一维数组的引用数组必须先定义,然后使用 。 C语言规定只能逐个引用数组元素而不能一次引用整个数组 。
引用数组元素的一般形式为:
数组名 [下标 ]
下标必须从 0开始,可以是整型常量或整型表达式 。
下标是数组元素到数组开始的偏移量 。 第 1个元素的偏移量是 0,第 2个元素的偏移量是 1,依次类推 。 由此,数组是一系列大小相同的连续项,每项到公共基点的偏移量是固定的 。
例如 int a[5];
第 5章 数组定义 a是有 5个元素的数组,对它们的引用分别是 a[0],
a[1],a[2],a[3],a[4]。 注意不能使用数组元素
a[5]。
【 例 5.1】 数组元素的应用
main( )
{
int i,a[10];
for(i=0; i<=9; i++)
a[i]=2*i;
for(i=9; i>=0; i--)
printf("%d ",a[i]); }
第 5章 数组程序运行结果为:
18 16 14 12 10 8 6 4 2 0
程序使 a[0]到 a[9]的值为 0~ 18,然后按逆序输出 。
5.1.3一维数组的初始化对数组元素的初始化可以用以下方法实现:
( 1) 在定义数组时对数组元素赋初值 。 例如:
int a[6]={0,1,2,3,4,5};
将数组元素的初值依次放在一对花括弧内 。 经过上面的 定 义 和 初 始 化 之 后,a[0]=0,a[1]=1,
a[2]=2,a[3]=3,a[4]=4,a[5]=5。
第 5章 数组
( 2) 可以只给一部分元素赋值。例如:
int a[7]={1,2,3};
定义 a数组有 7个元素,但花括弧内只提供 3个初值 。 这表示只给前 3个元素赋初值,后 4个元素全为 0。
( 3) 用循环语句对数组赋值 。 例如:
int a[5];
for(i=0; i<5; i++)
a[i]=2*i+1;
定义 a 数组有 5 个元素,用循环语句赋值后,
a[0]=1,a[1]=3,a[2]=5,a[3]=7,a[4]=9。
( 4) 在对所有数组元素赋初值时,可以不指定数组第 5章 数组长度 。 例如:
int a[8]={1,2,3,4,5,6,7,8};
可以写成
int a[ ]={1,2,3,4,5,6,7,8};
在第二种写法中,花括弧内有 8个数,系统就会据此自动定义 a数组的长度为 8。
【 例 5.2】 用冒泡排序法对 10个数排序 ( 从小到大 )
分析:假设有 N个数据需要排序 。
第 5章 数组
1)首先比较第一个数和第二个数,如果第一个数大于第二个数,交换两数;然后比较第二个数和第三个数,如果第二个数大于第三个数,交换两数;依此类推,直到第 N-1个数与第 N个数比较、交换为止。如此经过一趟排序,使得最大的数被放到最后。
2) 对前面 N-1个数重复以上过程,则次大数被放在第 N-1
位置上 。
3) 重复以上过程,直到前面只剩下 1个数据为止 。 这时,
已确定 N-1个数据位于其最终位置,显然就是 N个数据已排序 。
第 5章 数组在冒泡排序的过程中,较大数总是往上 ( 地址递增的方向 ) 移动,就像水中气泡逐步往上冒出一样,因而称为冒泡排序 。
显然,冒泡排序总是比较相邻两个数,经过一趟排序后,找出当前数中的最大数放在最后 。
如果对 N个数排序,需要经过 N-1趟冒泡排序 。
第 1趟找 N个数中的最大数,要两两比较 N-1次;第 2趟找剩下 N-1个数中的最大数,要进行 N-2次比较;依此类推,第 k趟找 N-k+1个数中的最大数,要进行 N-k次比较;最后一趟找剩下的两个数的最大数,比较 1次 。
第 5章 数组
main( )
{ int a[10]; /*定义 a数组用来存放 10个数据 */
int i,j,t;
for(i=0; i<=9; i++)
scanf("%d,",&a[i]); /*对数组中每个数据输入值 */
printf("\n");
for(i=0; i<=8; i++) /*i用来代表排序的趟数 */
for(j=0; j<9-i; j++) /*j用来表示每一趟相邻两个数要比较的次数 */
第 5章 数组
if(a[j]>a[j+1])
{t=a[j]; a[j]=a[j+1]; a[j+1]=t; } /*相邻两个数据互换 */
for(i=0; i<=9; i++)
printf("%d,",a[i]); }
程序运行情况如下:
55,2,6,4,32,12,9,73,26,37,↙ ( 输入 10个数据,
↙ 代表回车键 )
2,4,6,9,12,26,32,37,55,73,
第 5章 数组
5.2 二维数组的定义和使用
5.2.1二维数组的定义实际问题中有很多量是二维的或多维的,因此C语言允许构造多维数组。多维数组元素有多个下标,以标识它在数组中的位置,所以也称为多下标变量。 本小节只介绍二维数组,
多维数组可由二维数组类推而得到。前面介绍的数组只有一个下标,称为一维数组,其数组元素也称为单下标变量。 C
语言中的数组可以有多个下标,需要两个下标才能标识某个元素的数组称为二维数组。二维数组经常用来表示按行和列格式存放信息的数值表。要识别表中某个特定的元素,必须指定两个下标。习惯上,第一个下标表示该元素所在行,第二个下标表示该元素所在列。
二维数组定义的一般形式是:
类型说明符 数组名 [整型常量表达式 1][整型常量表达式 2];
第 5章 数组其中,整型常量表达式 1表示第一维下标的长度,整型常量表达式 2 表示第二维下标的长度。
例如 int a[3][4];
定义 a数组是一个 3× 4( 3行 4列)的整型二维数组。下图 5—1
表示了此数组,可以看到,第一个下标的范围是 0~2,第二个下标的范围是0~3。二维数组是按先行后列的顺序在内存中线性排列的。二维数组在概念上是二维的,即是说其下标在两个方向上变化,下标变量在数组中的位置也处于一个平面之中,而不是象一维数组只是一个向量。但是,实际的硬件存储器却是连续编址的,也就是说存储器单元是按一维线性排列的。 如何在一维存储器中存放二维数组,可有两种方式
:一种是按行排列,即放完一行之后顺次放入第二行。另一种是按列排列,即放完一列之后再顺次放入第二列。在C语言中,二维数组是按行排列的。 在图 5.1中,按行依次存放,
第 5章 数组先存放 a[0]行,再存放 a[1]行,最后存放 a[2]行。每行中有四个元素也是依次存放。
第 5章 数组上述定义的二维数组可以看成定义了 3个一维数组,即相当于
int a[0][4],a[1][4],a[2][4]。 此处把 a[0],a[1],a[2]看作一维数组名 。
5.2.2二数组的引用二维数组的元素也称为双下标变量 。
二维数组引用数组元素的表示形式为:
数组名 [下标 ][下标 ]
其中,下标应为整型常量或整型表达式 。
说明:
(1)第一个下标必须在行下标范围内,第二个下标必须在列下标范围内 。
(2)两个下标不能写在一个下标运算符 [ ]中 。
例如,int a[3][4];
a[3][4]=3; (错误 )
a[2,3]=2; (错误 )
第 5章 数组定义 a是一个 3行 × 4列的数组,行下标的范围是 0~ 2,列下标的范围是 0~ 3。引用 a[3][4]超过了数组的范围。引用数组中第 3行第 4列元素为 a[2][3],而不是 a[2,3]。
值得注意:下标变量和数组定义说明在形式中有些相似,但这两者具有完全不同的含义。定义说明的方括号中给出的是某一维的长度,即可取下标的最大值; 而数组元素中的下标是该元素在数组中的位置标识。前者只能是常量。 后者可以是常量,变量或表达式。
5.2.3二维数组的初始化可以用下面的方法对二维数组初始化:
(1)分行给二维数组赋值 。 例如:
int a[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}};
这种赋值方法是把第 1个花括弧的数据给第 1行的元素,第 2
第 5章 数组个花括弧的数据给第 2行的元素 …… 即按行赋值。也即是
a[0][0]=1,a[0][1]=2,a[0][2]=3,a[0][3]=4
a[1][0]=5,a[1][1]=6,a[1][2]=7,a[1][3]=8
a[2][0]=9,a[2][1]=10,a[2][2]=11,a[2][3]=12
(2)将所有数据写在一个花括弧内,按数组排列的顺序对各元素赋初值 。 例如:
int a[3][4]={1,2,3,4,5,6,7,8,9,10,11,12};
效果与前相同 。 但第 1种方法更好 。
(3)可以对部分元素赋初值 。 例如:
int a[3][4]={{12,3},{4,5,6},{7}};
它只是对每行前面的元素赋值,每行后面没赋值的元素值自动为 0。 即赋值后各元素的值如下图 5.2。
第 5章 数组第 5章 数组也可以只对某几行元素赋初值 。 例如:
int a[3][4]={{1,2,},{3},{}}; 第 3行不赋初值
,则第 3行元素全为 0。
int b[3][6]={{27,48},{},{3,4,5,6,7,8}};第 2
行元素不赋初值,则第 2行元素全为 0。
( 4) 如果对全部元素都赋初值,则定义数组时可以省略第一维的长度,但第二维的长度不能省 。 例如:
int a[2][3]={1,2,3,4,5,6};
与下面定义等价:
int a[ ][3]={1,2,3,4,5,6};
编译器会根据数据总个数分配空间,每行 3列,所以确定该数组为 2行 。
也可以只对部分元素赋初值而省略第一维的长度,但应分行赋初值 。 例如:
int a[ ][7]={{1,2,3},{ },{4,5}};
编译器可得知数组有 3行 。
第 5章 数组
【 例 5.3】 有一个 3× 4列矩阵,要求编程序求出其中值最小的那个元素的值,以及其所在的行号和列标 。
main( )
{ int i,j,r=0,c=0,min;
int a[3][4]={{1,5,6,4},{33,99,100,67},{120,-
5,78,94}};
min=a[0][0];
for(i=0; i<=2; i++)
for(j=0; j<=3; j++)
if(a[i][j]<=min)
{min=a[i][j];
r=i;
c=j; }
printf("min=%d,r=%d,c=%d",min,r,c);
}
第 5章 数组程序运行结果为:
min=-5,r=2,j=1
【 例 5.4】 有一个 4× 4列矩阵,要求求出主对角线元素之和 。
main( )
{int i,j;
float a[4][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12},
{13,14,15,16}},sum=0;
for(i=0; i<=3; i++)
for(j=0; j<=3; j++)
if(i==j)
sum+=a[i][j];
printf("%f",sum);
}
程序运行结果为:
34,000000
第 5章 数组
5.3 字符数组与字符串数组中每个元素的类型都是字符型数据的数组是字符数组 。
字符数组的每个元素用来存放一个字符 。
5.3.1字符数组的定义和引用只要将我们前面的数组定义的类型说明符改为 char,就变成了字符数组的定义 。
一维数组定义的一般形式为:
char 数组名 [整型常量表达式 ];
二维数组定义的一般形式为:
char 数组名 [整型常量表达式 1][整型常量表达式 2];
引用字符数组的元素和前面引用数组元素的方法是一样的 。
下标从 0开始,为整型数据 。
例如:
char a[8];
a[0]='g',a[1]='o',a[2]='o',a[3]='d',a[4]='l',
a[5]='u?,a[6]='c',a[7]= 'k';
第 5章 数组定义 a为包含 10个元素的字符数组。在赋值以后数组的状态如下图 5.3所示。
由于字符型与整型是相互通用的 。 因此上面的定义也可以改为:
int a[8]; /*合法,但浪费存储空间 */
5.3.2字符数组的初始化字符数组的初始化与数值型数组的初始化基本一致,有如下形式:
第 5章 数组
(1)逐个元素初始化 。
char c[5]={ 'a',' ','b','o','y'};
(2)初始化是如果为全部元素赋值,则可以省略第一维长度

char c[ ]={ 'a',' ','b','o','y?}; /*数组 c共有5
个元素 */
(3)初始化时如果给定的数据个数少于数组长度,其余未赋值的元素自动赋值为,空,。
( 即 ASCII码为0的字符 '\0') 。
char c[5]={ 'a','b'};
则数组 c在内存中的存储示意图如下图 5.4所示 。 若初始化时如果提供的值的个数大于数组元素的个数,则提示语法错误
,Too many initializers”。
第 5章 数组
(4) 用字符串来初始化字符数组 。
例如:
char a[11]={ "I am a boy"};
或省略大括号:
char a[11]= "I am a boy";
则字符数组 a在内存中的存储情况如下图 5.5所示 。 如果用字符串初始化字符数组时,系统自动在其后加上结束标志 '\0'
( 占一个字节,其值为二进制0 ),而用字符初始化时不会自动添上结束标志 '\0'。
第 5章 数组在 C语言中没有专门的字符串变量,通常用一个字符数组来存放一个字符串 。
5.3.3字符数组与字符串的输入与输出字符 数组和字符串都可以以单个字符的形式逐个输入与输出,也可以以整体的形式输入与输出 。
1,用,%c”格式逐个输入输出例如,char c[10];
for(i=0; i<10; i++)
scanf("%c",&c[i]); /*或用 c[i]=getchar( ); */
for(i=0; i<10; i++)
第 5章 数组
printf("%c",c[i]); /*或用 putchar(c[i]); */
2,用,%s”格式整体输入输出例如:
char c[10];
scanf("%s",c); /*注意此处用数组名 c*/
printf("%s",c); /*注意此处用数组名 c*/
说明:
( 1 ) 用,%s”格式输出字符数组时,遇 '\0'时结束输出,且输出字符中不包含 '\0'。 若数组中包含一个以上
'\0',则遇第一个 '\0'时即结束输出 。
第 5章 数组
(2)用,%s”格式输入或输出字符数组时,函数 scanf的地址项,
函数 printf的输出项都必须是字符数组名或字符数组第0个元素的地址 。 若使用数组名作为实参,数组名前不能再加
,&”,因为数组名就是数组的起始地址 。
例 如:
char s1[ ]= "abcdef";
s1[3]='\0';
printf("%s",s1);
程序运行结果为:
abc
显然,字符数组 s1的第 5,6个元素的值 e,f及最后一个结束标志 '\0'都未输出 。
第 5章 数组
(3)用语句,scanf(”%s“,s2);,为字符数组 s2输入数据时,
遇空格键或回车键是结束输入。但所读入的字符串中不包含空格键或回车键,而是在字符串末尾添加 ‘ \0?。
(4) 用一个 scanf函数输入多个字符串,输入时应以空格键或回车键作为字符串间的分隔。例如:
char s1[5],s2[5];
scanf("%s%s",s1,s2);
若输入数据:
C Prog
则字符数组 s1和 s2的存储情况如下图 5.6所示第 5章 数组
【 例 5.5】 用户从键盘输入一个字符串 ( 字符中不包含空格 ),
当输入回车时认为输入结束,统计输入字符串中小写英文字母,
大写英文字母,数字字符及其他字符的个数 。
分 析:
1)当输入一个不含空格字符的字符串 。
2)对字符串中的每一个字符进行判断,确定字符类型并计数 。
3)输出结果 。
程序如下:
main( )
{ {int i,m,n,x,y; /*m,n,x,y统计各类字符个数 */
char c[80];
printf("input a string:\n");
scanf("%s",c);
第 5章 数组
m=n=x=y=0; /*计数器置 0*/
i=0;
while(c[i]!='\0')
{ if(c[i]>=?a?&&c[i]<=?z?) m++; /*判断是否是小写字母 */
else if(c[i]>='A'&&c[i]<='Z') n++; /*判断是否是大写字母 */
else if(c[i]>='0'&&c[i]<='9') x++; /*判断是否是数字字符 */
else y++; /*其他字符 */
i++; /*为下一个字符的判断作准备 */
}
printf("a~z:%d\nA~Z:%d\n0~9:%d\nothers:%d\n",m,n,x,y
);
}
第 5章 数组程序运行情况:
input a string:
YouAre189Right! ↙
a~z:8
A~Z:3
0~9:3
others:1
3,用字符串输入函数 gets实现输入字符串输入函数 gets的函数原型在头文件,stdio.h”中被说明,调用该函数时,应在程序中加入文件包含命令:
#include"stdio.h"
函数原型:
char *gets(char*s);
第 5章 数组函数功能:
调用该函数时,要求用户从标准键盘输入设备上 ( 比如键盘
) 输入一个字符串,以回车键作为输入结束标志;然后将接收到的字符依次给数组的各元素,并自动在字符串末尾加字符串结束标志 '\0'。 函数的返回值为该字符数组的首地址 。 同时,
调用该函数时与形参 s对应的实参应该定义为该字符数组名或有确定值的指针 。
例如:
char a[10];
gets(a); /*当输入回车时认为输入结束 */
printf("%s",a);
若运行时从键盘输入:
you are right ↙
第 5章 数组则输出结果是:
you are right
注意:调用函数 gets输入的字符串中可包含有空格字符,这是它与函数 scanf的主要差别 。
4,用字符串输出函数 puts实现输出字符串输出函数 puts的函数原型也在头文件,stdio.h”中被说明,调用该函数时,应在程序中加入相应的文件包含命令 。
函数原型:
int puts(const char*s);
函数功能:
把字符数组中的字符串或字符指针所指向的字符串输出到标准输出设备上(例如显示器),同时将 '\0'转换为 '\n'。因此输出时会自动换行,不必再设计换行的语句,这与函数 printf
用,%s”格式输出不同,后者没有自动换行的功能。
第 5章 数组
【 例 5.6】 取出字符串 s1中从第 m个字符开始剩余的所有字符,
送入字符数组 s2中 。
分析:
1) 输入字符串 s1。 若输入的字符串中包含空格,就不能使用函数 scanf,只能使用函数 gets。
2) 确定字符串 s1中第 m个字符的位置 。 这里要注意,口头语中的第 m个一般对应数组的第 m—1个元素,因为人们都习惯于从1开始编号 。
3) 将第 m个字符及其后的所有字符逐个写入到字符数组 s2中

4) 在字符数组 s2的末尾加上一个结束标志 '\0'。
程序如下:
#include"stdio.h"
main( )
{int i,j,m;
第 5章 数组
char s1[80],s2[80];
printf("input a string:\n");
gets(s1); /*输入字符串 s1*/
printf("input start point:\n");
scanf("%d",&m); /*输入 m*/
i=m-1; /*确定字符串 s1的第 m个字符的位置 */
j=0; /*字符串 s2的开始位置 */
while(s1[i]!='\0') /*当字符串 s1未结束时,进行字符的复制 */
{s2[j]=s1[i];
i++;
j++;
}
s2[j]='\0'; /*为字符数组 s2加上结束标志 ’ \0?*/
puts(s2);
第 5章 数组
}
程序运行情况:
input a string:
abcdefghijklmnopqrstuvwxyz↙
input start point:
10↙
klmnopqrstuvwxyz
5.3.4字符串处理函数
C语言提供了丰富的字符串处理函数,大致可以分为字符串的输入,输出,合并,修改,比较,转换,复制和搜索几类
。 使用这些函数可大大减轻编程的负担 。
除字符串输入输出函数外,字符串处理函数的原型均包含在头文件,string.h”中,调用这些函数,应注意使用文件包含命令:
第 5章 数组
#include "string.h“
下面介绍几个最常用的字符串函数 。 注意,字符串的处理函数往往都涉及到指针,下面函数原型中,*” 的含义是指针 。
为了便于完整地描述字符串处理函数,这里使用了指针,有关指针的操作以后的章节会讲,这里就不详述 。
1,字符串复制函数 strcpy
函数原型:
char *strcpy(char *dest,const char *src);
函数功能:
将字符串 src复制到字符数组 dest中,返回被复制的字符串
。 其中,src可以是字符数组名,字符串常量或字符指针变量
。 dest可以是字符数组名或字符指针变量 。 若 dest是字符指针变量,要注意给该指针变量赋初值 。
例如:
第 5章 数组
char a[10]= "abcdefghi",b[ ]= "happy";
strcpy(a,b);
字符数组 a在内存中的初始状态如下图 5.7所示。调用函数
strcpy后,字符数组 a,b在内存中存储的情况如下图 5.8所示。
第 5章 数组
【 例 5.7】 分析下面程序的运行结果 。
#include "conio.h"
#include "string.h"
#include"stdio.h"
main( )
{
char c1[18]= "happybirthday",c2[ ]= "hello";
strcpy(c1,c2);
clrscr( );
puts(c1);
printf("%c",c1[7]); }
程序运行结果为:
Hello
r
第 5章 数组
【 例 5.8】 实参为字符指针的复制情况 。
#include"string.h"
main( )
{char *s1="123",*s2="abcdef",*s3="1";
/*定义 s1,s2,s3为字符指针 */
s3=strcpy(s1,s2);
printf("%u,%u,%u\n",s1,s2,s3); /*输出指针 s1,
s2,s3在内存中的地址值 */
puts(s1);
puts(s2);
puts(s3); }
程序运行结果为:
404,408,404
abcdef
ef
abcdef
第 5章 数组注意:当 dest定义为字符数组时,则 dest的长度应大于等于字符串或字符数组 src的长度 。
不能用赋值语句将字符串或字符数组直接赋给一个字符数组
,但可以将一个字符常量赋给一个字符指针变量。字符数组之间不能相互赋值,但字符指针之间可以相互赋值。因为字符数组名是一个地址常量,不可以修改;而字符指针是一个指针变量,可以存放不同字符串的地址。
2,字符串连接函数 strcat
函数原型:
char *strcat(char*dest,const char*src);
函数功能:
删去字符串 dest的结束标志 ‘ \0?,将字符串或字符数组 src连同末尾的结束标记一起连接到字符数组 dest尾部,返回连接以后的字符串。
第 5章 数组例如:
char a[20]= "My name is ",b[10]= "Kate";
strcat(a,b);
执行完连接后字符数组 b不变,数组 a在内存中的情况如下图
5.9所示。
【 例 5.9】 字符串的连接 。
#include "string.h"
main( )
第 5章 数组
{ char s1[20]= "123",s2[ ]= "onetwothree",*s3;
s3=strcat(s1,s2);
puts(s1);
puts(s2);
puts(s3);
}
程序运行结果为:
123onetwothree
onetwothree
123onetwothree
注意:当 src是字符指针变量时,连接操作完成后,其值可能有所改变 。 若 dest是字符数组,则它的长度应大于数组 src
和 dest中实际字符的个数 。 同时,程序中的 s3只能定义为字符指针变量而不能定义为字符数组,因为字符数组名是一个地址常量 。
第 5章 数组
3,计算字符串长度的函数 strlen
函数原型:
unsigned int strlen(const char*str);
函数功能:
求字符串或字符数组中 str中实际字符的个数 ( 不包括 '\0'
) 。
【 例 5.10】 以下程序是求一字符串的长度,试分析程序的运行结果 。
分析:
1) 字符串的长度是指字符串中实际字符的个数 。
2) 字符串以 '\0'作为结束标记 。
3) 当一个字符串存在多个 '\0'时,则第一个 '\0'前面的字符个数即字符串的长度 。
#include "stdio.h"
#include "string.h"
第 5章 数组
main()
{char str[10]= "china";
char s[13]= "abcdef\0we\09";
printf("%d,%d",strlen(str),strlen(s));
}
程序运行结果为:
5,6
4,字符串比较函数 strcmp
函数原型:
int strcmp(char *str1,char *str2);
函数功能:
第 5章 数组比较字符串或字符数组 str1和字符串或字符数组 str2的大小 。
即对两个字符串自左至右逐个字符相比 ( 按 ASCII码值大小比较 ),直到出现不同的字符或遇到 '\0'为止 。 如全部字符相同,
则认为相等;若出现不相同的字符,则以第一个不相同的字符的比较结果为准 。
比较的结果由函数值带回 。
当字符串 str1大于字符串 str2时,函数返回值为一正整数 。
当字符串 str1等于字符串 str2时,函数返回值为 0。
当字符串 str1小于字符串 str2时,函数返回值为一负整数 。
例如,strcmp("computer","compare")的函数值大于 0,表示字符串 "computer"大于字符串 "compare"。
strcmp("DOG","cat")的函数值小于 0,表示字符串 "DOG"小于字符串 "cat"。
strcmp("equal","equal")的函数值等于 0,表示字 符串
"equal"等于字符串 "equal"。
第 5章 数组注意:对两个字符串进行比较大小时,不能使用前面学过的比较运算符,>”,,<”,,= =”,而只能使用字符串比较函数
strcmp,而根据 strcmp的值来确定两个字符串的大小关系 。
【 例 5.11】 输入三个字符串,按英文字母顺序排列后输出 。
分析:
1) 所谓英文字母顺序是指按英文字母从小到大排序 。 如字符串,China”,,American”,,France”由小到大的顺序为
,American”,,China”,,France”。
2) 采用两两比较的方法进行 。 同理假设将排列好的结果依次存放在三个字符数组中 。
程序如下:
#include "stdio.h"
#include"string.h"
main( )
第 5章 数组
{
char s1[9]= "China",s2[9]= "American",
s3[9]= "France",t[9];
if(strcmp(s1,s2)>0)
{ strcpy(t,s1);
strcpy(s1,s2);
strcpy(s2,t); }
if(strcmp(s1,s3)>0)
{ strcpy(t,s3);
strcpy(s3,s1);
strcpy(s1,t); }
if(strcmp(s2,s3)>0)
{ strcpy(t,s2);
strcpy(s2,s3);
strcpy(s3,t); }
第 5章 数组
puts(s1);
puts(s2);
puts(s3);
}
程序运行结果为:
American
China
France
【 例 5.12】 比较用户输入的字符串是否为表示同意的 yes( 用户可以用大写或小写 ) 。
分析:
第 5章 数组
1) 不区分大小写比较两个字符串,首先应该将两个字符串全部都转换为大写字母或小写字母 。
2) 要将一个字符串的全部字符转换为大 ( 小 ) 写字母,可调用转换函数,也可直接转换 。 这里采用直接转换方式 。
3) 大小写字母的转换是根据字母的 ASCII码来实现的 。 例如
,'A'+32='a',反之,'a'-32='A'。 这是基本的转换算法 。
程序如下:
#include"stdio.h"
#include"string.h"
main( )
{ int k;
char s1[5],s2="yes";
printf("input a string:\n");
gets(s1);
k=0;
第 5章 数组
while(s1[k]!='\0')
{ if(s1[k]>='A'&&s1[k]<='Z')
s1[k]=s1[k]+32;
k++;
}
if(strcmp(s1,s2)!=0)
printf("s1!=s2\n");
else printf("s1=s2\n");
}
程序运行情况:
input a string:
yes ↙
s1=s2
本节所介绍的都是常用的字符串处理函数,由于篇幅限制,
还有一些没有介绍,请读者在使用时查看本书的附录或相关的库函数手册 。
第 5章 数组
5.4程序举例
【 例 5.13】 判断一个字符串是否为回文串 ( 回文串是指正读反读都一样的字符串,如:字符串,abce171ecba”) 。
分析:
1) 定义一个字符数组 s来存储字符串中的每个字符 。
2) 求字符串长度 n,这样就知道了字符串中共有多少个实际字符,同时也知道了字符数组的最大下标值,即字符串实际长度减 1。
3) 从两边 ( 分别称为左边,右边 ) 向中间逐对判断串中字符是否相等,即 s[0]与 s[n-1],s[1]与 s[n-2]…… 如果出现不同
,结束循环,否则继续判断 。 比较过程的另一种结束条件是左边元素的下标大于等于右边元素的下标 。
4) 根据循环变量的最终值判断是否为回文串,如果不是回文串,一定是跳出了循环,在这种情况下左边元素的下标应小于右边元素的下标 。
第 5章 数组程序如下:
#include"stdio.h"
#include"string.h"
main( )
{ char s[20];
int i,j,n;
gets(s);
n=strlen(s);
i=0; j=n-1;
while(s[i]==s[j]&&i<j)
{ i++;
j++; }
if(i>=j) printf("The number is palindrome\n");
else printf("The number is not palindrome\n");
}
第 5章 数组程序运行情况:
abcde123321edcba↙
The number is palindrome
【 例 5.14】 输入一个整数,判断该整数是否全部由奇数字组成或全部由偶数字组成 。 若全部由奇数字组成或全部由偶数字组成,输出,YES!”,否则输出,NO!”。
分析:
本题有两种解法,一种是采用整除取余数的方法,分别对组成整数的每一个数字进行判断;另一种方法是把该整数以字符串的形式输入,然后对字符数组的每一个元素进行判断。第二种方法的优点在于不必考虑该整数是基本整型还是长整型,即使该整数超出了长整型的表示范围,也能方便地加以判断。下面给出第二种方法解题的基本步骤。
(1)以字符串的形式读入一个整数(不必考虑其取值范围)

第 5章 数组
(2)设置两个标志位:奇标志位和偶标志位。奇标志位用于标识是否全部是奇数字,偶标志位用于标识是否全部是偶数字
。两个标志位均赋初始值为 1,即假设全部是奇数字和全部是偶数字组成。
(3)依次对字符串的每一个字符进行判断,若字符为奇数字字符,则偶标志位置 0;若字符为偶数字标志,则奇标志位置 0

(4)根据奇偶标志位的值,输出结果 。
程序如下:
#include"stdio.h"
#include"conio.h"
main( )
{
第 5章 数组
char s[28];
int odd=1,even=1; /*设置标志位的初始值 */
int i;
clrscr( );
printf("enter a number,");
gets(s); /*将一个整数以字符串的形式输入 */
i=0;
while(s[i]!='\0')
{ if((s[i]-'0')%2==0) odd=0; /*修改标志位 */
else even=0;
i++; }
if(odd==1||even==1) printf("YES! ");
else printf("NO! ");
}
第 5章 数组程序运行情况:
enter a number:13579797955331357137 ↙
YES!
enter a number:224466880080642426806 ↙
YES!
enter a number:123457485769090765432 ↙
NO!
由程序运行情况可知,输入的整数不必考虑是整型还是长整型,如运行时输入的,13579797955331357137”已经超出了长整型的表示范围 。 程序中的,s[i]-'0'”是把数字字符转换为对应的数字 。
【 例 5,15】 输出如下图 5.10( a) 所示的杨辉三角形的前 5
行 。
第 5章 数组第 5章 数组分析:
1) 所谓杨辉三角形,是一组特殊的组合运算 。 对于杨辉三角形的第 i行而言,每个数据依次为,Ci0,Ci1,…,Cii。 因此
,可利用组合运算来处理 。
2) 如果杨辉三角形改写成如图 5.10( b) 所示的形式,并将它放在一个二维数组中,可根据这个二维数组的特点来处理

3) 在图 5—10( b) 中,对角线上的值均为 1,即当二维数组的行号与列号相等时,对应位置的值为 1;最左一列即第 0列的值全为 1;其他位置的数据刚好是其上一行的本列及前一列两数之和,例如最后一行中第一个 5( 第 1列 ) 就是上一行的 1
( 第 0列 ) 和 4( 第 1列 ) 的和,10( 第 2列 ) 是上一行的 4( 第 1
列 ) 和 6( 第 2列 ) 的和 。 由此,可归纳出,a[i][j]=a[i-
1][j-1]+a[i-1][j](这里假设该二维数组名为 a)。
第 5章 数组
4) 根据上述分析,生成如图 5.10( b) 所示的二维数组 。
5) 输出生成的二维数组,注意只输出该二维数组的下三角部分 。
程序如下:
#define N 5
#include "stdio.h"
main( )
{ int i,j;
int a[N][N];
for(i=0; i<N; i++)
for(j=0; j<=i; j++) /*在下三角部分,列号总是小于或等于行号 */
{if(j==0||j==i)
a[i][j]=1; /*处理第 0列和对角线上的值 */
else a[i][j]=a[i-1][j-1]+a[i-1][j]; /*i-1表示上一行,j-1表示前一列 */
}
第 5章 数组
for(i=0; i<N; i++)
{for(j=0; j<=i; j++)
printf("%d ",a[i][j]); /*输出下三角矩阵 */
printf("\n");
}
}
程序运行结果为:
1
1 1
1 2 1
1 3 3 1
1 4 6 6 1