Yesterday I got a sudden urge to go from writing Python to something, well, more UNIX core-ish. I read some examples on here and decided I might as well put some of that stuff to use to test something else I'm working on: computability theory. Ergo: I wanted to write a basic, one tape, Turing machine simulator.
I'd really like some review on the code. One thing I'm particularly curious about is whether I'm doing appropriate error checking and handling. e.g. are there specific cases where assert is more appropriate or where I should do more error checking?
On error checking and use of assert, I think you have done a good job ofchecking. I'm not a big user of asserts (so maybe my thoughts on them are notof much use to you). I'm always uneasy using an assert - they are funnythings. They say, in effect, that the tested condition is so important that itis worth exiting if it occurs during testing, but that if it occurs duringnormal use (NDEBUG) it can be ignored. That is illogical unless you can besure that all possible assert failures can be detected during testing. To methat implies that asserts should be used only to test for errors that areintrinsic to the program and have no dependence upon the data or the runtime.For example checking whether malloc failed would use an if conditionwhereas checking for something that can only happen if an algorithm is wronglycoded is a fair use of assert. In your case, I might be tempted to useassert where you check array entries are not NULL:
Identifiers with two underscores are reserved for the implementation (so don't use them).Also MACROS (things defined by #define) are traditionally all uppercase (because they do not obey scope rules (because they are not part of the C language but part of the pre-processor system) we make them all uppercase to make sure that we don't accidentally clash with other identifiers).
The system header files aready define FALSE/TRUE. Also in this situation you define TRUE as 1. This is not correct. The only thing you can say about TRUE is (!FALSE). Which is not necessarily the same as 1.
Nothing wrong with this.But if you lay out your type with the chars first then you may not get the best packing arrangement. Always order them from largest to smallest (if you care about layout (usually it is not a big thing but if you have large space requirements and can become an issue)).
It's best to include your own headers first, in order to avoid any possible dependency issues with the system libraries. In other words, you shouldn't force your headers to be exposed to other libraries, especially if that is not intended to happen.