1. 什么是有限状态机
2. 有限状态机的应用场景
3.状态机的基本框架
3.1 定义状态
如果要使用状态机进行解决问题,首先要确定这个问题本事有几个状态,然后我们把所用的状态做一个枚举类型的定义,问什么是枚举类型呢? 因为我们定义==状态的目的就是把状态当作索引值==,这可以说是状态机实现的精髓了,因为它就是根据当前的状态来确定下一步的行为。
例如:一个问题有三种状态,则可以使用这样的定义:
enum {
STATE_0 = 0, /* 数据下标从0开始,因此开始设置为0,后边逐渐递增*/ STATE_1, STATE_2, }FSM_STATE;
3.2定义事件
enum {
EVENT_NOT_SPACE=0, /*数据下标索引,从0开始*/ EVENT_SPACE, EVENT_STR, }FSM_EVENTS;
3.3定义状态机的结构体
因为我们已经知道状态机是有状态和事件构成的,因此状态机的结构体可以定义为 “动作”+“下一状态”。
例如:
struct FSM_node{
void (*func)(char *); /*当前状态下,发生某个事件所采取的措施*/ int next_state; /*这个事件发生后,要切换的状态*/ };
struct {
int (*func)(char *); int next_state; }FSM[STATE_NUM][EVENT_NUM]= {
{
/*current state isNotSpace : 状态0*/ {
isNotSpace_func1,STATE_0}, /*NOT_SPACE:状态0时遇到一个非空格,打印 + 下一状态为状态0*/ {
isNotSpace_func2,STATE_1}, /*IS_SPACE*:状态0时遇到一个空格,打印 + 下一状态为状态1 */ }, {
/*current state isSpace : 状态1*/ {
isSpace_func1, STATE_0}, /*NOT_SPACE:状态1时遇到一个非空格,打印 + 下一状态为状态0*/ {
isSpace_func2, STATE_1}, /*IS_SPACE:状态1时遇到一个空格,不打印 + 下一状态为状态1*/ }, };
3.4 画状态变迁图
4实例
4.1实例一
问题:除去一个字符串中连续的空格,只保留一个。
状态变迁图:


代码实现
#include
typedef enum{
STATE_0 = 0, STATE_1, }state; typedef enum{
NOT_SPACE= 0, IS_SPACE, }events; #define STATE_NUM 2 #define DEVENT_NUM 2 int isNotSpace_func1(char *str) {
putchar(*str); } int isNotSpace_func2(char *str) {
putchar(*str); } int isSpace_func1(char *str) {
putchar(*str); } int isSpace_func2(char *str) {
; /*do nothing*/ } struct {
int (*func)(char *); int next_state; }FSM[STATE_NUM][DEVENT_NUM]= {
{
/*current state isNotSpace*/ {
isNotSpace_func1,STATE_0}, /*NOT_SPACE*/ {
isNotSpace_func2,STATE_1}, /*IS_SPACE*/ }, {
/*current state isSpace : 状态1*/ {
isSpace_func1, STATE_0}, /*NOT_SPACE*/ {
isSpace_func2, STATE_1}, /*IS_SPACE*/ }, }; /*根据当前状态和当前事件做索引,找到对应的处理情况;然后再获取下一状态*/ void demo1() {
char str[] = "h e l l o, w o r l d;"; char *p = str; int state_now = STATE_0; int _event, ret; while(*p){
if(*p==' ') _event = IS_SPACE; else _event = NOT_SPACE; /* FSM[state_now][_event]: 节点对象*/ /* (FSM[state_now][_event]).func : 该对象函数指针*/ /* *((FSM[state_now][_event]).func) : 获取到函数指针指向的函数*/ ret = (*((FSM[state_now][_event]).func))(p); state_now = (FSM[state_now][_event]).next_state; p++; } }
结果:
root# ./a.out root# h e l l o, w o r l d;
4.2实例二
问题:除去一个字符串中连续的空格,只保留一个,但保留双引号(“ ”)内的所有字符。
状态变迁图:

代码实现
#include
enum {
STATE_0 = 0, STATE_1, STATE_2, }FSM_STATE; enum {
EVENT_NOT_SPACE=0, EVENT_SPACE, EVENT_STR, }FSM_EVENTS; #define STATE_NUM 3 #define EVENT_NUM 3 void func1(char *str) {
putchar(*str); } void func2(char *str) {
putchar(*str); } void func3(char *str) {
putchar(*str); } void func4(char *str) {
putchar(*str); } void func5(char *str) {
; } void func6(char *str) {
putchar(*str); } void func7(char *str) {
putchar(*str); } void func8(char *str) {
putchar(*str); } void func9(char *str) {
putchar(*str); } struct {
void (*func)(char *); int next_state; }FSM_test2[STATE_NUM][EVENT_NUM]= {
{
//state_0 not space {
func1, STATE_0}, {
func2, STATE_1}, {
func3, STATE_2}, }, {
//state_1 space {
func4, STATE_0}, {
func5, STATE_1}, {
func6, STATE_2}, }, {
//state_2 "" {
func7, STATE_2}, /* when first " is reached, the state is always STATE_2, only when the next " reached, next state is STATE_0*/ {
func8, STATE_2}, {
func9, STATE_0}, }, }; void demo2() {
char str[] = "h e l l o ,\"today is friday !!!\" w o r l d ."; char *p = str; int ret; int state = STATE_0; int event; while(*p){
if(*p==' ') event = EVENT_SPACE; else if(*p=='"') event = EVENT_STR; else event = EVENT_NOT_SPACE; //printf("\n-----state=%d-----event=%d------\n",state, event); (*(FSM_test2[state][event].func))(p); state = FSM_test2[state][event].next_state; p++; } putchar(10); }
结果:
root# ./a.out root# h e l l o ,"today is friday !!!" w o r l d .
定义了很多同样的实现函数,只是为了说明每一种(状态,事件)都有各自的处理情景,这个栗子只是巧合
5结束
状态机的C语言基本实现框架就是这样,后续如果有经典的状态机实现,做更新处理。
发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/206387.html原文链接:https://javaforall.net
