7.1 一维数组的定义和引用
7.2 二维数组的定义和引用
7.3 字符数组习题第 7章 数 组迄今为止,我们使用的都是属于基本类型 (整型、
字符型、实型 )的数据,c语言还提供了构造类型的数据,它们有:数组类型、结构体类型、
共用体类型。构造类型数据是由基本类型数据按一定规则组成的,因此有的书称它们为“导出类型”。
本章只介绍数组。数组是有序数据的集合。数组中的每一个元素都属于同一个数据类型。用一个统一的数组名和下标来唯一地确定数组中的元素。有关数组的概念和其他高级语言中介绍的是相同的,不再赘述。本章只介绍 c语言中如何定义和使用数组。
7.1 一维数组的定义和引用
7.1.1 一维数组的定义一维数组的定义方式为类型说明符 数组名[常量表达式];
例如:
int a[ 10] ;
它表示数组名为 a,此数组有 10个元素。
说明:
(1) 数组名定名规则和变量名相同,遵循标识符定名规则。
(2) 数组名后是用方括弧括起来的常量表达式,不能用圆括弧,下面用法不对,int a(10);
(3) 常量表达式表示元素的个数,即数组长度。例如,
在 a[ 10]中,10表示 a数组有 10个元素,下标从 0
开始,这 10个元素是,a[ 0],a[ 1],a[ 2],
a[ 3],a[ 4],a[ 5],a[ 6],a[ 7],a
[ 8],a[ 9]。注意不能使用数组元素 a[ 10]。
(4) 常量表达式中可以包括常量和符号常量,不能包含变量。也就是说,c不允许对数组的大小作动态定义,即数组的大小不依赖于程序运行过程中变量的值。例如,下面这样定义数组是不行的:
int n;
scanf("%d",&n);
int a[ n] ;
7.1.2 一维数组元素的引用数组必须先定义,然后使用。 c语言规定只能逐个引用数组元素而不能一次引用整个数组。
数组元素的表示形式为数组名[下标]
下标可以是整型常量或整型表达式。例如,
a[ 0] =a[ 5] +a[ 7] -a[ 2*3]
例 7.1数组元素的引用。
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
程序使 a[ 0]到 a[ 9]的值为 0~ 9,然后按逆序输出。
7.1.3 一维数组的初始化对数组元素的初始化可以用以下方法实现:
(1) 在定义数组时对数组元素赋以初值。例如,
int a[ 10] ={0,1,2,3,4,5,6,7,8,9};
将数组元素的初值依次放在一对花括弧内。经过上面的定义和初始化之后,a[ 0] =0,a[ 1] =1,a[ 2] =2,a[ 3]
=3,a[ 4] =4,a[ 5] =5,a[ 6] =6,a[ 7] =7,a[ 8]
=8,a[ 9] =9。
(2) 可以只给一部分元素赋值。例如,
int a[ 10] ={0,1,2,3,4};
定义 a数组有 10个元素,但花括弧内只提供 5个初值,这表示只给前面 5个元素赋初值,后 5个元素值为 0。
(3) 如果想使一个数组中全部元素值为 0,可以写成
int a[ 10] ={0,0,0,0,0,0,0,0,0,0};
不能写成
int a[ 10] ={0*10};
这是与 FORTRAN语言不同的,不能给数组整体赋初值。
(4) 在对全部数组元素赋初值时,可以不指定数组长度。
例如,
int a[ 5] ={1,2,3,4,5};
可以写成
int a[] ={1,2,3,4,5}
在第二种写法中,花括弧中有 5个数,系统就会据此自动定义 a数组的长度为 5。
但若被定义的数组长度与提供初值的个数不相同,
则数组长度不能省略。例如,想定义数组长度为
10,就不能省略数组长度的定义,而必须写成
int a[ 10] ={1,2,3,4,5};
只初始化前 5个元素,后 5个元素为 0。
7.1.4 一维数组程序举例例 7.2用数组来处理求 fibonacci数列问题。
程序如下:
main()
{
int i;
int f[ 20] ={1,1};
for(i=2; i<20;i++)
f[ i] =f[ i-2] +f[ i-1] ;
for(i=0;i<20;i++)
{
if(i%5==0) printf("\ n");
printf("%12d",f[ i] );
}
}
运行结果如下:
1 1 2 3 5
8 13 21 34 55
89 144 233 377 610
987 1597 2584 4181 6765
if语句用来控制换行,每行输出 5个数据。
例 7.3用起泡法对 10个数排序 (由小到大 )。
起泡法的思路是:将相邻两个数比较,将小的调到前头。见图 7.1。
图 7.1
图 7.2
若有 6个数。第一次将 8和 9对调,第二次将第 2和第 3个数 (9和
5)对调 …… 如此共进行 5次,得到 8 5 4 2 0 9的顺序,
可以看到:最大的数 9已“沉底”,成为最下面一个数,而小的数“上升”。最小的数 0已向上“浮起”一个位置。经第一趟 (共 5次 )后,已得到最大的数。然后进行第二趟比较,
对余下的前面 5个数按上法进行比较,见图 7.2。经过 4次比较,得到次大的数 8。如此进行下去。可以推知,对 6个数要比较 5趟,才能使 6个数按大小顺序排列。在第一趟中要进行两个数之间的比较共 5次,在第二趟中比 4次 …… 第 5趟比 1次。如果有 n个数,则要进行 n-1趟比较。在第 1趟比较中要进行 n-1次两两比较,在第 j趟比较中要进行 n-j次两两比较。据此画出流程图 (见图 7.3)。根据流程图写出程序 (今设 n=10),定义数组长度为 11,本例中对 a[ 0]不用,只用
a[ 1]到 a[ 10],以符合人们的习惯。
图 7.3
main()
{
int a[ 11] ;
int i,j,t;
printf("input 10 numbers,\ n");
for (i=1;i<11;i++)
scanf("%d",&a\[i\]);
printf("\ n");
for(j=1; j<=9; j++)
for(i=1; i<=10-j;i++)
if (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] );
}
运行情况如下:
input 10 numbers:
1 0 4 8 12 65 -76 100 -45 123
the sorted numbers:
-76 -45 0 1 4 8 12 65 100 123
7.2.1 二维数组的定义二维数组定义的一般形式为类型说明符 数组名[常量表达式][常量表达式]。
例如,float a[ 3][ 4],b[ 5][ 10];
定义 a为 3× 4(3行 4列 )的数组,b为 5× 10(5行 10列 )
的数组。注意不能写成
float a[ 3,4],b[ 5,10] ;
c语言对二维数组采用这样的定义方式,使我们可以把二维数组看作是一种特殊的一维数组:它的元素又是一个一维数组。例如,可以把 a看作是一个一维数组,它有 3个元素,a[ 0],a[ 1]、
7.2 二维数组的定义和引用
a[ 2],每个元素又是一个包含 4个元素的一维数组。见图 7.4。可以把 a[ 0],a[ 1],a[ 2]看作是 3个一维数组的名字。上面定义的二维数组可以理解为定义了 3个一维数组,即相当于 float a
[ 0][ 4],a[ 1][ 4],a[ 2][ 4]
图 7.5图 7.4
此处把 a[ 0],a[ 1],a[ 2]看作一维数组名。 c
语言的这种处理方法在数组初始化和用指针表示时显得很方便,这在以后会体会到。
c语言中,二维数组中元素排列的顺序是:按行存放,
即在内存中先顺序存放第一行的元素,再存放第二行的元素。图 7.5表示对 a[ 3][ 4]数组存放的顺序。
c允许使用多维数组。有了二维数组的基础,再掌握多维数组是不困难的。例如,定义三维数组的方法是
float a[ 2][ 3][ 4] ;
多维数组元素在内存中的排列顺序:第一维的下标变化最慢,最右边的下标变化最快。例如,上述三维数组的元素排列顺序为
a[ 0][ 0][ 0] → a[ 0][ 0][ 1] → a[ 0][ 0]
[ 2] → a[ 0][ 0][ 3] → a[ 0][ 1][ 0]
→ a[ 0][ 1][ 1] → a[ 0][ 1][ 2] → a[ 0]
[ 1][ 3] → a[ 0][ 2][ 0] → a[ 0][ 2]
[ 1] → a[ 0][ 2][ 2] → a[ 0][ 2][ 3]
→ a[ 1][ 0][ 0] → a[ 1][ 0][ 1] → a[ 1]
[ 0][ 2] → a[ 1][ 0][ 3] → a[ 1][ 1]
[ 0] → a[ 1][ 1][ 1] → a[ 1][ 1][ 2]
→ a[ 1][ 1][ 3] → a[ 1][ 2][ 0] → a[ 1]
[ 2][ 1] → a[ 1][ 2][ 2] → a[ 1][ 2]
[ 3]
7.2.2 二维数组的引用二维数组的元素的表示形式为数组名[下标][下标]
如 a[ 2][ 3]。下标可以是整型表达式,如 a[ 2-1]
[ 2*2-1]。不要写成 a[ 2,3],a[ 2-1,2*2-1]
形式。
数组元素可以出现在表达式中,也可以被赋值,例如:
b[ 1][ 2] =a[ 2][ 3] /2
在使用数组元素时,应该注意下标值应在已定义的数组大小的范围内。常出现的错误是
int a[ 3][ 4] ;

a[ 3][ 4] =3;
定义 a为 3× 4的数组,它可用的行下标值最大为 2,
列下标值最大为 3。用 a[ 3][ 4]超过了数组的范围。
请读者严格区分在定义数组时用的 a[ 3][ 4]和引用元素时的 a[ 3][ 4]的区别。前者 a[ 3][ 4]
用来定义数组的维数和各维的大小,后者 a[ 3]
[ 4]中的 3和 4是下标值,a[ 3][ 4]代表某一个元素。
7.2.3 二维数组的初始化可以用下面的方法对二维数组初始化:
(1) 分行给二维数组赋初值。如
int a[ 3][ 4] ={{1,2,3,4},{5,6,7,8},{9,
10,11,12}};
这种赋初值方法比较直观,把第 1个花括弧内的数据给第 1行的元素,第 2个花括弧内的数据赋给第 2行的元素 …… 即按行赋初值。
(2) 可以将所有数据写在一个花括弧内,按数组排列的顺序对各元素赋初值。如,int a[ 3][ 4] ={1,
2,3,4,5,6,7,8,9,10,11,12};效果与前相同。但以第 1种方法为好,一行对一行,界限清楚。
用第 2种方法如果数据多,写成一大片,容易遗漏,
也不易检查。
(3) 可以对部分元素赋初值。
int a[ 3][ 4] ={{1},{5},{9}};
它的作用是只对各行第 1列的元素赋初值,其余元素值自动为 0。赋初值后数组各元素为
1 0 0 0
5 0 0 0
9 0 0 0
也可以对各行中的某一元素赋初值:
int a[ 3][ 4] ={{1},{0,6},{0,0,11}};
初始化后的数组元素如下:
1 0 0 0
0 6 0 0
0 0 11 0
这种方法对非 0元素少时比较方便,不必将所有的 0
都写出来,只需输入少量数据。也可以只对某几行元素赋初值:
int a[ 3][ 4] ={{1},{5,6}};
数组元素为
1 0 0 0
5 6 0 0
0 0 0 0
第 3行不赋初值。也可以对第 2行不赋初值:
int a[ 3][ 4] ={{1},{},{9}};
(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};
系统会根据数据总个数分配存储空间,一共 12个数据,每行 4列,当然可确定为 3行。
在定义时也可以只对部分元素赋初值而省略第一维的长度,但应分行赋初值。如,int a[][ 4]
={{0,0,3},{},{0,10}};
这样的写法,能通知编译系统;数组共有 3行。数组各元素为
0 0 3 0
0 0 0 0
0 10 0 0
从本节的介绍中可以看到,c语言在定义数组和表示数组元素时采用 a[][]这种两个方括弧的方式,
对数组初始化时十分有用,它使概念清楚,使用方便,不易出错。
7.2.4 二维数组程序举例例 7.4将一个二维数组行和列元素互换,存到另一个二维数组中。例如:
a=1 2 3 b=1 4
4 5 6 2 5
3 6
程序如下:
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++)
{
for (j=0;j<=2;j++)
{
printf("%5d",a[ i][ j] );
b[ j][ i] =a[ i][ j] ;
}
printf("\ n");
}
printf("array b:\ n");
for (i=0;i<=2,i++)
{
for(j=0;j<=1;j++)
printf("%5d",b[ i][ j] );
printf("\ n");
}
}
运行结果如下:
array a:
1 2 3
4 5 6
array b:
1 4
2 5
3 6
例 7.5有一个 3× 4的矩阵,
要求编程序求出其中值最大的那个元素的值,以及其所在的行号和列号。先用 N-S流程图表示算法,见图
7.6。
据此写出以下程序:
图 7.6
main()
{int i,j,row=0,colum=0,max;
int a[ 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);
}
输出结果为:
max=10,row=2,colum=1
由于数值型数组的概念和应用与其他高级语言差不多,读者比较熟悉,因此不再赘述。
7.3.1 字符数组的定义定义方法与前面介绍的类似。例如:
char 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';
定义 c为字符数组,包含 10个元素。在赋值以后数组的状态如图 7.7所示。
7.3 字符数组
用来存放字符数据的数组是字符数组。字符数组中的一个元素存放一个字符。
图 7.7
也可以用整型数值来存放字符型数据,因此上面第一行也可以改用:
int c[ 10] ;/*合法,但浪费存储空间 */
7.3.2 字符数组的初始化对字符数组初始化,最容易理解的方式是逐个字符赋给数组中各元素。如,char c[ 10] ={'I',' ',
'a','m',' ','h','a','P','P','y'};把 10个字符分别赋给 c[ 0]到 c[ 9] 10个元素。
如果花括弧中提供的初值个数 (即字符个数 )大于数组长度,则按语法错误处理。如果初值个数小于数组长度,则只将这些字符赋给数组中前面那些元素,其余的元素自动定为空字符 (即 '\ 0')。如:
char c[ 10] ={'c',' ','P','r','o','g','r','a',
'm'};
数组状态如图 7.8所示。
图 7.8
如果提供的初值个数与预定的数组长度相同,在定义时可以省略数组长度,系统会自动根据初值个数确定数组长度。如:
char c[] ={'I',' ','a','m',' ','h','a','p',
'p','y'};
数组 c的长度自动定为 10。用这种方式可以不必人工去数字符的个数,尤其在赋初值的字符个数较多时,比较方便。
也可以定义和初始化一个二维字符数组,如,
char diamond[ 5][ 5] ={{' ',' ',
'*'},{' ','*',' ','*'},
{'*',' ',' ',' ','*'},{' ','*',' ',
'*'},{' ',' ','*'}};
用它代表一个钻石形的平面图形,见图 7.9。完整的程序见例 7.7。
图 7.9
例 7.6输出一个字符串。
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 boy
例 7.7输出一个钻石图形。 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");
}
}
运行结果为:
7.3.4 字符串和字符串结束标志在 c语言中,将字符串作为字符数组来存放。例 7.6就是用一个一维的字符数组存放一个字符串,I am a
boy”中的字符。这个字符串的实际长度与数组长度相等。有时,人们关心的是有效字符串的长度而不是字符数组的长度。例如,定义一个字符数组长度为 100,而实际有效字符只有 40个。为了测定字符串的实际长度,c语言规定了一个“字符串结束标志”,
以字符‘\ 0?代表。如果有一个字符串,其中第 10
个字符为‘\ 0?,则此字符串的有效字符为 9个。也就是说,在遇到字符‘\ 0?时,表示字符串结束,
由它前面的字符组成字符串。
系统对字符串常量也自动加一个‘\ 0?作为结束符。
例如,c Program”共有 9个字符,但在内存中占 10
个字节,最后一个字节‘\ 0? 是由系统自动加上的。
字符串作为一维数组存放在内存中。
有了结束标志‘\ 0?后,字符数组的长度就显得不那么重要了。在程序中往往依靠检测‘\ 0? 的位置来判定字符串是否结束,而不是根据数组的长度来决定字符串长度。当然,在定义字符数组时应估计实际字符串长度,保证数组长度始终大于字符串实际长度。如果在一个字符数组中先后存放多个不同长度的字符串,则应使数组长度大于最长的字符串的长度。
说明:‘\ 0?代表 ASCII码为 0的字符,从 ASCII码表中可以查到,ASCII码为 0的字符不是一个可以显示的字符,而是一个“空操作符”,即它什么也不做。用它来作为字符串结束标志不会产生附加的操作或增加有效字符,只起一个供辨别的标志。
我们以前曾用过以下的语句:
printf("How do you do?\ n");
即输出一个字符串。在执行此语句时系统怎么知道应该输出到哪里为止呢?实际上,在内存中存放时,系统自动在最后一个字符‘\ n?的后面加了一个‘\ 0?作为字符串结束标志,在执行 printf函数时,每输出一个字符检查一次,看下一个字符是否‘\ 0?。遇‘\ 0?就停止输出。
对 c语言处理字符串的方法有以上的了解后,我们再对字符数组初始化的方法补充一种方法,可以用字符串常量来使字符数组初始化。例如 char c[]
={"I am happy"};也可以省略花括弧,直接写成
char c[] ="I am happy";
不是用单个字符作为初值,而是用一个字符串 (注意字符串的两端是用双引号而不是单引号括起来的 )
作为初值。显然,这种方法直观、方便、符合人们的习惯。数组 c的长度不是 10,而是 11,这点务请注意。因为字符串常量的最后由系统加上一个
‘\ 0?。因此,上面的初始化与下面的初始化等价。
char c[] ={'I',' ','a','m',' ','h','a','p',
'p','y','\ 0'};
而不与下面的等价:
char c\[] ={'I',' ','a','m',' ','h','a','p',
'p','y'};
前者的长度为 11,后者的长度为 10。如果有 char c
[ 10] ={"china"};
数组 c的前 5个元素为 'c','h','i','n','a',第 6个元素为‘\ 0?,后 4个元素为空字符。见图 7.10。
图 7.10
需要说明的是:字符数组并不要求它的最后一个字符为‘\
0?,甚至可以不包含‘\ 0?。像以下这样写完全是合法的:
char c[ 5] ={'c','h','i','n','a'};
是否需要加‘\ 0?,完全根据需要决定。但是由于系统对字符串常量自动加一个‘\ 0?。
因此,人们为了使处理方法一致,便于测定字符串的实际长度,以及在程序中作相应的处理,在字符数组也常常人为地加上一个‘\ 0?。如:
char c[ 6] ={'c','h','i','n','a','\ 0'};
7.3.5 字符数组的输入输出字符数组的输入输出可以有两种方法:
(1) 逐个字符输入输出。用格式符,%c”输入或输出一个字符,如例 7.6。
(2) 将整个字符串一次输入或输出。用,%S”格式符,
意思是输出字符串 (String)。例如:
char c[] ={"china"};
printf("%S",c);
在内存中数组 c的状态如图 7.11所示。输出时,遇结束符‘\ 0?就停止输出。输出结果为,
china
china\ 0
图 7.11
请注意:
(1) 输出字符不包括结束符‘\ 0?。
(2) 用,%S”格式符输出字符串时,printf函数中的输出项是字符数组名,而不是数组元素名。写成下面这样是不对的:
printf("%S",c[ 0] );
(3) 如果数组长度大于字符串实际长度,也只输出到遇‘\ 0?结束。如 char c[ 10] ={"china"};
printf("%S",c);
也只输出,china”5个字符,而不是输出 10个字符。
这就是用字符串结束标志的好处。
(4) 如果一个字符数组中包含一个以上‘\ 0?,则遇第一个‘\ 0?时输出就结束。
可以用 scanf函数输入一个字符串。例如
scanf("%S",c);
scanf函数中的输入项 c是字符数组名,它应该在先前已被定义。从键盘输入的字符串应短于已定义的字符数组的长度。例如,已定义
char c[ 6] ;
从键盘输入:
china
系统自动在后面加一个‘\ 0?结束符。如果利用一个 scanf函数输入多个字符串,则以空格分隔。例如:
char strl[ 5],Str2[ 5],Str3[ 5] ;
scanf("%S%S%S",Str1,Str2,Str3);
输入数据:
How are you?
输入后 Str1,Str2,Str3数组状态见图 7.12。数组中未被赋值的元素的值是不可预料的。
图 7.12
若改为
char str[ 13] ;
scanf("%S",Str);
如果输入以下 12个字符
How are you?
实际上并不是把这 12个字符加上‘\ 0?送到数组
Str中,而只将空格前的字符,How”送到 str中,由于把,How”作为一个字符串处理,因此在其后加
‘\ 0?。 Str数组状态见图 7.13。
需要注意,scanf函数中的输入项是字符数组名。输入项为字符数组名时,不要再加地址符 &,因为在 c语言中数组名代表该数组的起始地址。下面写法不对,scanf("%S",&Str);
图 7.14所示的数组,若其名字为 c,占 6个字节。程序中如果只写数组名 c,它就代表地址 2000。例如:
图 7.13
图 7.14
printf("%o",c);
可以输出数组 c的起始地址 2000。前面介绍的输出字符串的方法:
printf("%S",c);
实际上是这样执行的:按字符数组名 c找到其数组起始地址,然后逐个输出其中的字符,直到遇‘\ 0?
为止。
由于 c语言用一维字符数组存放字符串,而且允许用数组名进行输入或输出一个字符串,因此,也可以把一维字符数组看作相当于其他语言 (如 BASIC)
中的“字符串变量”。
7.3.6 字符串处理函数在 c的函数库中提供了一些用来处理字符串的函数,
使用方便。几乎所有版本的 c都提供这些函数。下面介绍几种常用的函数。
1,puts(字符数组 )
其作用是:将一个字符串 (以‘\ 0?结束的字符序列 )
输出到终端。假如已定义 Str是一个字符数组名,
且该数组已被初始化为,china”。则执行 PutS(Str);
其结果是在终端上输出 china。由于可以用 printf函数输出字符串,因此 Puts函数用的不多。用 Puts函数输出的字符串中可以包含转义字符。例如:
char str[] ={"china\ nbeijing"};
puts(str);
输出:
china
beijing
在输出时将字符串结束标志‘\ 0?转换成‘\ n?,
即输出完字符串后换行。
2,gets(字符数组 )
其作用是:从终端输入一个字符串到字符数组,并且得到一个函数值。该函数值是字符数组的起始地址。如执行下面的函数:
gets(str)
从键盘输入,computer
将输入的字符串,computer”送给字符数组 Str(请注意送给数组的共有 9个字符,而不是 8个字符 ),函数值为字符数组 Str的起始地址。一般利用 gets函数的目的是向字符数组输入一个字符串,而不大关心其函数值。
注意:用 Puts和 gets函数只能输入或输出一个字符串,不能写成 puts(str1,str2)或 gets(str1,str2)
3,strcat(字符数组 1,字符数组 2)
strcat是 string catenate(字符串连接 )的缩写。其作用是:连接两个字符数组中的字符串,把字符串 2接到字符串 1的后面,结果放在字符数组 1中,函数调用后得到一个函数值 ——字符数组 1的地址。例如:
char str1[ 30] ={"people's republic of "};
char str2[] ={"china"};
printf("%s",strcat(str1,str2));
输出:
people's republic of china
连接前后的状况见图 7.15所示。
图 7.15
说明:
(1) 字符数组 1必须足够大,以便容纳连接后的新字符串。本例中定义 Str1的长度为 30,是足够大的,
如果在定义时改用 Str1[] ={"PeoPle?s Rebuplic
of"};就会出问题,因长度不够。
(2) 连接前两个字符串的后面都有一个‘\ 0?,连接时将字符串 1后面的‘\ 0?取消,只在新串最后保留一个‘\ 0?。
4,strcPy(字符数组 1,字符串 2)
StrcPy是 STRing coPY(字符串复制 )的缩写。它是
“字符串复制函数”。作用是将字符串 2复制到字符数组 1中去。例如:
char str1[ 10],Str2[] ={"china"};
StrcPy(Str1,Str2);
执行后,Str1的状态如图 7.16所示。
图 7.16
说明:
(1) 字符数组 1必须定义得足够大,以便容纳被复制的字符串。字符数组 1的长度不应小于字符串 2的长度。
(2),字符数组 1”必须写成数组名形式 (如 Str1),“字符串
2”可以是字符数组名,也可以是一个字符串常量。如
Strcpy(Str1,"china");作用与前相同。
(3) 复制时连同字符串后面的‘\ 0?一起复制到字符数组
1中。
(4)不能用赋值语句将一个字符串常量或字符数组直接给一个字符数组。如下面两行都是不合法的:
Str1={"china"};
Str1=Str2;
而只能用 Strcpy函数处理。用赋值语句只能将一个字符赋给一个字符型变量或字符数组元素。如下面是合法的:
char a[ 5],c1,c2;
c1='a';c2='b';
a[ 0] ='c';a[ 1] ='h';a[ 2] ='i';a[ 3] ='n';a[ 4]
='a';
(5) 可以用 Strncpy函数将字符串 2中前面若干个字符复制到字符数组 1中去。例如,Strncpy(Str1,Str2,
2);
作用是将 Str2中前面 2个字符复制到 Str1中去,取代
Str1中最前面 2个字符。
5,strcmp(字符串 1,字符串 2)
Strcmo是 string compare(字符串比较 )的缩写。作用是比较字符串 1和字符串 2。例如:
Strcmp(Str1,Str2);
Strcmp("china","Korea");
Strcmp(Str1,"beijing");
字符串比较的规则与其他语言中的规则相同,即对两个字符串自左至右逐个字符相比 (按 ASCII码值大小比较 ),直到出现不同的字符或遇到‘\ 0?为止。如全部字符相同,则认为相等;若出现不相同的字符,则以第一个不相同的字符的比较结果为准。例如:
“a”<“b”,,a”>“a”,,computer”>“compare”,
,these”>“that”,,36+54”>“!&#”,
,china”>“canada”,,DOG”<“cat” 。
如果参加比较的两个字符串都由英文字母组成,则有一个简单的规律:在英文字典中位置在后面的为“大”。 例如 computer在字典中的位置在
compare之后。但应注意小写字母比大写字母
“大”,所以,DOG”<“cat”。比较的结果由函数值带回。
(1) 如果字符串 1=字符串 2,函数值为 0。
(2) 如果字符串 1>字符串 2,函数值为一正整数。
(3) 如果字符串 1<字符串 2,函数值为一负整数。
注意:对两个字符串比较,不能用以下形式:
if(Str1==Str2) printf(“yes");
而只能用
if(StrcmP(Str1,Str2)==0)printf(“yes”);
6,strlen(字符数组 )
Strlen是 String Lenght(字符串长度 )的缩写。它是测试字符串长度的函数。函数的值为字符串中的实际长度,不包括‘\ 0?在内。如:
char str[ 10] ={"china"};
printf("%d",Strlen(Str));
输出结果不是 10,也不是 6,而是 5。也可以直接测字符串常量的长度,如 Strlen("china");
7,strlwr(字符串 )
Strlwr是 String Lowercase (字符串小写 )的缩写。函数的作用是将字符串中大写字母换成小写字母。
8,struPr(字符串 )
Strupr是 String uppercase (字符串大写 )的缩写。函数的作用是将字符串中小写字母换成大写字母。
以上介绍了常用的 8种字符串处理函数,应当再次强调:
库函数并非 c语言本身的组成部分,而是人们为使用方便而编写、提供大家使用的公共函数。每个系统提供的函数数量和函数名、函数功能都不尽相同,使用时要小心,必要时查一下库函数手册。当然,有一些基本的函数 (包括函数名和函数功能 ),不同的系统所提供的是相同的,这就为程序的通用性提供了基础。
7.3.7 字符数组应用举例例 7.8输入一行字符,统计其中有多少个单词,单词之间用空格分隔开。
程序如下:
#include <Studio.h>
main()
{
char string[ 81] ;
int i,num=0,word=0;
char c;
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 wordS in the line.\ n",
num);
}
运行情况如下:
I am a boy.
There are 4 words in
the line.
程序中变量 i作为循环变量,num用来统计单词个数,word作为判别是否单词的标志,若 word=0表示未出现单词,如出现单词 word就置成 1。
算法见图 7.17所示。
图 7.17
解题的思路是这样的:单词的数目可以由空格出现的次数决定 (连续的若干个空格作为出现一次空格;一行开头的空格不统计在内 )。如果测出某一个字符为非空格,而它的前面的字符是空格,则表示“新的单词开始了”,此时使 num(单词数 )累加 1。如果当前字符为非空格而其前面的字符也是非空格,则意味着仍然是原来那个单词的继续,num不应再累加
1。前面一个字符是否空格可以从 word的值看出来,
若 word=0,则表示前一个字符是空格;如果
word=1,意味着前一个字符为非空格。可以用图
7.18表示。
图 7.18
程序中 for语句中的“循环条件”为
(c=String[ i] )!='\ 0'
它的作用是先将字符数组的某一元素 (一个字符 )赋给字符变量 c。此时赋值表达式的值就是该字符,然后再判定它是否结束符。这个“循环条件”包含了一个赋值操作和一个关系运算。可以看到用 for循环可以使程序简练。
例 7.9有 3个字符串,要求找出其中最大者。
今设一个二维的字符数组 Str,大小为 3× 20,即有 3行
20列,每一行可以容纳 20个字符。图 7.19表示此二维数组的情况。
图 7.19
如前所述,可以把 str[ 0],str[ 1],str[ 2]看作 3
个一维字符数组,它们各有 20个元素。可以把它们如同一维数组那样进行处理。可以用 gets函数分别读入 3个字符串。经过二次比较,就可得到值最大者,
把它放在一维字符数组 String中。
程序如下,
main ( )
{
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);
}
运行结果如下,
china
holland
america
the largest string is∶
holland
当然,这个题目也可以不采用二维数组,而设 3个一维字符数组来处理。读者可自己完成。
7.4 习题
7.1 用筛法求 100之内的素数。
7.2 用选择法对 10个整数排序。
7.3 求一个 3× 3矩阵对角线元素之和。
7.4 已有一个已排好序的数组,今输入一个数,要求按原来排序的规律将它插入数组中。
7.5 将一个数组中的值按逆序重新存放。例如,原来顺序为 8,6,5,4,1。要求改为 1,4,5,6,8。
7.6 打印出以下的杨辉三角形 (要求打印出 10行 )。
1
11
121
1331
14641
15101051
………………
7.7 找出一个二维数组中的鞍点,即该位置上的元素在该行上最大,在该列上最小。也可能没有鞍点。
7.8 有一篇文章,共有 3行文字,每行有 80个字符。要求分别统计出其中英文大写字母、小写字母、数字、
空格以及其他字符的个数。
7.9 有一行电文,已按下面规律译成密码,
a→Za→z
b→Yb→y
c→Xc→x
……
即第 1个字母变成第 26个字母,第 i个字母变成第 (26-
i+1)个字母。非字母字符不变。要求编程序将密码译回原文,并打印出密码和原文。
7.10 编一程序,将两个字符串连接起来,不要用 Strcat
函数。
7.11 编一个程序,将两个字符串 S1和 S2比较,如果
S1>S2,输出一个正数 ;S1=S2,输出 0;S1<S2,输出一个负数。不要用 Strcmp函数。两个字符串用 gets函数读入。输出的正数或负数的绝对值应是相比较的两个字符串相应字符的 ASCII码的差值。例如,“a”与
,c”相比,由于,a”<“c”,应输出负数,由于,a”与,c”
的 ASCII码差值为 2,因此应输出,-2”。同理,“and”
和,aid”比较,根据第 2个字符比较结果,“n”
比,i”大 5,因此应输出,5”。
7.12 编写一个程序,将字符数组 s2 中的全部字符拷贝到字符数组 s1 中。 不用 strcpy 函数。 拷贝时,
\ 0?也要拷贝过去。‘\ 0?后面的字符不拷贝。