1、新编C语言程序设计教程 清华大学出版社周二强周二强 软件学院软件学院 计算机科学与工程系计算机科学与工程系配套视频:配套视频: 博客:博客: 6章章 数组数组6.3 6.3 字符数组和字符串字符数组和字符串6.3.1 字符数组6.3.2 字符串6.3.3 字符串输入输出6.3.4 字符串相关程序示例6.4 6.4 综合示例:求大数的阶乘综合示例:求大数的阶乘 第2页,共31页。6.3.1 6.3.1 字符数组字符数组字符数组是元素类型为字符型的数组,既有一维字符数字符数组是元素类型为字符型的数组,既有一维字符数组,又有多维字符数组。数组具有的特征,字符数组也不组,又有多维字符数组。数组具有的特
2、征,字符数组也不例外。由于字符型的特殊性,在使用字符数组时需注意:例外。由于字符型的特殊性,在使用字符数组时需注意:1.1.虽然初始化数组时可以用各种形式的字符型字面量,虽然初始化数组时可以用各种形式的字符型字面量,但要考虑程序的可读性。如有但要考虑程序的可读性。如有char ca6=char ca6=C C,72,72,111111,x4ex4e,x41x41,nn;语句时,字符型数组语句时,字符型数组caca的的各元素为各元素为2.2.字符型与整型的区别与联系。字符型与整型的区别与联系。第3页,共31页。例6-11例例6-11 6-11 输入由数字组成的一串字符,输出与这个数字输入由数字组
3、成的一串字符,输出与这个数字串相对应的整数。如输入串相对应的整数。如输入523523回车(回车(5 5,2 2,3 3),则输),则输出出523523(五百二十三)。(五百二十三)。分析:用字符数组存储这个数字串;用循环获得输入,分析:用字符数组存储这个数字串;用循环获得输入,遇到回车符时结束。为了便于处理,可在这个数字串的末遇到回车符时结束。为了便于处理,可在这个数字串的末尾加一个空字符(尾加一个空字符(nullnull)作为结束标志。)作为结束标志。第4页,共31页。例6-11return第5页,共31页。6.3.2 字符串前面指出,字符串就是用一对双撇号(前面指出,字符串就是用一对双撇号
4、()括起来的一)括起来的一串字符型字面量。这样理解字符串不太确切。串字符型字面量。这样理解字符串不太确切。C C语言规定,语言规定,字符串必须以空字符字符串必须以空字符00结束。因此,字符串是用一对双结束。因此,字符串是用一对双撇号(撇号()括起来的以空字符)括起来的以空字符00结束的一串字符型字面结束的一串字符型字面量。量。作为结束标志的空字符作为结束标志的空字符00显然不能出现在字符串的中显然不能出现在字符串的中间,因为在字符串中只要遇到空字符间,因为在字符串中只要遇到空字符00,就认为字符串,就认为字符串已经结束。已经结束。第6页,共31页。字符串为简便在书写时经常忽略字符串的结束标志为
5、简便在书写时经常忽略字符串的结束标志00,但在,但在使用时系统会自动在字符串后面加上结束标志。如字符串使用时系统会自动在字符串后面加上结束标志。如字符串ChinaChina的实际长度(包括空字符的实际长度(包括空字符00)为)为6 6,有效长度是,有效长度是5 5。第7页,共31页。字符串在在C C语言中常用字符数组存储字符串。存放在字符数组语言中常用字符数组存储字符串。存放在字符数组中的字符串分散成了一个个字符变量,因此很容易进行与中的字符串分散成了一个个字符变量,因此很容易进行与字符串相关的操作,如查找某个字符是否包含在字符串等。字符串相关的操作,如查找某个字符是否包含在字符串等。C C语
6、言中,字符串可以用来初始化字符数组。如语言中,字符串可以用来初始化字符数组。如char char c =China;c =China;或直接写成或直接写成char c =China;char c =China;。第8页,共31页。注意1.1.上面的初始化语句与上面的初始化语句与char c =char c =C C,h h,i i,n n,a a;并不等价,;并不等价,而与而与char c6=char c6=C C,h h,i i,n n,a a,00;等价;等价(最后一个空字符可以省略而自动赋值为(最后一个空字符可以省略而自动赋值为00)。)。2.2.设设c c是一个长度为是一个长度为101
7、0的字符数组,则赋值语句的字符数组,则赋值语句c=c=ChinaChina;并不正确,;并不正确,用字符串直接给字符数组赋值的格式只能用于初始化语用字符串直接给字符数组赋值的格式只能用于初始化语句。句。char c =China;char c =China;return第9页,共31页。6.3.3 6.3.3 字符串的输入输出字符串的输入输出用用printfprintf函数和函数和scanfscanf函数输入输出字符串时用格式符函数输入输出字符串时用格式符串串“%s”%s”。如有。如有char c=China;char c=China;,则语句,则语句printf(%s,c);printf(%
8、s,c);的输出结果为的输出结果为ChinaChina,在用,在用printfprintf函数函数输出字符串时需注意:输出字符串时需注意:1.1.与格式符串与格式符串“%s”%s”对应的变量为数组名对应的变量为数组名c c,而非数组,而非数组元素元素c0c0(c0c0是一个字符变量与格式符串是一个字符变量与格式符串“%c”%c”相对应)。相对应)。2.2.字符串中的结束标志空字符字符串中的结束标志空字符00并不输出。并不输出。第10页,共31页。注意:NowNow输出字符串时,遇到结束标志空字符输出字符串时,遇到结束标志空字符00时输出就结束时输出就结束了。了。第11页,共31页。字符串的输入
9、字符串的输入如有如有char c =I am ready!;scanf(%s,c)char c =I am ready!;scanf(%s,c),则从键盘输入则从键盘输入ChinaChina并回车后,数组并回车后,数组c c的状态为的状态为 第12页,共31页。一次输入多个字符串一次输入多个字符串时,空格符可用来分隔字符串一次输入多个字符串时,空格符可用来分隔字符串如有如有char str010,str110,str210;char str010,str110,str210;scanf(%s%s%s,str0,str1,str2);scanf(%s%s%s,str0,str1,str2);则输
10、入则输入Are you readyAre you ready?回车时,各个数组的状态为?回车时,各个数组的状态为scanf函数遇到空格符便认为一个字符串输入结束有时会带来不便,如无法通过scanf(%s,str);语句,把字符串Are you ready?输入到字符数组str中。第13页,共31页。专用的输入输出函数 标准函数库(标准函数库(stdio.hstdio.h)中也为字符串提供了专用的输)中也为字符串提供了专用的输入输出函数:入输出函数:putsputs函数和函数和getsgets函数。函数。putsputs函数的使用形式为:函数的使用形式为:putsputs(字符数组变量);(字符
11、数组变量);其作用是将字符数组中存储的字符串输出到输出设备上。其作用是将字符数组中存储的字符串输出到输出设备上。如有如有char str =HenannChinachar str =HenannChina;,则;,则puts(str)puts(str);的输出结果为:的输出结果为:HenanHenan China Chinaputsputs函数输出完字符串后会自动换行,也就是说函数输出完字符串后会自动换行,也就是说putsputs(strstr);与);与printfprintf(%sn%sn,strstr);等价。);等价。第14页,共31页。gets函数getsgets函数的使用形式为:函
12、数的使用形式为:gets(gets(字符数组变量字符数组变量);其作用是把输入设备输入的字符串存储到字符数组中。其作用是把输入设备输入的字符串存储到字符数组中。如有语句如有语句gets(str)gets(str);,从键盘输入:;,从键盘输入:Are you readyAre you ready?回车?回车则字符数组则字符数组strstr中的字符串为中的字符串为Are you readyAre you ready?。也就。也就是说是说getsgets函数认为空格符只是字符串中的一个普通字符,函数认为空格符只是字符串中的一个普通字符,回车才是一个字符串输入结束的唯一标志,这是它与回车才是一个字符
13、串输入结束的唯一标志,这是它与scanfscanf函数的最大区别。函数的最大区别。return第15页,共31页。6.3.4 6.3.4 字符串相关程序示例字符串相关程序示例例例6-12 6-12 有语句有语句scanf(%d%d,&m,&n);scanf(%d%d,&m,&n);,当用键盘输,当用键盘输入入23 5223 52回车时,变量回车时,变量m,nm,n的值分别为的值分别为2323和和5252。整个过程可。整个过程可简单地理解为:系统首先把来自键盘的输入放在一个字符简单地理解为:系统首先把来自键盘的输入放在一个字符数组中,遇到回车符后就把该字符数组交由数组中,遇到回车符后就把该字符数
14、组交由scanfscanf函数处函数处理。理。scanfscanf函数根据格式符,把字符串转换成相对应类型函数根据格式符,把字符串转换成相对应类型的数据,并赋给对应的变量。的数据,并赋给对应的变量。scanfscanf函数的本次处理过程可简单模拟如下:函数的本次处理过程可简单模拟如下:第16页,共31页。例6-12第17页,共31页。例6-13 比较两个字符串的大小。分析:比较两个字符时,分析:比较两个字符时,ASCIIASCII码大的字符大于码大的字符大于ASCIIASCII码码小的字符。比较两个字符串的大小时,从左向右依次比较小的字符。比较两个字符串的大小时,从左向右依次比较它们所含的字符
15、,它们所含的字符,如果相应位置上的字符不相同,如果相应位置上的字符不相同,则停止比较且相关字符串的大小就看此位置上的字符的则停止比较且相关字符串的大小就看此位置上的字符的大小。两个字符串完全一样时,显然它们相等。大小。两个字符串完全一样时,显然它们相等。第18页,共31页。例6-13return第19页,共31页。6.4 6.4 综合示例:求大数的阶乘综合示例:求大数的阶乘求阶乘的算法比较简单,但由于基本数据类型取值范围求阶乘的算法比较简单,但由于基本数据类型取值范围的限制,无法求出稍大数的阶乘。的限制,无法求出稍大数的阶乘。无符号长整型的最大取值约为无符号长整型的最大取值约为4343亿即亿即
16、1010位整数;双精度位整数;双精度浮点数的最大取值虽然可以达到浮点数的最大取值虽然可以达到300300位,但它的精度有限,位,但它的精度有限,只能准确表示约只能准确表示约1616位的数。一个稍大点整数的阶乘往往成位的数。一个稍大点整数的阶乘往往成百上千位,显然不能用百上千位,显然不能用C C语言中的基本数据类型表示。语言中的基本数据类型表示。第20页,共31页。大整数的表示如何表示大整数呢?如何表示大整数呢?258520167388849766400002585201673888497664000025852 01673 88849 76640 00025852 01673 88849 76
17、640 000258 52016 73888 49766 40000258 52016 73888 49766 400002585201673888497664000040000497667388852016258第21页,共31页。大整数的表示数组的长度可以很大,因此可以用无符号长整型的一维数组的长度可以很大,因此可以用无符号长整型的一维数组一个大整数。数组的每个元素表示整数的一位或几位。数组一个大整数。数组的每个元素表示整数的一位或几位。如定义一个长度为如定义一个长度为1010万的无符号长整型一维数组,让每个万的无符号长整型一维数组,让每个数组元素表示整数的数组元素表示整数的5 5位,则该
18、数组可以表示一个长达位,则该数组可以表示一个长达5050万位的大整数。万位的大整数。现有现有unsigned long result50000=0unsigned long result50000=0;,如果用;,如果用数组数组resultresult存储整数存储整数1212的阶乘的阶乘479001600479001600,则数组,则数组resultresult的状态为:的状态为:第22页,共31页。输出大整数注意:整数注意:整数5 5位一组,由低位到高位依次存储在数组中。位一组,由低位到高位依次存储在数组中。result0result0的值为的值为16001600(并非(并非01600016
19、00),输出时),输出时用语句用语句printf(%5d%05dprintf(%5d%05d,result1result1,result0)result0);就可输出整数就可输出整数479001600479001600。第23页,共31页。计算过程1313的阶乘的阶乘62270208006227020800,数组,数组resultresult第24页,共31页。计算过程设数组设数组resultresult中的值为中的值为1313的阶乘的阶乘62270208006227020800,此时,此时result0result0的值为的值为2080020800,result1result1的值为的值为6
20、227062270。设整型变量设整型变量iValidiValid的值为数组的值为数组resultresult中非零元素的最大中非零元素的最大下标,则这里下标,则这里iValidiValid的值为的值为1 1。用数组。用数组resultresult存储的大整存储的大整数乘以数乘以1414得到得到1414的阶乘的过程如下:的阶乘的过程如下:第25页,共31页。第一步第一步:第一步:resultresult中的有效元素(非零元素)分别乘以中的有效元素(非零元素)分别乘以1414;此为循环,循环变量此为循环,循环变量j j由由0 0至至iValidiValid,对于第,对于第j j次循环有次循环有re
21、sultj resultj*=14=14。(相乘后,相乘后,result0result0的值为的值为291200291200,result1result1的值为的值为871780)871780)第26页,共31页。第二步:“进位”处理。相乘后,相乘后,result0result0的值为的值为291200291200,result1result1的值为的值为871780871780resultresult中的每位数组元素只能存中的每位数组元素只能存5 5位,相乘后多出的位数就位,相乘后多出的位数就是是“进位进位”,需要向前进位。此处理也为循环,循环变量,需要向前进位。此处理也为循环,循环变量k
22、k从从0 0到到iValidiValid,对于第,对于第k k次循环有(整型变量次循环有(整型变量carrycarry用于存储进位):用于存储进位):carry=resultk/100000;carry=resultk/100000;resultk%=100000;resultk%=100000;resultk+1+=carry;resultk+1+=carry;第27页,共31页。最高位是否也向前进位处理完进位后还需要判断最高位是否也向前进位了,以处理完进位后还需要判断最高位是否也向前进位了,以便调整便调整iValidiValid的值。的值。(处理完后:(处理完后:result0result
23、0的值为的值为9120091200,result1result1的值的值为为7178271782,result2result2的值为的值为8 8,iValidiValid的值为的值为2 2)第28页,共31页。输出结果最高最高5 5位不用考虑补位不用考虑补0 0直接用语句直接用语句printf(%5d,printf(%5d,resultiValidresultiValid);输出,其余的用循环输出,循环变量输出,其余的用循环输出,循环变量i i从从iValidiValid1 1至至0 0,对于第,对于第i i次输出有次输出有printf(%05dprintf(%05d,resulti);resulti);第29页,共31页。第30页,共31页。return第31页,共31页。