我们知道,一般编写程序时都要画出流程图,按照流程图结构来编程,如果编写一个比较繁琐,容易思维混乱的程序时,我们可以利用有限状态机模型画出一个状态转移图,这样便可以利用画出的逻辑图来编写程序,简洁且不易出错。

那什么是有限状态机是什么意思呢?百度百科上这样解释:

有限状态机,(英语:Finite-state machine, FSM),又称有限状态自动机,简称状态机,是表示有限个状态以及在这些状态之间的转移和动作等行为的数学模型。

常见的计算机就是使用有限状态机作为计算模型的:对于内存的不同状态,CPU通过读取内存值进行计算,更新内存中的状态。CPU还通过消息总线接受外部输入设备(如键盘、鼠标)的指令,计算后更改内存中的状态,计算结果输出到外部显示设备(如显示器),以及持久化存储在硬盘。
电脑游戏设计中也经常使用有限状态机模型。以水果忍者游戏为例,游戏中水果的状态是有限状态,其运行轨迹是由模拟物理运动规律的计算公式运算而成的,一个香蕉抛起来后会按照抛物线运行,其每一帧位置变化都是一个状态的改变,状态改变通过计算公式来决定。当然作为游戏不会仅仅这么简单,如果这么简单就是动画了,游戏还有复杂的人机交互事件,比如用手在屏幕上“切”了水果,水果感知到这个事件后,会按照程序逻辑进入爆炸状态。
简单知道其定义是没有用的,在C编程中我们改如何应用呢?
例题1:去除一个字符串中连续的空格,即 H__el___lo 变成 H_el_lo;
我们拿到这道题时,可能会想到用getchar()依次取字符,当遇到空格时,继续下一个字符是否为空格,如果是则删除,如果不是则继续;那么问题来了,如果空格后面还有空格呢?如果还有很多空格呢?如果还有其他要求呢?这样很容易造成思维混乱,所以这时我们可以用到有限状态机模型,好像这样说很模糊啊,该怎么使用呢?利用这种方式,最后的就是利用好flag,即标识符;这样吧,我们来画一下这个模型:
这样看好像有点抽象,我来解释一下:
状态0  (flag = 1)若当前字符是空格,输出并跳转到状态1(flag = 1),如果是非空格,则打印字符;
状态1  (flag = 1) 若当前字符为非空格,则输出并跳转到状态0,若是空格,则不打印;
下面几个例题我尽量写得清楚;
我们按照这种逻辑来写程序,看看是不是比较方便,代码如下:
[cpp] view plaincopy
  1. #include <stdio.h>
  2. int main(int argc, char *argv[])
  3. {
  4. char flag = 0;
  5. int ch;
  6. while((ch = getchar()) != EOF)
  7. {
  8. switch(flag)
  9. {
  10. case 0:
  11. if(ch == ' ')
  12. flag = 1;
  13. putchar(ch);
  14. break;
  15. case 1:
  16. if(ch == ' ')
  17. continue;
  18. flag = 0;
  19. putchar(ch);
  20. break;
  21. default:
  22. break;
  23. }
  24. }
  25. return 0;
  26. }

程序执行结果如下:

[cpp] view plaincopy
  1. fs@ubuntu:~/qiang/char1$ gcc -o test test.c
  2. fs@ubuntu:~/qiang/char1$ ./test
  3. H  el   lo
  4. H el lo
效果很明显;
上面的例题还算简单吧,好像不用这个模型也可以是吧,那好,我们再来一题
例题2:除连续的空格但字符串中的连续空格不变,比如H_ _el__"wor___ld"___lo;
大家看看,如果直接写程序是不是很烦,一会就乱掉了,那我们还用这个模型来编写,还是先画图:
[cpp] view plaincopy
  1. #include <stdio.h>
  2. int main(int argc, char *argv[])
  3. {
  4. char flag = 0;
  5. int ch;
  6. while((ch = getchar()) != EOF){
  7. switch(flag){
  8. case 0:
  9. if(ch == ' ')
  10. flag = 1;
  11. if(ch == '"')
  12. flag = 2;
  13. putchar(ch);
  14. break;
  15. case 1:
  16. if(ch != ' '){
  17. flag = 0;
  18. if(ch == '"')
  19. flag = 2;
  20. putchar(ch);
  21. }
  22. break;
  23. case 2:
  24. if(ch == '"')
  25. flag = 0;
  26. if(ch == '\"')
  27. ch = '"';
  28. putchar(ch);
  29. break;
  30. default:
  31. printf("error!\n");
  32. break;
  33. }
  34. }
  35. return 0;
  36. }

执行结果如下:
[cpp] view plaincopy
  1. fs@ubuntu:~/qiang/char1$ ./char3
  2. H  el  "wor   ld"   lo
  3. H el "wor   ld" lo

 
来个实际点的问题:
例题3::除单行注释
示例程序:
[cpp] view plaincopy
  1. /*****This is a program!*****/
  2. #include <stdio.h>
  3. int main()
  4. {
  5. printf("Hello world!\n");//Hello world!
  6. }

将这段程序中的单行注释去掉,继续画图:

编写程序如下:
[cpp] view plaincopy
  1. #include <stdio.h>
  2. int main(void)
  3. {
  4. char flag = 0;
  5. char ch;
  6. while((ch = getchar()) != EOF)
  7. {
  8. switch(flag)
  9. {
  10. case 0:
  11. if(ch == '/')
  12. flag = 1;
  13. else
  14. putchar(ch);
  15. break;
  16. case 1:
  17. if(ch == '/'){
  18. flag = 2;
  19. }
  20. else{
  21. putchar('/');
  22. putchar(ch);
  23. }
  24. break;
  25. case 2:
  26. if(ch == '\n')
  27. {
  28. flag = 0;
  29. putchar(ch);
  30. }
  31. break;
  32. default:
  33. break;
  34. }
  35. }
  36. }

执行命令:

[cpp] view plaincopy
  1. fs@ubuntu:~/qiang/char1$ ./quzhushi1 < test.c >result.c

注意命令中用到的重定向,将test.c文件重定向到quzhushi1 中,输出结果重定向到 result.c中

可查看result.c中:
[cpp] view plaincopy
  1. /*****This is a program!*****/
  2. #include <stdio.h>
  3. int main()
  4. {
  5. printf("Hello world!\n");
  6. }

单行注释被删除。

例题4:去除单行注释和多行注释
还是这个测试程序:
[cpp] view plaincopy
  1. /*****This is a program!*****/
  2. #include <stdio.h>
  3. int main()
  4. {
  5. printf("Hello world!\n");//Hello world!
  6. }

好吧,继续画图,图上比较抽象,大家可以自己思考一下

这次比较复杂,要有5个标识符
测试代码如下:
[cpp] view plaincopy
  1. #include <stdio.h>
  2. int main()
  3. {
  4. char ch;
  5. int flag = 0;
  6. while((ch = getchar()) != EOF)
  7. {
  8. switch(flag)
  9. {
  10. case 0:
  11. if(ch == '/')
  12. flag = 1;
  13. else
  14. putchar(ch);
  15. break;
  16. case 1:
  17. if(ch == '/')
  18. flag = 2;
  19. else if(ch == '*')
  20. flag = 3;
  21. else
  22. {
  23. flag = 0;
  24. putchar('/');
  25. putchar(ch);
  26. }
  27. break;
  28. case 2:
  29. if(ch == '\n')
  30. {
  31. putchar(ch);
  32. flag = 0;
  33. }
  34. break;
  35. case 3:
  36. if(ch == '*')
  37. flag = 4;
  38. break;
  39. case 4:
  40. if(ch == '/')
  41. flag = 0;
  42. else
  43. flag = 3;
  44. break;
  45. }
  46. }
  47. }

执行命令:

[cpp] view plaincopy
  1. fs@ubuntu:~/qiang/char1$ ./quzhushi < test.c >result.c

执行结果:

result.c
[cpp] view plaincopy
  1. #include <stdio.h>
  2. int main()
  3. {
  4. printf("Hello world!\n");
  5. }

大家可以比较画的图与所写程序,这种方法可以使我们编写程序时有个很好的思路!

Linux C 编程技巧--利用有限状态机模型编程相关推荐

  1. Matlab编程技巧:打开模型时加载数据字典

    本文研究通过回调函数,在打开模型时加载数据字典到工作空间中. 文章目录 1 问题引入 2 简单例程 2.1 模型配置 2.2 数据字典表格 2.3 创建脚本 3 效果演示 4 总结 1 问题引入 在& ...

  2. Linux Shell常用技巧(十二) Shell编程

    二十三. Bash Shell编程:  1.  读取用户变量:     read命令是用于从终端或者文件中读取输入的内建命令,read命令读取整行输入,每行末尾的换行符不被读入.在read命令后面,如 ...

  3. Linux驱动小技巧 | 利用DRIVER_ATTR实现调用内核函数

    1. 前言 很多朋友在调试驱动的时候,都会遇到这样一个场景:修改一个参数,然后调用某个内核中的函数. 比如将某个gpio的值拉高/拉低,修改某个寄存器的值等等. 如果每一个参数都通过字符设备的ioct ...

  4. python3实用编程技巧_6.python3实用编程技巧进阶(一)

    1.1.如何在列表中根据条件筛选数据# 1.1.如何在列表中根据条件筛选数据 data = [-1, 2, 3, -4, 5] #筛选出data列表中大于等于零的数据 #第一种方法,不推荐 res1 ...

  5. python3实用编程技巧_9.python3实用编程技巧进阶(四)

    4.1.如何读写csv数据 爬取豆瓣top250书籍import requests import json import csv from bs4 import BeautifulSoup books ...

  6. python编程技巧1002python编程技巧_总结Python编程中三条常用的技巧

    在 python 代码中可以看到一些常见的 trick,在这里做一个简单的小结. json 字符串格式化 在开发 web 应用的时候经常会用到 json 字符串,但是一段比较长的 json 字符串是可 ...

  7. 单片机编程技巧_编程技巧

    单片机编程技巧 From the desk of a brilliant weirdo #1: 从辉煌的怪胎#1的桌子上: Thank you for taking the time to check ...

  8. python编程第四版_Python编程 第4版 影印版 上下册

    内容概要 本书是由Mark Lutz编写的<Python编程(影印版第4版)>.<Python编程(影印版第4版)>的内容包括: Python快速入门:搭建一个简单的例子,包括 ...

  9. 很全的linux网络编程技巧

    注:作者王晓,本人认为总结得很好,故记之,绝无侵权之意. 本文转自:https://www.cnblogs.com/jfyl1573/p/6476607.html 看到好文章想留做自己学习,如有侵权, ...

最新文章

  1. sar sensor传感器的作用_传感器攻防战-惯导IMU
  2. php+mysql 大容量数据高效分页效果(弃用limit)
  3. 解决ssm项目表单数据提交到数据库乱码问题
  4. Linux_SELinux使用
  5. 小工匠聊架构- 提升性能的大杀器之缓存技术
  6. Google提出的新型激活函数:Swish
  7. Ie6下asp.net 中treeview自动随鼠标变小的修复
  8. postman安装路径_Newman进行postman脚本自动化
  9. 一年级下册数学计算机应用题,一年级数学下册期中检测试题
  10. C语言各种keyword
  11. c语言怎样编写图形,「分享」C语言如何编写图形界面
  12. spool.exe 出错 无法打印
  13. php 屏蔽微信分享,详解React Js中微信禁止复制链接分享禁止隐藏右上角菜单功能的案例分析...
  14. 代码管理学:通过配置文件限制依赖关系
  15. mybatis-plus代码自动生成器
  16. 老罗Android开发视频教程_基于JavaSE开发(适合Android初学者菜鸟级别的人)
  17. smart原则_写给中学生:用SMART原则制定寒假计划
  18. 微信小程序实现授权登录及退出
  19. 关于python的英文参考文献_参考文献英文版
  20. 使用python3开发趴小说的小工具

热门文章

  1. Oracle 11gR2 RAC恢复OCR和VOTE DISK
  2. linux下mono的安装与卸载
  3. C Primer+Plus(十七)高级数据表示 编程练习(二)
  4. eq相等,smarty 比较操作符!时间戳
  5. VMworld 2010旧金山胜利闭幕
  6. arduino消息服务器,在C(Arduino IDE)中将API链接消息解析为服务器(示例代码)
  7. 什么时候使用静态方法
  8. 实习生解雇_我们解雇了我们的顶尖人才。 我们做出的最佳决定。
  9. 27个机器学习图表翻译_使用机器学习的信息图表信息组织
  10. jsp导出数据时离开页面_您应该在要离开的公司开始使用数据