第 10章 字符串
C语言是用一维字符数组来存储字符串
10.1 用一个一维字符数组来存储字符串
字符串:一系列字符组成的字符系列。在 C语言中所有以双引号括起来的字符都以字符串方式存储。如:” China”,“I am a boy.”,“a”,“A”
C语言中以字符’ \0?作为字符串的结束标志。’ \0?是转义字符,称为空字符,其 ASCII码为 0。’ \0?作为标志要占用存储空间( 1byte),
但不计入字符串的长度。
C语言中字符串常量就是一个一维字符数组,所以它给出的是该字符串的首地址。
例如:
char str[10],*ps;
str =,hello!”; /*ERROR*/
str是一维数组名,其为地址常量,不能再次赋值。
ps =,hello!”; /*OK*/
ps是字符指针,将字符串常量” hello!”赋值给
ps实际上是将该字符串在内存的首地址赋值给
ps
10.1.1 一维字符数组的初始化
用一般的给数组初始化的方法。如:
char str[10] = {?s?,?t?,?r?,?i?,?n?,?g?,?!?,?\0? };
上述初始化方式等价于
char str[10] = {?s?,?t?,?r?,?i?,?n?,?g?,?!? };
因为初值个数少于 10,系统会自动对未赋值的元素赋值 ‘ \0?
s t r i n g ! \0 \0 \0
初始化时也可以省略字符数组的大小,但此时必须人为地在字符串末尾加 ‘ \0? 以作为字符串结束标志。如:
char str1[ ] = {?C?,?h?,?i?,?n?,?a?,?\0? };
char str2[ ] = {?C?,?h?,?i?,?n?,?a? };
str1的长度为 5,占用 6个字节的存储空间,有字符串结束标志。 str2占用 5个字节的存储空间,
没有字符结束标志,系统不知道该字符串在哪里终止。
直接用字符串初始化字符数组。如:
char str[10] = {,string!” }; /*OK*/
习惯上可以简写为
char str[10] =,string!”; /*OK*/
系统会自动在字符串末尾加上 ‘ \0? 作为结束标志。
需要注意的是,定义的字符数组的元素个数一定要比字符串中的字符个数至少多一个,因为多的一个要存储结束标志 ‘ \0?,否则将破坏其他数据或程序代码。如:
char str[6] =,China”; /*OK*/
char str[5] =,China”; /*ERROR*/
也可用如下方式定义:
char str[ ] =,string!” /*OK*/
系统会自动在末尾加 ‘ \0?,str的元素个数为 8
char mark[10] =,C program.”; /*OK*/
char mark[10];
mark =,C Program.”; /*ERROR*/
char mark[10];
int i;
for(i = 0; i < 9; i++)
scanf("%c",&mark[i]);
mark[i] = '\0'; /*OK*/
10.2 字符串与字符指针
同数组一样,可以定义指针变量指向字符串。
实质上是将该字符串的首地址赋值给指针变量
char *ps =,from one”;
其实质是将无名字符串” from one”的起始地址赋值给指针变量 ps,此时
*ps 的值为 ‘ f?,*(ps+1)的值为’ r?。
char str[ ] =,from two”;
char *ps = str;
此时是将字符数组 str(也是字符串 )的首地址赋值给 ps,即 ps与 &str[0]是等价的。
字符数组与字符指针的区别
char mark[ ] =,C program”;
char *pmark =,C program”;
这两种方式存储的内存模型是不同的。
10.3 字符串的输入和输出
用 %c格式逐个地输入输出
用 %s格式整体输入和输出。如:
Char str[10];
Scanf(“%s”,str); /*OK*/
假如从键盘上输入,programC
字符数组:存放字符数据的数组,每一个元素存放一个字符。
一、程序中定义字符数组例、
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字节 */
二、字符数组的初始化
1、逐个元素初始化
static char c[10] = {'I',' ','a','m',' ','h','a','p','p','y'};
2、初始化数据少于数组长度,多余元素自动为“空”( '\0',二进制 0)。
static char c[10] = {'c',' ','p','r','o','g','r','a','m'}; /* 9 */
3、指定初值时,若未指定数组长度,则长度等于初值个数。
static char c[ ] = {'I',' ','a','m',' ','h','a','p','p','y'};
三、字符数组的引用引用一个元素,得到一个字符。
[例 7.6] 输出一个字符串。
main()
{static 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()
{static 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");
}
}
输出形状:
四、字符串字符串例子,"I am a boy"
1,C语言中,字符串作为字符数组处理。字符数组可以用字符串来初始化,例、
static char c[] = {"I am happy"};
也可以这样初始化:(不要大括号)
static char c[] = "I am happy";
2、字符串在存储时,系统自动在其后加上结束标志 '\0'(占一字节,其值为二进制 0)。但字符数组并不要求其最后一个元素是 '\0',例、
static char c[] = {"China"};
static char c[5] = {"China"};
static char c[10] = {"China"};
五、字符数组的输入输出两种方法:
1、用,%c”格式符逐个输入输出。
2、用,%s”格式符按字符串输入输出。例、
static char c[6];
scanf("%s",c);
printf("%s",c);
注意:
( 1)输出时,遇 '\0'结束,且输出字符中不包含 '\0'。
( 2),%s”格式输出字符串时,printf()函数的输出项是字符数组名,
而不是元素名。
static char c[6] = "China";
printf("%s",c); printf("%c",c[0]);
printf("%s",c[0]); ×
( 3),%s”格式输出时,即使数组长度大于字符串长度,
遇 '\0'也结束。例、
static char c[10] = {"China"};
printf("%s",c); /*只输出 5个字符 */
( 4),%s”格式输出时,若数组中包含一个以上 '\0',
遇第一个 '\0'时结束。
( 5)输入时,遇回车键结束,但获得的字符中不包含回车键本身( 0x0D,0x0A),而是在字符串末尾添 '\0'。
因此,定义的字符数组必须有足够的长度,以容纳所输入的字符。(如,输入 5个字符,定义的字符数组至少应有 6个元素)。
( 6)一个 scanf函数输入多个字符串,输入时以“空格”键作为字符串间的分隔。例、
static char str1[5],str2[5],str3[5];
scanf("%s%s%s",str1,str2,str3);
输入数据,How are you?
str1,str2,str3获得的数据见右图。
例、
static char str[13];
scanf("%s",str);
输入,How are you?
结果:仅,How”被输入数组 str
如要想 str获得全部输入(包含空格及其以后的字符),程序应设计为:
static char c[13];
int i;
for(i=0;i<13;i++) c[i] = getchar();
( 7) C语言中,数组名代表该数组的起始地址,因此,scanf()函数中不需要地址运算符 &。
例、
static char str[13];
scanf("%s",str);
scanf("%s",&str);
C语言中,数组名代表该数组的起始地址。如右图所示的数组 C,占 6个字节。
在程序中只写数组名 C,它就代表地址
2000。如
Printf(“%o”,c);
输出结果:
2000 /*数组 C在内存中的首地址 */ \0
a
n
i
h
C
2005
2004
2003
2002
2001
2000
C语言实际上是按字符数组名找到数组的起始地址,然后逐个输出一个个字符,直到遇到字符结束符 \0为止。其他类型的数组名其实也是该数组在内存中的起始地址 (基地址 )
[案例 7.5]从键盘输入一个字符串,回车键结束,并将字符串在屏幕上输出 。
/*案例代码文件名,AL6_5.C*/
main()
{int i;
static char str[80];
clrscr();
for(i=0;i<80;i++)
{ str[i]=getchar(); /*逐次给数组元素 str[i]赋值,但不回显在屏幕上 */
printf("*"); /*以星号代替输入字符的个数 */
if(str[i]=='\x0d') break; /*若输入回车则终止循环 */
}
i=0;
while(str[i]!='\x0d')
printf("%c",str[i++]); /*逐次输出字符数组的各个元素 */
printf("\n");
getchar(); /*程序暂停 */
}
复习:
1,字符数组的定义
1维字符数组,用于存储和处理 1个字符串,其定义格式与 1维数值数组一样 。
2维字符数组,用于同时存储和处理多个字符串,
其定义格式与 2维数值数组一样 。
2,字符数组的初始化字符数组的初始化,可以通过为每个数组元素指定初值字符来实现 。
3,字符数组的引用字符数组的逐个字符引用,与引用数值数组元素类似 。
( 1) 字符数组的输入除了可以通过初始化使字符数组各元素得到初值外,也可以使用 getchar()或 scanf()函数输入字符 。
例如:
char str[10];
……
for(i=0; i<10; i++)
{ scanf("%c",&str[i]);
fflush(stdin); /*清除键盘输入缓冲区 */
}
……
( 2) 字符数组的输出字符数组的输出,可以用 putchar()或 printf()
函数 。
例如:
char str[10]="c language";
……
for(i=0; i<10; i++) printf("%c",str[i]);
printf("\n");
……
注意,逐个字符输入,输出时,要指出元素的下标,而且使用,%c”格式符 。 另外,从键盘上输入字符时,无需输入字符的定界符 ──单引号;输出时,系统也不输出字符的定界符 。
7.3.2 字符数组的整体操作
[案例 7.6] 字符数组的整体输入与输出 。
/*案例代码文件名,AL6_6.C*/
/*功能:将 2维字符数组进行初始化,并在屏幕上输出 */
main()
{ int i;
char name[5][9]={"张三山 ","李四季 ","王五魁 ","刘六顺 ","赵七巧 "};
for(i=0;i<5;i++)
printf("\n%s\t",name[i]); /*name[i]代表该行数组元素的首地址 */
getchar();
}
1.字符串及其结束标志所谓字符串,是指若干有效字符的序列。 C语言中的字符串,可以包括字母、数字、专用字符、转义字符等。
C语言规定:以‘ \0’作为字符串结束标志(‘ \0’代表
ASCII码为 0的字符,表示一个“空操作”,只起一个标志作注意,由于系统在存储字符串常量时,会在串尾自动加上 1个结束标志,所以无需人为地再加 1个 。
另外,由于结束标志也要在字符数组中占用一个元素的存储空间,
因此在说明字符数组长度时,至少为字符串所需长度加 1。
2,字符数组的整体初始化字符串设置了结束标志以后,对字符数组的初始化,就可以用字符串常量来初始化字符数组 。
3,字符数组的整体引用
( 1) 字符串的输入除了可以通过初始化使字符数组各元素得到初值外,也可以使用
scanf()函数输入字符串 。
( 2) 字符串的输出
printf()函数,不仅可以逐个输出字符数组元素,还可以整体输出存放在字符数组中的字符串 。
7.3.3 常用的字符串处理函数字符串标准函数的原型在头文件 string.h中 。
1,输入字符串 ──gets()函数
( 1) 调用方式,gets(字符数组 )
( 2) 函数功能:从标准输入设备 (stdin)──键盘上,读取 1个字符串 ( 可以包含空格 ),并将其存储到字符数组中去 。
( 3) 使用说明
1) gets()读取的字符串,其长度没有限制,编程者要保证字符数组有足够大的空间,存放输入的
2,输出字符串 ──puts()函数
( 1) 调用方式,puts(字符数组 )
( 2) 函数功能:把字符数组中所存放的字符串,
输出到标准输出设备中去,并用 ‘ \n’取代字符串的结束标志 ‘ \0’。 所以用 puts()函数输出字符串时,
不要求另加换行符 。
( 3) 使用说明
1)字符串中允许包含转义字符,输出时产生一个控制操作 。
2)该函数一次只能输出一个字符串,而 printf()
函数也能用来输出字符串,且一次能输出多个 。
3,字符串比较 ── strcmp()函数
( 1) 调用方式,strcmp(字符串 1,字符串 2)
其中,字符串,可以是串常量,也可以是 1维字符数组 。
( 2) 函数功能:比较两个字符串的大小 。
如果,字符串 1=字符串 2,函数返回值等于 0;
字符串 1<字符串 2,函数返回值负整数;
字符串 1>字符串 2,函数返回值正整数 。
( 3) 使用说明
1) 如果一个字符串是另一个字符串从头开始的子串,则母串为大 。
2) 不能使用关系运算符,==,来比较两个字符串,只能用
strcmp() 函数来处理 。
[案例 7.7] gets函数和 strcmp函数的应用 。
/*案例代码文件名,AL6_7.C,功能:简单密码检测程序 */
#include "stdio.h"
main()
{char pass_str[80]; /*定义字符数组
pass_str*/
int i=0;
/*检验密码 */
while(1)
{clrscr();
printf("请输入密码 \n");
gets(pass_str); /*输入密码 */
if(strcmp(pass_str,“password”)!=0) /*口令错 */
printf("口令错误,按任意键继续 ");
else
break; /*输入正确的密码,中止循环 */
getch();
i++;
4,拷贝字符串 ── strcpy()函数
( 1) 调用方式,strcpy(字符数组,字符串 )
其中,字符串,可以是串常量,也可以是字符数组 。
( 2) 函数功能:将,字符串,完整地复制到,字符数组,中,字符数组中原有内容被覆盖 。
( 3) 使用说明
1) 字符数组必须定义得足够大,以便容纳复制过来的字符串 。 复制时,连同结束标志 '\0'一起复制 。
2) 不能用赋值运算符,=,将一个字符串直接赋值给一个字符数组,只能用 strcpy()函数来处理 。
5,连接字符串 ── strcat()函数
( 1) 调用方式,strcat(字符数组,字符串 )
( 2) 函数功能:把,字符串,连接到,字符数组,中的字符串尾端,并存储于,字符数组,中 。,字符数组,
中原来的结束标志,被,字符串,的第一个字符覆盖,而
,字符串,在操作中未被修改 。
( 3) 使用说明
1) 由于没有边界检查,编程者要注意保证,字符数组,定义得足够大,以便容纳连接后的目标字符串;否则,
会因长度不够而产生问题 。
2) 连接前两个字符串都有结束标志 '\0',连接后,字符数组,中存储的字符串的结束标志 '\0'被舍弃,只在目标串的最后保留一个 '\0'。
6,求字符串长度 ── strlen()函数 ( len是 length的缩写 )
( 1) 调用方式,strlen(字符串 )
( 2) 函数功能:求字符串 ( 常量或字符数组 ) 的实际长度 ( 不包含结束标志 ) 。
7,将字符串中大写字母转换成小写 ── strlwr()函数
( 1) 调用方式,strlwr(字符串 )
( 2) 函数功能:将字符串中的大写字母转换成小写,其它字符
( 包括小写字母和非字母字符 ) 不转换 。
8,将字符串中小写字母转换成大写 ── strupr()函数
( 1) 调用方式,strupr(字符串 )
( 2) 函数功能:将字符串中小写字母转换成大写,其它字符
( 包括大写字母和非字母字符 ) 不转换 。
[例 7.9] 输入三个字符串,并找出其中最大者。
分析:用 strcmp()函数比较字符串的大小。首先比较前两个,把较大者拷贝给字符数组变量 string(用 strcpy()函数拷贝),再比较 string和第三个字符串。
程序:设字符串最长为 19个字符。
#include "string.h" /* strcmp,strcpy函数均在 string.h中定义 */
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);
}
本章要求及作业数组是程序设计的常用数据结构,字符串(字符数组)在现代程序中也用得相当普遍,应掌握它们的意义和用法。
1、数组(一维和二维,下同)名、数组元素的概念。
2、数组的初始化方法。
3、数组元素在内存中的存储顺序。
4、数据排序算法。
5、字符串的特点(作为数组处理、最后一字节加 '\0')。
6、字符串处理函数的应用。
作业:
7.2,7.3,7.4,7.6,7.7,7.9,7.10,7.13
上机:
( 1)作业及熟悉 Turbo C在线帮助系统的用法。