1 / 28

实验七 字符串编程

实验七 字符串编程. 一、实验目的. 掌握字符串的概念 理解字符数组和字符指针的区别 熟悉常用的字符串库函数的用法 掌握字符指针变量和字符指针数组作函数参数的方法. 二、实验内容. 1 、字符串基本概念 在 C 语言中一串以 ’ ’ 结尾的字符被看作是字符串。当 C 语言编译器在程序中遇到长度为 n 的字符串字面量时,它会为字符串字面量分配长度为 n+1 的内存空间。这块内存空间将用来存储字符串字面量中的字符,以及一个额外的字符 —— 空字符。空字符用来标志字符串的末尾。空字符是 ASCII 字符集中真正的第一个字符,因此它用转义序列 来表示。.

Download Presentation

实验七 字符串编程

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 实验七 字符串编程

  2. 一、实验目的 • 掌握字符串的概念 • 理解字符数组和字符指针的区别 • 熟悉常用的字符串库函数的用法 • 掌握字符指针变量和字符指针数组作函数参数的方法

  3. 二、实验内容 • 1、字符串基本概念 • 在C语言中一串以’\0’结尾的字符被看作是字符串。当C语言编译器在程序中遇到长度为 n 的字符串字面量时,它会为字符串字面量分配长度为 n+1 的内存空间。这块内存空间将用来存储字符串字面量中的字符,以及一个额外的字符——空字符。空字符用来标志字符串的末尾。空字符是 ASCII 字符集中真正的第一个字符,因此它用转义序列\0 来表示。

  4. 既然字符串字面量是作为数组来存储的,那么编译器会把它看作是char * 类型的指针。例如,printf函数和scanf函数都接收char *类型的值作为它们的第一个参数。思考下面的例子: printf("abc"); • 当调用 printf函数时,会传递"abc"的地址(即指向字母 a 存储单元的指针)。

  5. a)字符串字面量与字符常量 • 只包含一个字符的字符串字面量不同于字符常量。字符串字面量"a"是用指针来表示的,这个指针指向存放字符"a"(以及随后的空字符)的内存单元。字符常量'a'是用整数(字符的ASCII 码)来表示的。 • 不要在需要字符串的时候使用字符(或者反之亦然)。 下面的函数调用是合法的: printf("\n"); • 因为 printf函数期望指针作为它的第一个参数。然而,下面的调用却是非法的: printf('\n'); /*** WRONG ***/

  6. b)字符串变量 • 假设需要变量用来存储最多 80 个字符的字符串。既然字符串会在末尾处需要空字符,那么要声明的变量是含有 81 个字符的数组: #define STR_LEN 80 [惯用法] char str[STR_LEN+1]; • 注意这里把 STR_LEN定义为 80 而不是 81,因此强调的事实是 str 可以存储最多 80 个字符的字符串。对宏加一的这种方法是C程序员常用的方式。 • 当声明用于存放字符串的字符数组时,始终要保证数组的长度比字符串的长度多一个字符。这是因为 C 语言规定每个字符串都要以空字符结尾。如果没有给空字符预留位置,可能会导致程序运行时出现不可预知的结果,因为 C 函数库中的函数假设字符串都是以空字符结束的。

  7. c)初始化字符串变量 • 字符串变量可以在声明时进行初始化: char date1[8] = "June 14"; • 编译器将把字符串"June 14"中的字符复制到数组 date1中,然后追加一个空字符从而使 date1可以作为字符串使用。虽然"June 14"看起来是字符串字面量,但其实不然。C编译器会把它看成是数组初始化式的缩写形式。实际上,我们可以写成: char date1[8] = {'J', 'u', 'n', 'e', ' ', '1', '4', '\0'}; • 相信大家都会认同原来的方式看起来更便于阅读。 • 如果初始化式比字符串变量长时又会怎样呢?这对字符串而言是非法的,就如同对数组是非法的一样。然而,C语言允许初始化式(不包括空字符)与变量有完全相同的长度: char date3[7] = "June 14"; • 编译器把初始化式中的字符简单地复制到date3 中,没有空间给空字符,所以编译器也不会试图存储一个空字符。

  8. 如果计划初始化用来放置字符串的字符数组,一定要确保数组的长度要长于初始化式的长度。否则,编译器将忽略空字符,这将使得数组无法作为字符串使用。如果计划初始化用来放置字符串的字符数组,一定要确保数组的长度要长于初始化式的长度。否则,编译器将忽略空字符,这将使得数组无法作为字符串使用。 • 字符串变量的声明可以忽略它的长度。这种情况下,编译器会自动计算长度: char date4[] = "June 14"; • 编译器为 date4 分配 8个字符的空间,这足够存储"June 14"中的字符和一个空字符。(事实是date4 的长度没有指明不意味着稍候可以改变数组的长度。一旦编译了程序,那么 date4的长度就固定是 8 了。)如果初始化式很长,那么忽略字符串变量的长度是特别有效的,因为手工计算长度很容易出错。

  9. d)字符串字面量的操作 • 通常情况下可以在任何 C语言允许使用 char *指针的地方使用字符串字面量。例如,字符串字面量可以出现在赋值运算符的右边: char *p; p = "abc"; • 这个赋值操作不是复制"abc"中的字符,而仅仅是使 p 指向字符串的第一个字符。 • 允许改变字符串字面量中的字符,但是不推荐这么做: char *p = "abc"; *p = 'b'; /* string literal is now "bbc" */ • 对于一些编译器而言,改变字符串字面量可能会导致程序运行异常。

  10. e)字符数组与字符指针 • 一起来比较一下下面两个声明: char date[] = "June 14"; • 它声明 date 是个字符数组。和这个声明相似的是下面这个声明: char *date = "June 14"; • 它声明 date 是个指向字符串字面量的指针。正因为有了数组和指针之间的紧密关系,才使上面两个声明中的 date都可以作为字符串。尤其是,任何期望传递字符数组或字符指针的函数都将接收这两种声明的date作为参数.

  11. 然而,需要注意,不能错误地认为上面两种 date可以互换。两者之间有着显著的差异: • 在声明为数组时,就像任意数组元素一样,可以修改存储在 date 中的字符。在声明为指针时,date 指向字符串字面量,从第4小节知是不可以修改字符串字面量的。 • 在声明为数组时,date 是数组名。在声明为指针时,date是变量,这个变量可以在程序执行期间指向其他字符串。

  12. 如果需要可以修改的字符串,那么就要建立字符数组用来存储字符串。这时声明指针变量是不够的。如果需要可以修改的字符串,那么就要建立字符数组用来存储字符串。这时声明指针变量是不够的。 • 下面的声明使编译器为指针变量分配了足够的内存空间: char *p; • 可惜的是,它不为字符串分配空间。(这怎么可能呢?因为我们没有指明字符串的长度。)在使用 p 作为字符串之前,必须把 p 指向字符数组。一种可能是把 p 指向已经存在的字符串变量: char str[STR_LEN+1], *p; p = str; • 现在 p 指向了 str 的第一个字符,所以可以把p 作为字符串使用了。

  13. 使用未初始化的指针变量作为字符串是非常严重的错误。考虑下面的例子,它试图创建字符串"abc": char *p; p[0]='a'; /*** WRONG ***/ p[1]='b'; /*** WRONG ***/ p[2]='c'; /*** WRONG ***/ p[3]='\0'; /*** WRONG ***/ • 因为 p 没有初始化,所以我们不知道它指向哪里。把字符 a、b、c 和\0 写入 p所指向的内存将会对程序产生无法预期的影响。程序可能没有错误继续运行,或者可能崩溃,或者可能行为异常。

  14. 2、字符串的读/写 • 使用printf函数或 puts 函数来写字符串是很容易的。读入字符串却有点麻烦,主要是因为输入的字符串可能比用来存储的字符串变量更长。为了一次性读入字符串,可以使用scanf函数或 gets函数,也可以以每次一个字符的方式读入字符串。

  15. a)用 printf 函数和 puts 函数写字符串 • 转换说明%s 允许 printf函数写字符串。参考下面的例子: char str[] = "Are we having fun yet?" printf("Value of str: %s\n", str); • 输出会是 Value of str: Are we having fun yet? • printf函数会逐个写字符串中的字符直到遇到空字符才停止。(如果空字符丢失,printf函数会越过字符串的末尾继续写,直到最终在内存的某个地方找到空字符为止。) • 如果只显示字符串的一部分,可以使用转换说明%.ps。这里的 p是要显示的字符数量。语句 printf("%.6s\n", str); • 会显示出:Are we

  16. 就像数一样,字符串可以在指定域内显示。 转换说明%ms 会在大小为 m的域内显示字符串。(对于超过 m个字符的字符串,printf函数会显示出整个字符串,而不会截断。)如果字符串少于 m个字符,则会在域内右对齐输出。为了强制左对齐,可以在m前加一个减号。m值和p值可以组合使用:转换说明%m.ps 会使字符串的前 p 个字符在大小为 m的域内显示。 • printf函数不是唯一一个字符串输出函数。C函数库还提供 puts 函数。此函数可以按如下方式使用: puts(str); • puts 函数只有一个参数, 此参数就是需要显示的字符串, 参数中没有格式串。 在写完字符串后,puts 函数总会添加一个额外的换行符,因此显示会移至下一输出行的开始处。

  17. 输入并运行以下程序,观察程序运行结果。参考程序如下:输入并运行以下程序,观察程序运行结果。参考程序如下: #include <stdio.h> void main() { int i; char string1[5]={'A','B','C','D','E'}; char string2[6]={'A','B','C','D','E','\0'}; char string3[6]="ABCDE\0"; char string4[5]="ABCDE"; printf("string1= \"%s\"\n",string1); //第9行 printf("string2= \"%s\"\n",string2); printf("string3= \"%s\"\n",string3); printf("string4= \"%s\"\n",string4); } • 对于上面的程序,将第9行改为:for (i=0;i<5;i++) printf("c",string1[i]); 运行修改后的程序,观察显示的结果。试分析其中的原因。

  18. b)逐个字符读字符串 • 对许多程序而言,因为 scanf函数和gets函数都有风险且不够灵活,C程序员经常会编写自己的输入函数。通过每次一个字符的方式来读入字符串,这类函数可以提供比标准输入函数更大程度的控制。 • 如果决定设计自己的输入函数,那么就需要考虑下面这些问题: • 在开始存储字符串之前,函数应该跳过空白字符吗? • 什么字符会导致函数停止读取:换行符、任意空白字符、还是其他一些字符?需要存储这类字符还是忽略掉? • 如果输入的字符串太长以致无法存储,那么程序应该做些什么:忽略额外的字符,还是把它们留给下一次的输入操作?

  19. 假定需要的函数不会跳过空白字符,在第一个换行符处(不把换行符存储到字符串中)停止读取,并且忽略额外的字符。函数将有如下原型: int read_line(char str[], int n); • str 表示用来存储输入的数组,而且 n 是最大读入字符的数量。如果输入行包含多于 n 个的字符,read_line 函数将忽略多余的字符。read_line 函数会返回实际存储在str中的字符数量(在 0到 n 之间的任意数)。不可能总是需要 read_line 函数的返回值,但是有这个返回值也没问题。

  20. read_line函数主要由一个循环构成,只要str 留有空间,那么此循环就逐个读入字符并且把它们存储起来。在读入换行符时循环终止。下面是 read_line 函数的完整定义: int read_line(char str[], int n) { char ch; int i = 0; while ((ch = getchar()) ! = '\n') { if (i < n) { str[i++] = ch; } } str[i] = '\0' /* terminates string */ return i; /* number of characters stored */ }

  21. 返回之前,read_line 函数在字符串的末尾放置了一个空字符。就像 scanf函数和 gets函数一样,标准函数会自动在输入字符串的末尾放置一个空字符。然而,如果你正在写自己的输入函数,那么必须要考虑这一点。 • 3、常用的字符串处理函数包括: • 字符串连接函数strcat(str1,str2), • 字符串复制函数strcpy(str1,str2), • 字符串比较函数strcmp(str1,str2), • 测试字符串长度函数strlen(str)等等。

  22. 以下程序是用字符数组编程实现字符串的拷贝。参考程序如下:以下程序是用字符数组编程实现字符串的拷贝。参考程序如下: /******************************************** 函数功能:字符串拷贝 函数参数:字符型数组srcStr, 存储源字符串 字符型数组dstStr, 存储目的字符串 函数返回值:无 **********************************************/ void mystrcpy(char dstStr[ ], char srcStr[ ]) { int i=0; while(srcStr[i]!='\0') { dstStr[i]=srcStr[i]; i++; } dstStr[i]='\0'; } • 将上述函数改写成用字符指针变量实现。比较两者的区别。

  23. 4、录入并运行以下程序,查看运行结果: #include <stdio.h> void main() { int i; char as[]="I am happy"; //第5行:初始化字符数组 char *ps="I am happy"; //第6行:初始化字符指针 printf("The as string is:"); for(i=0;i<11;i++) { printf("%c",*(as+i)); //第9行:字符数组用指针法输出 } printf("\n"); printf("The ps string is:"); for(i=0;i<11;i++) { printf("%c",*(ps+i)); //第13行:字符指针用指针法输出 } printf("\n"); } • 若将第5行和第6行修改为:char *as="I am happy"; 程序是否还能运行?为什么? • char ps[]="I am happy"; • 若将第5行修改为:char as[]="I am happy"; 第9行改为:printf("%s",as); 程序运行后会出现什么结果?说明了什么?

  24. 5、录入并运行以下程序,查看运行结果。 #include <stdio.h> char *Strcpy(char *dst,char *scr) { char *p; p=dst; while(*(p++)=*(scr++)); return dst; } void main() { char str1[80],str2[80]; printf("\nPlease enter a string:"); gets(str1); printf("\nThe str2 is %s",Strcpy(str2,str1)); } • 运行后,该程序的结果是什么?这是一个返回指针值的函数,该程序的功能是什么?

  25. 6、观察下面的程序,其中有两处错误,请找出出错的行数和原因,并修改错误。6、观察下面的程序,其中有两处错误,请找出出错的行数和原因,并修改错误。 #include <stdio.h> void main() { char *name; char msq[10]; printf("What's your name?\n"); scanf("%s",&name); msq="Hello"; printf("%s %s \n",msq,name); }

  26. 三、编程题 • 1.主函数定义一个存放各种编程语言的字符指针数组char *language[],数组的长度定义为常量N,要求字符串按字典顺序排序。编写下列两个函数:数组排序函数sort(char *language[]),数组输出函数output(char *language[]),用字符指针变量作参数。字符串为”PASCAL”, “BASIC”, “C/C++”, ”Fortran”, “Turbo C”, “JAVA”。

  27. 2.有一篇文章,共有3行文字,每行有80个字符。要求分别统计出其中英文大写字母、小写字母、数字、空格以及其他字符的个数。

  28. 本节课完!  谢谢! 

More Related