I am trying to find the source code for the earliest implementation of the stack data structure in C
There is no stack data structure in C. Look through the language specification and you won't find it there. If you were a programmer and you wanted a stack, you had to implement your own. If you go back to the beginnings of C and look at all the code that needed a stack, you'll probably find that there were as many implementations as there were stacks.
There are many ways to implement a stack in C. Perhaps the easiest is as an array and an index
int intStack[STACK_SIZE];
int stackPointer = 0;
void push(int newElement)
{
intStack[stackPointer++] = newElement;
}
int pop()
{
return intStack[--stackPointer];
}
Two points about the above:
- I'm using modern syntax. I can barely remember how to write K&R C, so I'm not even going to try.
- There are no checks for stack overflow or underflow. It would complicate the code and there were probably plenty of stacks written without bounds checks anyway.
The above implementation is very similar to a stack defined in K&R The C Programming Language in chapter 4 which probably counts as a fairly early example of a stack.
I am particularly interested in knowing if the member variables of the stack data structure were made private, or if they were kept public
That would depend on the quality of the programmer. Contrary to popular belief, C does have data hiding. In fact, I would argue that it is better than C++1. However, there's no qualification of structure members by access keywords. Data hiding has to be done at the compilation unit (file) level and is all or nothing. Here's how:
Firstly, you need to put the elements of your stack and the pointer into a struct
in a separate source file.
/* intstack.c */
#include "intstack.h" /* See below for what is in here */
struct IntStack
{
int data[STACK_SIZE];
int pointer;
}
void IntStack_push(struct IntStack *stack, int newElement)
{
stack->data[stack->pointer++] = newElement;
}
int IntStack_pop(struct IntStack *stack)
{
return stack->data[--stack->pointer];
}
struct IntStack *IntStack_new()
{
return calloc(1, sizeof(struct IntStack));
}
void IntStack_delete(struct IntStack *stack)
{
free(stack);
}
Then you need a header file that has prototypes of all the functions and an incomplete declaration of the struct
/* intstack.h */
struct IntStack; /* Incompleter declaration */
void IntStack_push(struct IntStack *stack, int newElement);
int IntStack_pop(struct IntStack *stack);
struct IntStack *IntStack_new();
void IntStack_delete(struct IntStack *stack);
Other people can use your stack by simply including the header file. They have no access to the internal members of the struct (well, not without doing something bad casting pointers to the struct to some other type).
#include "intstack.h"
int main()
{
struct IntStack *stack = IntStack_new();
IntStack_push(stack, 3);
printf("%d\n", IntStack_pop()); /* prints 3 */
IntStack_delete(stack);
return 0;
}
I am also interested in the source codes of other data structures like queue and linked list and so on.
Similar comments to the above are applicable2. Incidentally, a singly linked list is pretty much the same as a dynamically growing stack i.e. one that doesn't overflow until the memory runs out.
1 In C++ you haver to put the private members in a class declaration in a header which means the protections can be defeated simply by #define private public
before the header is included.
2 Some operating systems have implementations of queues e.g. macOS has a number of library functions and macros to implement queues of various types.