Este ejemplo es de los que quedan mejor con programación orientada a objetos (POO), pero igualmente lo puedes hacer con un tipo abstracto de datos (TAD), o... como lo has hecho, que es una chapuza pero funciona.
El caso es que tienes un tipo de datos, que es un autómata, que a su vez tiene varios tipos o campos, los estados, la tabla de transiciones, etc.
A este autómata le pasas una cadena y ves si la acepta, en tu caso, sin POO sería una función para manejar este TAD, le pasas una variable del TAD, la cadena y te devuelve un booleano (el tipo de datos en C tendrá que ser un int, char o lo que quieras, pero semánticamente funciona como booleano).
Para ver si acepta la cadena lo que tienes que hacer (si no tienes iniciado el autómata por defecto) es iniciar el autómata en el estado inicial (son dos campos, estado actual y estado inicial) se hace con la función iniciar aplicada a ése tipo de datos, que te devuelve el mismo autómata en el estado inicial.
Luego le vas pasando caracter por caracter, lo mismo, otra función, le pasas un caracter y el autómata, internamente mira la tabla de transiciones y el estado actual, y lo actualiza con la transicioń correspondiente.
Y cuando se acaba la cadena lo que haces es mirar si el estado actual está en la lista de estados finales, también otra función de manejo del TAD. Y el retorno de esa función es el retorno de la función para comprobar si acepta una cadena.
Se hace un poco duro porque manejar TADs es más pesado que manejar objetos, al estar programando, pero tampoco tiene mucho.
Más o menos es como lo has hecho, pero con un TAD es programación estructurada y como lo tienes es un caos
tienes que entender que en programación es más habitual hacer middleware, librerías, etc. que programas completos, y el código que has hecho es poco reutilizable. Imagina el lío que tendría que montar alguien si quisiera por ejemplo hacer una interfaz gráfica para manejar autómatas.