Skip to content

Instantly share code, notes, and snippets.

@ChunMinChang
Last active June 8, 2023 14:38
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ChunMinChang/31f11789bb859356daf05107e8fc859e to your computer and use it in GitHub Desktop.
Save ChunMinChang/31f11789bb859356daf05107e8fc859e to your computer and use it in GitHub Desktop.
Simulate a C++ class in C for linked-list implementation

Class in C for linked-list implementation

An example to simulate a C++ class in C.

This is a comparison to ChunMinChang/8e04130e778d77e0b30b8954cc5f2473, which implement a linked-list in C++.

TODO

  • Implement delete function to remove a node from the list
  • Implement move function to move cursor to a specific node
  • Implement search function to return one specific node

Comparison with C++ version

Please read this

References

#include "list.h"
#include <assert.h> // for assert
// #include <stddef.h> // for NULL, size_t, they are already included in list.h
#include <stdlib.h> // for calloc, free
#include <string.h> // for memcpy
// Using "static" prevents these functions from being exposed outside.
static void
destroy(struct List* self)
{
for (struct Node* cur = self->head ; cur != NULL ;) {
struct Node* next = cur->next;
free(cur->data);
free(cur);
cur = next;
}
self->head = self->cursor = NULL;
}
static void
append(struct List* self, void* data, size_t size) {
struct Node* n = (struct Node*)calloc(1, sizeof(struct Node));
assert(n);
n->next = NULL;
n->data = calloc(1, size);
assert(n->data);
memcpy(n->data, data, size);
if (!self->head) { // The list is empty.
assert(!self->cursor); // cursor = head = NULL now.
self->head = n;
} else {
assert(self->cursor);
self->cursor->next = n;
}
self->cursor = n;
}
static void
prepend(struct List* self, void* data, size_t size) {
struct Node* n = (struct Node*)calloc(1, sizeof(struct Node));
assert(n);
n->next = self->head;
n->data = calloc(1, size);
assert(n->data);
memcpy(n->data, data, size);
self->head = n;
if(!self->cursor) { // The list is empty before inserting value.
self->cursor = n;
}
}
static void
traverse(struct List* self, Callback func)
{
for (struct Node* cur = self->head ; cur != NULL ; cur = cur->next) {
func(cur);
}
}
static struct List
new()
{
return (struct List) {
.head = NULL,
.cursor = NULL,
.destroy = (void*) &destroy,
.append = (void*) &append,
.prepend = (void*) &prepend,
.traverse = (void*) &traverse
};
}
const struct ListClass /*ListProxy*/ List = {
.new = &new,
};
#ifndef LIST_H
#define LIST_H
#include <stddef.h> // for size_t
struct Node {
void* data; // Any data type can be stored in this node
struct Node* next;
};
typedef void (*Callback)(struct Node* node);
struct List {
struct Node* head;
struct Node* cursor;
void (* const destroy)(struct List* self);
void (* const append)(struct List* self, void* data, size_t size);
void (* const prepend)(struct List* self, void* data, size_t size);
void (* const traverse)(struct List* self, Callback func);
};
extern const struct ListClass {
struct List (*new)();
} /*ListProxy*/ List;
#endif // LIST_H
CC=gcc
CFLAGS=-Wall
SOURCES=list.c
TEST=test.c
EXECUTABLE=$(TEST:.c=)
all:
$(CC) $(CFLAGS) $(TEST) $(SOURCES) -o $(EXECUTABLE)
clean:
rm $(EXECUTABLE)
#include "list.h"
#include <stdbool.h> // for bool
#include <stdio.h> // for printf
#define VA_ARGS(...) , ##__VA_ARGS__
#define CALL(obj, method, ...) ((obj).method(&(obj) VA_ARGS(__VA_ARGS__)))
void print(struct Node* node, bool is_float)
{
if (!node) {
return;
}
is_float ? printf("%f", *(float*)node->data) :
printf("%d", *(int*)node->data);
printf("%s", (node->next) ? "->" : "\n");
}
void print_int(struct Node* node)
{
print(node, false);
}
void print_float(struct Node* node)
{
print(node, true);
}
int main()
{
int data_int[6] = { 11, 22, 33, 44, 55, 66 };
float data_float[6] = { 1.1f, 2.2f, 3.3f, 4.4f, 5.5f, 6.6f };
struct List l = /*ListProxy*/List.new();
l.prepend(&l, &data_int[0], sizeof(data_int[0]));
l.append(&l, &data_int[1], sizeof(data_int[1]));
l.append(&l, &data_int[2], sizeof(data_int[2]));
l.prepend(&l, &data_int[3], sizeof(data_int[3]));
l.append(&l, &data_int[4], sizeof(data_int[4]));
l.prepend(&l, &data_int[5], sizeof(data_int[5]));
l.traverse(&l, print_int);
l.destroy(&l);
CALL(l, prepend, &data_float[0], sizeof(data_float[0]));
CALL(l, append, &data_float[1], sizeof(data_float[1]));
CALL(l, append, &data_float[2], sizeof(data_float[2]));
CALL(l, prepend, &data_float[3], sizeof(data_float[3]));
CALL(l, append, &data_float[4], sizeof(data_float[4]));
CALL(l, prepend, &data_float[5], sizeof(data_float[5]));
CALL(l, traverse, print_float);
CALL(l, destroy);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment