C generic programming
I don't do a lot of C hacking, but I think the way to go with this is void*
.
So, just rewrite your stack of push/pop void*
instead of some_struct*
. It becomes your problem to keep the types correct, but that's just a price you pay for using such a low-level* programming language.
*Not to imply that this is a bad thing.
Finding commonalities and creating abstractions is one of the most valuable skills for a programmer. As you're still learning, I'd suggest you do the following things:
(1) Implement the stack for that other struct. Yes, it's double work, but at your stage every working program counts. Builds up experience.
(2) Compare the programs. What are the parts they have in common? What are the parts that differ? Your goal is to separate the parts that are common from the parts that are different. What are the means that these two groups use to communicate? The parts that they have in common go into one part of your system (stack.h/stack.c), the parts that are different go into their own files (account.h/c, person.h/c, etc.). And the part where you combine them should do an include of stack.h and the parameterizing entity.
(3) Try to find all possible ways you know that the language offers that you can use to implement the abstract struct functionality. At first it always seems as if there is only one way, but for every non-trivial problem there are alsway several approaches. In the stack case, using standard C, for example, zou can use void pointers, you can use preprocessor macros, you should look into token pasting, you can use function pointers plus struct pointers, etc.
(4) Implement as many of them as possible. Again, this is for the learning experience. C has so many traps, and the earlier you run into them, the better.
(5) After you have enumerated and implemented all these different approaches, you should evaluate them: Which one was easiest to use? Which one was easiest to implement? Which one is fastest? Which one is easiest to debug?
For production code, I generally prefer C++. Even if you don't plan to go all out with OO, generics and metaprogramming, you can use C++ as a better C (in this case, just to get std::stack for free).
If you have to use C, try to keep it simple and make pragmatic choices based on your particular circumstance. For instance, if you know for sure that your stack is bounded to some small limit and the data you're holding is simple, then your stack code could be as simple as stack[tos++] = x;
and return stack[--tos]
without needing a reusable library. The answers suggesting a library based on void*
are also appropriate under different circumstances. C++'s std::stack pretty much solves this problem once and for all; C doesn't quite give you that luxury.
I believe that abstraction is mostly in the eye of the programmer. A great programmer can see the pattern in simple statements, even in a low level language as C. Languages and their syntax can surely help but how statements and expressions are finally written are somewhat what differentiate good programmers from bad ones. That said, how do this help you? Well, my point is to become familiar with the constructs in C so you know them when you see them, and the void*
as Kevin Montrose mention is a common one. Strategies I think are good is to think about stdlib
, how has things been solved there? and reflect in great code when you see some.
Ie a common pattern in stdlib
is to have zero (0) to represent OK. Or reflect on how well a filedescriptor work with all the read
, write
etc functions regardless its origin (socket, file, pipe etc). This SO question (link) has some good links to great code to read.
(source: skitch.com)
Picture from Thinking Forth, a great old programming book regardless of language.