[关闭]
@yy0518 2016-04-07T12:55:02.000000Z 字数 2943 阅读 1314

C-19 switch、字符输入输出

C语言学习笔记


1.switch语句

switch语句是多重选择语句,用法诸如:

  1. switchnumber
  2. {
  3. case 1statement1
  4. break
  5. case 2statement2
  6. break
  7. ……
  8. defaultstament;
  9. }

switch后的圆括号中的表达式被求值,值的类型应为整数值(包括char类型),case后的值应为整型常量(包含char型)或者整数常量表达式(只包含整数常量的表达式),判断与哪个分支的值相同,便开始从哪条语句开始执行,如果语句后没有break,则一直往下执行剩下的语句。然后如果语句后有break,则执行到break之后就退出switch语句,执行switch之后的语句。所以在写程序的时候一定要根据具体需求,选择是否加break。statement可选。

特别提醒:break语句可用于循环和switch中,但continue只能用于循环。不过当switch位于一个循环中时,在switch中使用continue对switch并没有什么用,但能对循环产生效果,也就是跳过本次循环的剩余部分,直接进入下一次的循环。


2.goto语句

貌似以前只在汇编里见过这样的指令。而且在C语言中不是很常用,而且说是最好不用。不过,goto相比break和continue的优点在于能够跳出多重嵌套循环,如goto help;在出现故障的时候挺好用的。


3.字符输入输出

被“您可能还想知道是否存在更好的方法来终止输入”给吸引了,所以还有什么更好的方法呢?

(1)缓冲区(buffer)

首先,对于输入来说,有两种输入方式:有缓冲输入非缓冲(直接)输入。两者的区别在于,有缓冲输时,键入的字符首先先被收集并存储在缓冲区中,然后等待缓冲区内容对程序可用(比如按下回车键),缓冲区的内容成块地传输给程序。而非缓冲输入则是将键入的字符立即传递给程序,不经过缓冲区。
相比之下,缓冲区存在的好处在于:将键入的字符成块地传输比单个地一个个传输所耗费的时间少;有缓冲输入时,在按下回车之前,所键入的内容还可以修改。
缓冲也分为两种:完全缓冲(fully buffered)和行缓冲(line-buffered)。
完全缓冲:缓冲区满了传输。(文件输入)缓冲区的大小取决于系统,常见的一般是512字节和4096字节。
行缓冲:遇到换行字符传输。(键盘输入)

(2)流

C对待输入和输出设备与其对待存储设备上普通文件相同。C程序处理这些输入输出以及文件读写,实际上都是都是对流进行操作。
流是一个理想化的数据流,实际的输入输出映射到这个数据流上。采用流的好处在于,将具有不同属性的多种输入输出统一用流来表示,能够减小系统差异所带来的麻烦,C用户只需要通过使用标准的IO包,对流进行处理,从而实现多种类型的输入输出操作。
如键盘的输入由一个被称为stdin的流表示,屏幕或其它显示设备上的输出由一个被称为stdout流表示。而标准IO中的scanf()、printf()等就能实现对这两个流的操作。

(3)文件的结尾及如何停止输入

在对文件进行处理时,计算机系统需要判断每个文件的起始和结束位置。判断文件结尾一般有两种方法:一种是根据文件的大小来判断文件结尾,如果已经读取了文件大小的内容,则表示到达了文件尾。一种是在文件中放置一个特殊的字符来标志结尾(如Ctrl+Z).

这两种方法,对于C语言来说其实都是,让getchar()函数和scanf()函数在到达文件结尾时,返回值为EOF。这个EOF的返回值通常定义为-1(因为它不与任何一个字符对应),这个实在stdio.h的头文件中已经定义过了,包含头文件后我们可以直接使用,也不用管它具体的值是多少。
对于char()函数,下面的写法可以用Ctrl+Z正常结束输入.

  1. while ((ch = getchar()!=EOF))
  2. putchar(ch);

对于scanf()函数,下面的写法却不能用Ctrl+Z结束输入.

  1. while (scanf_s("%c",&ch)!=EOF)
  2. putchar(ch);

但下面的这个却又可以用Ctrl+Z结束输入,不明白这其中的差别在哪里.

  1. while (scanf_s("%c",&ch))
  2. putchar(ch);

作业

为了简化上次的程序,首先介绍两个大小写转换的函数
(1)tolower()
函数功能:若字符为大写字母,则返回对应的小写字母;如果字符为小写字母,则返回原值。
函数原型: int tolower(int c);
(2)toupper()
函数功能:与上类似,若是小写字母,则返回对应的大写字母;若是大写字母,则返回原值。
函数原型:extern int toupper(int c);

这两个函数在使用时,都必须包含ctype.h的头文件。


采用二维数组的方式的程序如下:

  1. #include "stdio.h"
  2. #include"ctype.h"
  3. #include"string.h"
  4. int main()
  5. {
  6. char ch[100][100], c_f;
  7. int i = 0, j = 1, k;
  8. int d_f1, d_f2, d_f;
  9. while ((ch[i][j] = getchar()) != '#')
  10. {
  11. if (ch[i][j] == '.') { ch[i][0] = j + 1; i++; j = 1; }
  12. else j++;
  13. }
  14. /*for (i -= 1;i >= 0;i--)
  15. for (j = 1;j < ch[i][0];j++)
  16. putchar(ch[i][j]);
  17. for (k = 0;k < 100;k++)
  18. {
  19. if (ch[i][j] = getchar()!=EOF)
  20. {
  21. if (ch[i][j] == '.') { i++; j = 0; }
  22. else j++;
  23. }
  24. else break;
  25. }
  26. */
  27. for (i -= 1;i >= 0;i--)
  28. {
  29. ch[i][1] = tolower(ch[i][1]);
  30. d_f2 = ch[i][0] - 1;
  31. for (j = ch[i][0]-1;j > 0;j--)
  32. {
  33. if ((ch[i][j] == ' ') || (ch[i][j] == ','))
  34. {
  35. c_f = ch[i][j];
  36. d_f1 = j;
  37. d_f = d_f1;
  38. for (d_f1 += 1;d_f1 < d_f2;d_f1++)
  39. putchar(ch[i][d_f1]);
  40. putchar(c_f);
  41. d_f2 = d_f;
  42. }
  43. else if (j == 1)
  44. {
  45. d_f1 = j;
  46. for (;d_f1 < d_f2;d_f1++)
  47. printf("%c", ch[i][d_f1]);
  48. }
  49. else continue;
  50. }
  51. printf(".");
  52. }
  53. return 0;
  54. }

程序分析
将所输入的段落存储在二维数组中,每一行存一个句子。然后每一行的第一位即ch[i][0]存这个句子的长度。前面说过可以用strlen的函数计算字符数组的长度,但是因为对数组初始化的方式不一样,strlen(ch[i])出来的结果并不是存入的字符的个数,所以不能采用这种方式。而对于以单词为单位的倒序输出的方法,本质上跟上一次差不多。
缺陷:对于有换行符的字符段,不能很好地倒序输出。但是发现上一个程序也是这样的,只是之前木有发现。
问题
1 被注释掉的那部分的输入方法不知道为什么不可行,为什么在输入结束之后就没有后续的输出了呢??
2 为什么有换行符输入的时候,倒序输出时却没有出现换行符?

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注