How do you create a function pointer with struct table such as
static struct {
int pid;
int queue[MAXPROCS];
} semtab[MAXSEMS];
I think I understand how to make OO equivalent in C using function pointer with this post, but how can I do with when my struct is an array. I'm still a little iffy with the syntax.
Would it be something like
static struct {
int pid;
int queue[MAXPROCS];
void (*fncPtr_enqueue)(int) = enqueue;
// or is it void(*enqueue)(semtable[]*) ?
int (*fcnPtr_dequeue)() = dequeue;
} semtab[MAXSEMS];
void enqueue(int i) { /* code */ }
int dequeue() { /* code */ }
// then to use it, it would be like this?
void foo() {
semtab[5].enqueue(6);
}
Use
static struct {
int pid;
int queue[MAXPROCS];
void (*fncPtr_enqueue)(int); // This defines a member fncPtr_enqueue
int (*fncPtr_dequeue)(); // Note that you had fcnPtr_ in your post.
// I have fncPtr_ here.
} semtab[MAXSEMS];
void enqueue(int i) { /* code */ }
int dequeue() { /* code */ }
Each object in semtab that needs to have valid function pointers needs to be updated.
semtab[0].fncPtr_enqueue = enqueue;
semtab[0].fncPtr_dequeue = dequeue;
You could use:
static struct
{
int pid;
int queue[MAXPROCS];
void (*enqueue)(int);
int (*dequeue)(void);
} semtab[MAXSEMS];
void enqueue(int i) { /* code */ }
int dequeue(void) { /* code */ }
void foo(void)
{
semtab[5].enqueue(6);
}
Changes include:
Systematic names for structure member pointers (instead of mixed fncPtr and fcnPtr prefixes).
No attempt to initialize in the structure definition.
Add void to function prototypes to indicate no arguments. In C (and in contrast to C++), an empty pair of brackets (parentheses) means "a function taking an undefined number of arguments, but not one which has a variable argument list with ... ellipsis".
Because of (1), the original invocation is OK. (With the original code, you'd have needed semtab[5].fncPtr_enqueue(6); — or even (*semtab[5].fncPtr_enqueue)(6);)
You would still have to ensure that the function pointers in the table are all initialized.
With GCC and C99 or C11 compilation, you could initialize the array using:
static struct
{
int pid;
int queue[MAXPROCS];
void (*enqueue)(int);
int (*dequeue)(void);
} semtab[MAXSEMS] =
{
[0 ... MAXSEMS-1] = { .enqueue = enqueue, .dequeue = dequeue }
};
The [0 ... MAXSEMS-1] part is a GCC extension. Observe that a space is required after the 0 to avoid problems with the 'maximal munch' rule.
As JS1 mentioned in the comments, it's actually pretty pointless to do this with the example you have, as you're not achieving anything with the indirection if you're not going to vary the value of those pointers.
That being said, here's an example using a stack (because the logic is easier than a queue, and this is a simple example). Note that you must pass a pointer to the stack to each of your member functions, because while C++ member functions have an implicit this argument, C functions never do. You also need to give your struct a name, otherwise you won't be able to refer to it in the abstract, which you need to do.
This program uses the same struct to implement two variations of a stack, one normal one, and one which unnecessarily shouts at you when you push or pop:
#include <stdio.h>
#include <stdlib.h>
enum {
STACKSIZE = 1024
};
struct stack {
int stack[STACKSIZE];
size_t top;
void (*push)(struct stack *, int);
int (*pop)(struct stack *);
void (*destroy)(struct stack *);
};
void stack_push(struct stack * this, int i)
{
if ( this->top == STACKSIZE ) {
fprintf(stderr, "Queue full!\n");
exit(EXIT_FAILURE);
}
this->stack[this->top++] = i;
}
void stack_push_verbose(struct stack * this, int i)
{
stack_push(this, i);
printf("** PUSHING %d ONTO STACK! **\n", i);
}
int stack_pop(struct stack * this)
{
if ( this->top == 0 ) {
fprintf(stderr, "Stack empty!\n");
exit(EXIT_FAILURE);
}
return this->stack[--this->top];
}
int stack_pop_verbose(struct stack * this)
{
const int n = stack_pop(this);
printf("** POPPING %d FROM STACK! **\n", n);
return n;
}
void stack_destroy(struct stack * this)
{
free(this);
}
struct stack * stack_create(void)
{
struct stack * new_stack = malloc(sizeof * new_stack);
if ( !new_stack ) {
perror("Couldn't allocate memory");
exit(EXIT_FAILURE);
}
new_stack->top = 0;
new_stack->push = stack_push;
new_stack->pop = stack_pop;
new_stack->destroy = stack_destroy;
return new_stack;
}
struct stack * stack_verbose_create(void)
{
struct stack * new_stack = stack_create();
new_stack->push = stack_push_verbose;
new_stack->pop = stack_pop_verbose;
return new_stack;
}
int main(void)
{
struct stack * stack1 = stack_create();
struct stack * stack2 = stack_verbose_create();
stack1->push(stack1, 4);
stack1->push(stack1, 3);
stack1->push(stack1, 2);
printf("Popped from stack1: %d\n", stack1->pop(stack1));
stack2->push(stack2, 5);
stack2->push(stack2, 6);
printf("Popped from stack2: %d\n", stack2->pop(stack2));
printf("Popped from stack1: %d\n", stack1->pop(stack1));
printf("Popped from stack1: %d\n", stack1->pop(stack1));
printf("Popped from stack2: %d\n", stack2->pop(stack2));
stack1->destroy(stack1);
stack2->destroy(stack2);
return 0;
}
with output:
paul#horus:~/src/sandbox$ ./stack
Popped from stack1: 2
** PUSHING 5 ONTO STACK! **
** PUSHING 6 ONTO STACK! **
** POPPING 6 FROM STACK! **
Popped from stack2: 6
Popped from stack1: 3
Popped from stack1: 4
** POPPING 5 FROM STACK! **
Popped from stack2: 5
paul#horus:~/src/sandbox$
Note that we use the exact same struct stack for both types of stack - the differences between them are implemented by having the function pointers point to different functions in each case. The only visible difference to the user is that one is created with stack_create(), and the other is created with stack_create_verbose(). In all other respects, they're used identically, so you can see the polymorphism at work.
Related
I'm trying to do a "class model" in C in which I define a struct that represents the class and inside it I define function pointers to represent methods, like this:
//ClassName.h
typedef struct struct_ClassName ClassName;
struct ClassName
{
char a;
char b;
char c;
void (*method1)(ClassName*, char);
void (*method2)(ClassName*, char);
...
void (*methodN)(ClassName*, char);
};
void initClassName(ClassName*);
//ClassName.c
#include "ClassName.h"
static void method1(ClassName *this_c, char c);
static void method2(ClassName *this_c, char c);
...
static void methodN(ClassName *this_c, char c);
void initClassName(ClassName *this_c)
{
this_c->method1 = &method1;
this_c->method2 = &method2;
...
this_c->methodN = &methodN;
}
void method1(ClassName *this_c, char c)
{
//do something
}
void method2(ClassName *this_c, char c)
{
//do something
}
...
void methodN(ClassName *this_c, char c)
{
//do something
}
Everything works fine but, somewhere in the code, I define an array:
...
ClassName objects[200];
for(i = 0; i < 200; i++)
{
initClassName(&objects[i]);
}
...
Because of the function pointers, the memory usage associated to this array is quite high (I have several "methods" in this "class").
Considering that this is a code that will run in an embedded system, is there a better way to do it?
Defining functions outside the structure could be a possibility but in my opinion it does not respect what I'm trying to emulate.
I have to use only C, not C++.
What you have created is a very dynamic system where each object instance can have its own set of method implementations. That's why it uses so much memory.
Another approach is an implementation closer to early C++ (before multiple inheritance) where all instance of the same class share the same vtable. The vtable contains the function pointers.
typedef struct struct_ClassName ClassName;
typedef struct struct_ClassName_vtable ClassName_vtable;
struct ClassName_vtable
{
void (*method1)(ClassName*, char);
void (*method2)(ClassName*, char);
...
void (*methodN)(ClassName*, char);
}
struct ClassName
{
ClassName_vtable* _vtable;
char a;
char b;
char c;
};
void initClassName(ClassName*);
static void method1(ClassName *this_c, char c);
static void method2(ClassName *this_c, char c);
...
static void methodN(ClassName *this_c, char c);
ClassName_vtable _ClassName_vtable = {
method1,
method2,
...,
methodN
};
void initClassName(ClassName *this_c)
{
this_c->_vtable = _ClassName_vtable;
}
That way, the OO overhead per instance is only the size of a pointer. It's also easier to create subclasses.
A method call looks like this:
ClassName* obj = ...;
obj->vtable->method2(obj, 'a');
ClassName objects[200];
for(i = 0; i < 200; i++)
initClassName(&objects[i]);
I will show you a stripped-off version of something I use here
for similar effect. It is hard to say when a certain size is huge in terms of pointers or whatever. Each environment has their truth and this can be useless or useful...
Anyway, the ideia is encapsulation. And in C we have no this pointer. C is not C++ or java or javascript. Each class instance must have a table of function pointers for the methods. We need to build these tables. This is how virtual classes are implemented in others languages anyway. And if each class element can allocate memory code is needed to allocate and free memory.
TL;DR
Below is a C example of a program that builds and uses an array of classes. In this case an array of stacks. It shows a mechanism of building stacks of mixed things. Each array item has all that is needed to manage his own stack instance, be it of a trivial type or a complex structure. It can be easily changed to implement other tyoes of classes in C.
Please do not bother warning me that I cast the return of malloc(). I , as many others, do not like implicit things. And I know that C-FAQ is a never-updated thing from the end of the '90s so no need to reference this either.
An example: a static STACK container
typedef struct
{
int data[SIZE];
int limit; // capacity
int size; // actual
} Stack;
This is it: a simple stack of int values. Let us say we want to declare a vector of stacks of different things, but in C. And use methods on them. If we use trivial types --- in C++ we say the struct is trivialy constructible --- things can get easier, but if we are about to use structs we need to know about how to manipulate stack elements, since they can allocate memory.
We are writing a container so the methods of the class must work for any underlying data. And we have no iterators like C++ STL. Here we are implementing the POP TOP and PUSH methods for stacks, and a toString() method like in java to print values on the screen.
For each possible content in the container we need to have a constructor, a
destructor, a copy constructor and a display method. In this example we have just 2 types of stacks: a stack of int and a stack of struct Sample:
typedef struct
{
size_t _id;
char name[30];
char phone[20];
} Sample;
We can add others just by writing the required 4 functions.
main.c example
int main(void)
{
srand(220804); // for the factory functions
Stack* class_array[2] = {
create(4, create_i, copy_i, destroy_i, show_i),
create(3, create_st, copy_st, destroy_st, show_st)};
printf("\n\n=====> Testing with STACK of int\n\n");
class_test(class_array[0], factory_i);
printf(
"\n\n=====> Testing with STACK of struct "
"Sample\n\n");
class_test(class_array[1], factory_st);
class_array[0]->destroy(class_array[0]);
class_array[1]->destroy(class_array[1]);
return 0;
}
Each instance of Stack has pointers to the stack methods and to the functions that manipulate the stack data, so we can have a single class_test() function that does the following:
builds a stack of the required size, 4 or 3 in the example
fills the stack with data generated by factory functions (in production the logic builds the data)
shows the stack contents
removes all stack elements, one by one
At the end the destructor is called for eack stack.
The class.h file
typedef void* (PVFV)(void*);
typedef int (PIFV)(void*);
typedef struct
{
size_t size_;
size_t lim_;
void** data_;
PVFV* copy;
PVFV* destroy;
int (*show)(void*,const char*); // for testing
// constructor and destructor for container elements
PVFV* create_1;
PVFV* copy_1;
PVFV* destroy_1;
PIFV* show_1;
// member functions
PIFV* POP;
int (*PUSH)(void*,void*);
PVFV* TOP;
PIFV* empty;
size_t (*size)(void*);
} Stack;
Stack* create(
size_t,
void* (*)(void*),
void* (*)(void*),
void* (*)(void*),
int (*)(void*));
int class_test(Stack*, void* (*)());
the example output
=====> Testing with STACK of int
Stack is empty
POP() on empty stack returned -2
TOP() on empty stack returned NULL
Calls PUSH until error
Value inserted: 42
Value inserted: 41
Value inserted: 40
Value inserted: 39
Stack now has 4 elements
Stack has 4 of 4 elements:
42
41
40
39
Calls POP() until error
Stack size: 3
Stack size: 2
Stack size: 1
Stack size: 0
=====> Testing with STACK of struct Sample
Stack is empty
POP() on empty stack returned -2
TOP() on empty stack returned NULL
Calls PUSH until error
Value inserted: 0195 Sample id#0195 +76(203)6840-195
Value inserted: 0943 Sample id#0943 +35(686)9368-943
Value inserted: 0152 Sample id#0152 +16(051)8816-152
Stack now has 3 elements
Stack has 3 of 3 elements:
0096 Sample id#0096 +24(477)0418-096
0037 Sample id#0037 +27(214)3509-037
0836 Sample id#0836 +68(857)4634-836
Calls POP() until error
Stack size: 2
Stack size: 1
Stack size: 0
the logic
For each tye of element we need to write the 4 functions: they can alocate memory and be very complex or they can be trivial, but the class methods need to handle any case.
code for struct Sample in stack_struct.h###
#pragma once
#include <memory.h>
#include <stdio.h>
#include <stdlib.h>
void* copy_st(void*);
void* create_st(void*);
void* destroy_st(void*);
void* factory_st();
typedef struct
{
size_t _id;
char name[30];
char phone[20];
} Sample;
void* create_st(void* el)
{
return factory_st();
}
void* copy_st(void* el)
{
if (el == NULL) return NULL;
Sample* e = (Sample*)malloc(sizeof(Sample));
*e = *((Sample*)el);
return e;
}
void* destroy_st(void* el)
{
if (el == NULL) return NULL;
free(el);
return NULL;
}
int show_st(void* el)
{
if (el == NULL) return 0;
Sample* e = (Sample*)el;
printf(
" %04d %15s %20s\n",
(int) e->_id, e->name, e->phone);
return 0;
}
void* factory_st()
{
Sample* e = (Sample*)malloc(sizeof(Sample));
e->_id = rand() % 1000;
sprintf(e->name, "Sample id#%04d", (int)e->_id);
memset(e->phone, 0, sizeof(e->phone));
e->phone[0] = '+';
for (int i = 1; i <= 17; i += 1)
e->phone[i] = '0' + rand() % 10;
e->phone[3] = '(';
e->phone[7] = ')';
e->phone[12] = '-';
e->phone[13] = e->name[11];
e->phone[14] = e->name[12];
e->phone[15] = e->name[13];
e->phone[16] = e->name[14];
e->phone[17] = 0;
return (void*)e;
}
code for int elements stack_int.h_###
#pragma once
#include <stdio.h>
#include <stdlib.h>
void* create_i(void* el)
{
int* e = (int*)malloc(sizeof(int));
*e = *((int*)el);
return (void*)e;
}
void* copy_i(void* el)
{
if (el == NULL) return NULL;
int* e = (int*)malloc(sizeof(int));
*e = *( (int*)el );
return e;
}
void* destroy_i(void* el)
{
if (el == NULL) return NULL;
free(el);
return NULL;
}
int show_i(void* el)
{
if (el == NULL) return 0;
int v = *((int*)el);
printf(" %d\n", v);
return 0;
}
void* factory_i()
{
static int i = 42;
int* new_int = (int*)malloc(sizeof(int));
*new_int = i;
i -= 1;
return (void*)new_int;
}
The class implementation class.c
#include "class.h"
#include <stdio.h>
#include <stdlib.h>
void* Copy__(void*);
void* Destroy__(void*);
int POP__(void*);
int PUSH__(void*, void*);
int Show__(void*, const char*);
void* TOP__(void*);
int empty__(void*);
size_t size__(void*);
Stack* create(
size_t sz, void* (*create)(void*), void* (*copy)(void*),
void* (*destroy)(void*), int (*show)(void*))
{
Stack* stack = (Stack*)malloc(sizeof(Stack));
if (stack == NULL) return NULL;
stack->size_ = 0;
stack->lim_ = sz;
stack->data_ = (void*)malloc(sz * sizeof(void*));
stack->copy = Copy__;
stack->destroy = Destroy__;
stack->show = Show__;
stack->create_1 = create;
stack->copy_1 = copy;
stack->destroy_1 = destroy;
stack->show_1 = show;
stack->POP = POP__;
stack->PUSH = PUSH__;
stack->TOP = TOP__;
stack->empty = empty__;
stack->size = size__;
return stack;
}
void* Copy__(void* one) { return NULL; };
void* Destroy__(void* stack)
{ // before destructing a stack we need to
// destroy all elements
if (stack == NULL) return NULL;
Stack* st = (Stack*)stack;
for (size_t ix = 0; ix < st->size_; ix += 1)
(st->destroy_1)(st->data_[ix]);
free(st->data_);
free(st);
return NULL;
};
int POP__(void* stack)
{
if (stack == NULL) return -1; // no stack
Stack* st = stack;
if (st->size_ == 0) return -2; // empty
st->size_ -= 1; // one less
return 0; // ok
}
int PUSH__(void* el, void* stack)
{
if (el == NULL) return -1; // no element
if (stack == NULL) return -2; // no stack
Stack* st = (Stack*)stack;
if (st->size_ == st->lim_) return -3; // full
void* new_el = st->create_1(el); // copy construct
st->data_[st->size_] = new_el;
st->size_ += 1; // one up
return 0; // ok
}
int Show__(void* stack, const char* title)
{
if (stack == NULL) return -1;
Stack* st = stack;
if (title != NULL) printf("%s\n", title);
if (st->size_ == 0)
{
printf("Stack is empty\n");
return 0;
}
for (size_t ix = 0; ix < st->size_; ix += 1)
st->show_1(st->data_[ix]);
printf("\n");
return 0;
}
void* TOP__(void* stack)
{
if (stack == NULL) return NULL; // no stack
Stack* st = stack;
if (st->size_ == 0) return NULL; // empty
return st->data_[st->size_ - 1]; // ok
}
int empty__(void* stack)
{
if (stack == NULL) return 1; // empty??
return ((Stack*)stack)->size_ == 0;
}
size_t size__(void* stack)
{
if (stack == NULL) return 1; // empty??
return ((Stack*)stack)->size_;
}
///////////// TEST FUNCTION ///////////////
int class_test(Stack* tst, void* (*factory)())
{
if (tst == NULL) return -1;
// is stack empty?
if (tst->empty(tst))
printf("Stack is empty\n");
else
printf("Stack: %zd elements\n", tst->size(tst));
int res = tst->POP(tst);
printf("POP() on empty stack returned %d\n", res);
void* top = tst->TOP(tst);
if (top == NULL)
printf("TOP() on empty stack returned NULL\n");
else
{
printf(
"\nTOP() on empty stack returned NOT NULL!\n");
return -2;
}
printf("Calls PUSH until error\n\n");
void* one = factory();
int value = *(int*)one;
while (tst->PUSH(one, tst) == 0)
{
printf("Value inserted:");
tst->show_1(one);
free(one);
one = factory();
}
free(one); // last one, not inserted
printf("Stack now has %zd elements\n", tst->size(tst));
char title[80] = {" "};
sprintf(
title, "\nStack has %zd of %zd elements:\n",
tst->size_, tst->lim_);
tst->show(tst, title);
// agora esvazia a pilha ate dar erro
printf("\nCalls POP() until error\n");
while (tst->POP(tst) == 0)
printf("Stack size: %I32d\n", (int)tst->size(tst));
return 0;
};
The complete main.c program
#include <stdio.h>
#include "class.h"
#include "stack_int.h"
#include "stack_struct.h"
int main(void)
{
srand(220804);
Stack* class_array[2] = {
create(4, create_i, copy_i, destroy_i, show_i),
create(3, create_st, copy_st, destroy_st, show_st)};
printf("\n\n=====> Testing with STACK of int\n\n");
class_test(class_array[0], factory_i);
printf(
"\n\n=====> Testing with STACK of struct "
"Sample\n\n");
class_test(class_array[1], factory_st);
class_array[0]->destroy(class_array[0]);
class_array[1]->destroy(class_array[1]);
return 0;
}
I'm trying to do a "class model" in C in which I define a struct that represents the class and inside it I define function pointers to represent methods, like this:
//ClassName.h
typedef struct struct_ClassName ClassName;
struct ClassName
{
char a;
char b;
char c;
void (*method1)(ClassName*, char);
void (*method2)(ClassName*, char);
...
void (*methodN)(ClassName*, char);
};
void initClassName(ClassName*);
//ClassName.c
#include "ClassName.h"
static void method1(ClassName *this_c, char c);
static void method2(ClassName *this_c, char c);
...
static void methodN(ClassName *this_c, char c);
void initClassName(ClassName *this_c)
{
this_c->method1 = &method1;
this_c->method2 = &method2;
...
this_c->methodN = &methodN;
}
void method1(ClassName *this_c, char c)
{
//do something
}
void method2(ClassName *this_c, char c)
{
//do something
}
...
void methodN(ClassName *this_c, char c)
{
//do something
}
Everything works fine but, somewhere in the code, I define an array:
...
ClassName objects[200];
for(i = 0; i < 200; i++)
{
initClassName(&objects[i]);
}
...
Because of the function pointers, the memory usage associated to this array is quite high (I have several "methods" in this "class").
Considering that this is a code that will run in an embedded system, is there a better way to do it?
Defining functions outside the structure could be a possibility but in my opinion it does not respect what I'm trying to emulate.
I have to use only C, not C++.
What you have created is a very dynamic system where each object instance can have its own set of method implementations. That's why it uses so much memory.
Another approach is an implementation closer to early C++ (before multiple inheritance) where all instance of the same class share the same vtable. The vtable contains the function pointers.
typedef struct struct_ClassName ClassName;
typedef struct struct_ClassName_vtable ClassName_vtable;
struct ClassName_vtable
{
void (*method1)(ClassName*, char);
void (*method2)(ClassName*, char);
...
void (*methodN)(ClassName*, char);
}
struct ClassName
{
ClassName_vtable* _vtable;
char a;
char b;
char c;
};
void initClassName(ClassName*);
static void method1(ClassName *this_c, char c);
static void method2(ClassName *this_c, char c);
...
static void methodN(ClassName *this_c, char c);
ClassName_vtable _ClassName_vtable = {
method1,
method2,
...,
methodN
};
void initClassName(ClassName *this_c)
{
this_c->_vtable = _ClassName_vtable;
}
That way, the OO overhead per instance is only the size of a pointer. It's also easier to create subclasses.
A method call looks like this:
ClassName* obj = ...;
obj->vtable->method2(obj, 'a');
ClassName objects[200];
for(i = 0; i < 200; i++)
initClassName(&objects[i]);
I will show you a stripped-off version of something I use here
for similar effect. It is hard to say when a certain size is huge in terms of pointers or whatever. Each environment has their truth and this can be useless or useful...
Anyway, the ideia is encapsulation. And in C we have no this pointer. C is not C++ or java or javascript. Each class instance must have a table of function pointers for the methods. We need to build these tables. This is how virtual classes are implemented in others languages anyway. And if each class element can allocate memory code is needed to allocate and free memory.
TL;DR
Below is a C example of a program that builds and uses an array of classes. In this case an array of stacks. It shows a mechanism of building stacks of mixed things. Each array item has all that is needed to manage his own stack instance, be it of a trivial type or a complex structure. It can be easily changed to implement other tyoes of classes in C.
Please do not bother warning me that I cast the return of malloc(). I , as many others, do not like implicit things. And I know that C-FAQ is a never-updated thing from the end of the '90s so no need to reference this either.
An example: a static STACK container
typedef struct
{
int data[SIZE];
int limit; // capacity
int size; // actual
} Stack;
This is it: a simple stack of int values. Let us say we want to declare a vector of stacks of different things, but in C. And use methods on them. If we use trivial types --- in C++ we say the struct is trivialy constructible --- things can get easier, but if we are about to use structs we need to know about how to manipulate stack elements, since they can allocate memory.
We are writing a container so the methods of the class must work for any underlying data. And we have no iterators like C++ STL. Here we are implementing the POP TOP and PUSH methods for stacks, and a toString() method like in java to print values on the screen.
For each possible content in the container we need to have a constructor, a
destructor, a copy constructor and a display method. In this example we have just 2 types of stacks: a stack of int and a stack of struct Sample:
typedef struct
{
size_t _id;
char name[30];
char phone[20];
} Sample;
We can add others just by writing the required 4 functions.
main.c example
int main(void)
{
srand(220804); // for the factory functions
Stack* class_array[2] = {
create(4, create_i, copy_i, destroy_i, show_i),
create(3, create_st, copy_st, destroy_st, show_st)};
printf("\n\n=====> Testing with STACK of int\n\n");
class_test(class_array[0], factory_i);
printf(
"\n\n=====> Testing with STACK of struct "
"Sample\n\n");
class_test(class_array[1], factory_st);
class_array[0]->destroy(class_array[0]);
class_array[1]->destroy(class_array[1]);
return 0;
}
Each instance of Stack has pointers to the stack methods and to the functions that manipulate the stack data, so we can have a single class_test() function that does the following:
builds a stack of the required size, 4 or 3 in the example
fills the stack with data generated by factory functions (in production the logic builds the data)
shows the stack contents
removes all stack elements, one by one
At the end the destructor is called for eack stack.
The class.h file
typedef void* (PVFV)(void*);
typedef int (PIFV)(void*);
typedef struct
{
size_t size_;
size_t lim_;
void** data_;
PVFV* copy;
PVFV* destroy;
int (*show)(void*,const char*); // for testing
// constructor and destructor for container elements
PVFV* create_1;
PVFV* copy_1;
PVFV* destroy_1;
PIFV* show_1;
// member functions
PIFV* POP;
int (*PUSH)(void*,void*);
PVFV* TOP;
PIFV* empty;
size_t (*size)(void*);
} Stack;
Stack* create(
size_t,
void* (*)(void*),
void* (*)(void*),
void* (*)(void*),
int (*)(void*));
int class_test(Stack*, void* (*)());
the example output
=====> Testing with STACK of int
Stack is empty
POP() on empty stack returned -2
TOP() on empty stack returned NULL
Calls PUSH until error
Value inserted: 42
Value inserted: 41
Value inserted: 40
Value inserted: 39
Stack now has 4 elements
Stack has 4 of 4 elements:
42
41
40
39
Calls POP() until error
Stack size: 3
Stack size: 2
Stack size: 1
Stack size: 0
=====> Testing with STACK of struct Sample
Stack is empty
POP() on empty stack returned -2
TOP() on empty stack returned NULL
Calls PUSH until error
Value inserted: 0195 Sample id#0195 +76(203)6840-195
Value inserted: 0943 Sample id#0943 +35(686)9368-943
Value inserted: 0152 Sample id#0152 +16(051)8816-152
Stack now has 3 elements
Stack has 3 of 3 elements:
0096 Sample id#0096 +24(477)0418-096
0037 Sample id#0037 +27(214)3509-037
0836 Sample id#0836 +68(857)4634-836
Calls POP() until error
Stack size: 2
Stack size: 1
Stack size: 0
the logic
For each tye of element we need to write the 4 functions: they can alocate memory and be very complex or they can be trivial, but the class methods need to handle any case.
code for struct Sample in stack_struct.h###
#pragma once
#include <memory.h>
#include <stdio.h>
#include <stdlib.h>
void* copy_st(void*);
void* create_st(void*);
void* destroy_st(void*);
void* factory_st();
typedef struct
{
size_t _id;
char name[30];
char phone[20];
} Sample;
void* create_st(void* el)
{
return factory_st();
}
void* copy_st(void* el)
{
if (el == NULL) return NULL;
Sample* e = (Sample*)malloc(sizeof(Sample));
*e = *((Sample*)el);
return e;
}
void* destroy_st(void* el)
{
if (el == NULL) return NULL;
free(el);
return NULL;
}
int show_st(void* el)
{
if (el == NULL) return 0;
Sample* e = (Sample*)el;
printf(
" %04d %15s %20s\n",
(int) e->_id, e->name, e->phone);
return 0;
}
void* factory_st()
{
Sample* e = (Sample*)malloc(sizeof(Sample));
e->_id = rand() % 1000;
sprintf(e->name, "Sample id#%04d", (int)e->_id);
memset(e->phone, 0, sizeof(e->phone));
e->phone[0] = '+';
for (int i = 1; i <= 17; i += 1)
e->phone[i] = '0' + rand() % 10;
e->phone[3] = '(';
e->phone[7] = ')';
e->phone[12] = '-';
e->phone[13] = e->name[11];
e->phone[14] = e->name[12];
e->phone[15] = e->name[13];
e->phone[16] = e->name[14];
e->phone[17] = 0;
return (void*)e;
}
code for int elements stack_int.h_###
#pragma once
#include <stdio.h>
#include <stdlib.h>
void* create_i(void* el)
{
int* e = (int*)malloc(sizeof(int));
*e = *((int*)el);
return (void*)e;
}
void* copy_i(void* el)
{
if (el == NULL) return NULL;
int* e = (int*)malloc(sizeof(int));
*e = *( (int*)el );
return e;
}
void* destroy_i(void* el)
{
if (el == NULL) return NULL;
free(el);
return NULL;
}
int show_i(void* el)
{
if (el == NULL) return 0;
int v = *((int*)el);
printf(" %d\n", v);
return 0;
}
void* factory_i()
{
static int i = 42;
int* new_int = (int*)malloc(sizeof(int));
*new_int = i;
i -= 1;
return (void*)new_int;
}
The class implementation class.c
#include "class.h"
#include <stdio.h>
#include <stdlib.h>
void* Copy__(void*);
void* Destroy__(void*);
int POP__(void*);
int PUSH__(void*, void*);
int Show__(void*, const char*);
void* TOP__(void*);
int empty__(void*);
size_t size__(void*);
Stack* create(
size_t sz, void* (*create)(void*), void* (*copy)(void*),
void* (*destroy)(void*), int (*show)(void*))
{
Stack* stack = (Stack*)malloc(sizeof(Stack));
if (stack == NULL) return NULL;
stack->size_ = 0;
stack->lim_ = sz;
stack->data_ = (void*)malloc(sz * sizeof(void*));
stack->copy = Copy__;
stack->destroy = Destroy__;
stack->show = Show__;
stack->create_1 = create;
stack->copy_1 = copy;
stack->destroy_1 = destroy;
stack->show_1 = show;
stack->POP = POP__;
stack->PUSH = PUSH__;
stack->TOP = TOP__;
stack->empty = empty__;
stack->size = size__;
return stack;
}
void* Copy__(void* one) { return NULL; };
void* Destroy__(void* stack)
{ // before destructing a stack we need to
// destroy all elements
if (stack == NULL) return NULL;
Stack* st = (Stack*)stack;
for (size_t ix = 0; ix < st->size_; ix += 1)
(st->destroy_1)(st->data_[ix]);
free(st->data_);
free(st);
return NULL;
};
int POP__(void* stack)
{
if (stack == NULL) return -1; // no stack
Stack* st = stack;
if (st->size_ == 0) return -2; // empty
st->size_ -= 1; // one less
return 0; // ok
}
int PUSH__(void* el, void* stack)
{
if (el == NULL) return -1; // no element
if (stack == NULL) return -2; // no stack
Stack* st = (Stack*)stack;
if (st->size_ == st->lim_) return -3; // full
void* new_el = st->create_1(el); // copy construct
st->data_[st->size_] = new_el;
st->size_ += 1; // one up
return 0; // ok
}
int Show__(void* stack, const char* title)
{
if (stack == NULL) return -1;
Stack* st = stack;
if (title != NULL) printf("%s\n", title);
if (st->size_ == 0)
{
printf("Stack is empty\n");
return 0;
}
for (size_t ix = 0; ix < st->size_; ix += 1)
st->show_1(st->data_[ix]);
printf("\n");
return 0;
}
void* TOP__(void* stack)
{
if (stack == NULL) return NULL; // no stack
Stack* st = stack;
if (st->size_ == 0) return NULL; // empty
return st->data_[st->size_ - 1]; // ok
}
int empty__(void* stack)
{
if (stack == NULL) return 1; // empty??
return ((Stack*)stack)->size_ == 0;
}
size_t size__(void* stack)
{
if (stack == NULL) return 1; // empty??
return ((Stack*)stack)->size_;
}
///////////// TEST FUNCTION ///////////////
int class_test(Stack* tst, void* (*factory)())
{
if (tst == NULL) return -1;
// is stack empty?
if (tst->empty(tst))
printf("Stack is empty\n");
else
printf("Stack: %zd elements\n", tst->size(tst));
int res = tst->POP(tst);
printf("POP() on empty stack returned %d\n", res);
void* top = tst->TOP(tst);
if (top == NULL)
printf("TOP() on empty stack returned NULL\n");
else
{
printf(
"\nTOP() on empty stack returned NOT NULL!\n");
return -2;
}
printf("Calls PUSH until error\n\n");
void* one = factory();
int value = *(int*)one;
while (tst->PUSH(one, tst) == 0)
{
printf("Value inserted:");
tst->show_1(one);
free(one);
one = factory();
}
free(one); // last one, not inserted
printf("Stack now has %zd elements\n", tst->size(tst));
char title[80] = {" "};
sprintf(
title, "\nStack has %zd of %zd elements:\n",
tst->size_, tst->lim_);
tst->show(tst, title);
// agora esvazia a pilha ate dar erro
printf("\nCalls POP() until error\n");
while (tst->POP(tst) == 0)
printf("Stack size: %I32d\n", (int)tst->size(tst));
return 0;
};
The complete main.c program
#include <stdio.h>
#include "class.h"
#include "stack_int.h"
#include "stack_struct.h"
int main(void)
{
srand(220804);
Stack* class_array[2] = {
create(4, create_i, copy_i, destroy_i, show_i),
create(3, create_st, copy_st, destroy_st, show_st)};
printf("\n\n=====> Testing with STACK of int\n\n");
class_test(class_array[0], factory_i);
printf(
"\n\n=====> Testing with STACK of struct "
"Sample\n\n");
class_test(class_array[1], factory_st);
class_array[0]->destroy(class_array[0]);
class_array[1]->destroy(class_array[1]);
return 0;
}
I'm trying to create a stack in C using structures but the push() function I wrote is acting strangely. I'm sure it is something obvious that I'm missing but I just couldn't figure out what.
#include <stdio.h>
#define STACK_SIZE 50
typedef struct stack
{
int top;
int items[STACK_SIZE];
}
STACK;
void push(STACK* st, int newitem)
{
st->top++;
st->items[st->top] = newitem;
printf("%d", st->items[st->top]);
}
int main()
{
int n = 1;
STACK* st;
printf("test 1\n");
st->top = -1;
push(st, n);
printf("test 2\n");
return 0;
}
DevCpp only compiles but doesn't execute the code. OnlineGDB runs it but only prints the first test.
This is because your variable STACK* st; was never initialized properly.
Some Important Points:
Don't assign -1 to the length (top), 0 would be better
STACK* st; should be just STACK st;
Your function void push(STACK* st, int newitem) should be declared with static linkage.
Write st->top++
Pass st variable by address to the push() function
Instead of using bare return 0;, use return EXIT_SUCCESS;, which is defined in the header file stdlib.h.
As your total STACK_SIZE is only 50 so, int will be sufficient. But as your STACK_SIZE grows use size_t for your length(top).
use int main(void) { }, instead of int main() { }
NOTE: If STACK_SIZE and top becomes equal means your array is filled completely then further addition of data will lead to Undefined Behavior.
Final Code
#include <stdio.h>
#include <stdlib.h>
#define STACK_SIZE 50
typedef struct stack
{
int top;
int items[STACK_SIZE];
}
STACK;
static void push(STACK* st, int newitem)
{
if(st->top == STACK_SIZE)
{
fprintf(stderr, "stack size reached maximum length\n");
exit(EXIT_FAILURE);
}
st->items[st->top++] = newitem;
printf("%d\n", st->items[st->top - 1]); // we added +1 to `top` in the above line
}
int main(void)
{
int n = 1;
STACK st;
printf("test 1\n");
st.top = 0;
push(&st, n); //pass by address
return EXIT_SUCCESS;
}
I am implementing a small program to exercise with double pointers
This is the main program:
#include <stdio.h>
#include "serial.h"
#include "stack.h"
int main(void) {
serial_init();
/* Array to hold stack entries */
int stack[10]={0};
/* Stack pointer */
int *stack_p = stack;
/* Code to call the functions */
push(&stack_p, 1);
push(&stack_p, 2);
push(&stack_p, 3);
push(&stack_p, 4);
printf("popped value: %d\r\n", pop(&stack_p));
printf("popped value: %d\r\n", pop(&stack_p));
printf("popped value: %d\r\n", pop(&stack_p));
printf("popped value: %d\r\n", pop(&stack_p));
}
void push(int **sp, int value) {
/* Implement it */
}
int pop(int **sp) {
/* Implement it */
}
I have implemented the push function it seems ok. However, the pop return back just the last element and then 10
void push(int **sp, int value) {
/* implemented it*/
int *pt;
pt=&value; // Store the value to the pointer
printf("Push value is is %d\r\n", *pt);
sp = &pt; // associate the pointer to the pointer of pointer
++(*pt);
}
int pop(int **sp) {
/* implemented it */
int value;
int *pt;
pt=&value;
sp = &pt;
*pt--;
return value;
}
Your push and pop functions are overly complicated and totally wrong:
You want this:
void push(int **sp, int value) {
**sp = value; // put value onto top of the stack
(*sp)++; // increment stack pointer
}
int pop(int **sp) {
(*sp)--; // decrement stack pointer
return **sp; // return value which is on nthe op of the stack
}
Your wrong code for push with explanations in comments:
void push(int **sp, int value) {
int *pt;
pt=&value; // here you put the pointer to the local variable value
// into pt, but local variables disappear as soon
// as the function has finished
// the printf is the only thing one more or less correct
// but you could just print directly 'value' like this:
// printf("Pushed value is %d\r\n", value);
//
printf("Push value is is %d\r\n", *pt);
sp = &pt; // this only assigns the pointer to the local variable pt to
// the local variable sp
++(*pt); // here you increment actually the local variable
// value which is pointless
}
By the way: the initialisation to zero of the whole stack is not necessary, although it might help during the debugging process. So you can write the declaration of the stack like this:
int stack[10]; // no initialisation necessary
Exercise for you:
Explain the exact reason why it is not necessary to initialize all elements of the stack to zero.
Let's say that I have the following code in C that represents a stack :
#define MAX 1000
int arr[MAX];
static int counter = 0;
isstackempty()
{
return counter <= 0;
}
void push(int n)
{
if (counter >= MAX) {
printf("Stack is full. Couldn't push %d", n);
return;
}
arr[counter++] = n;
}
int pop(int* n)
{
if(isstackempty() || n == 0) {
printf("Stack is empty\n");
return 0;
}
*n = arr[--counter];
return 1;
}
The above code is in a stack.c file and the function prototypes are in a header.
Now, coming from a C# and OO background, if I would want to separate stacks to use in my application, in an OO language I would create two instances. But in C, how do you handle such a scenario?
Say I want to use two separate stacks in my C code...with the above code, how would I go about it?
Put the array arr inside a struct.
struct stack {
int arr[MAX];
...
}
This struct becomes your instance. You can then declare it on the stack:
struct stack mystack;
or on the heap using malloc:
struct stack *mystack = malloc(sizeof(struct stack));
You also need to pass a pointer to the instance as the first parameter to any function manipulating the instance.
The C way to do this is to wrap up all the state for your 'object' into a struct, and then explicitly pass it into all the functions that operate on stacks, so it should be:
typedef struct _stack {
int arr[MAX];
int counter;
} stack;
int isstackempty(stack *s)
{
return s->counter <= 0;
}
int push(stack *s, int n)
{
if (s->counter >= MAX) {
printf("Stack is full. Couldn't push %d", n);
return -1;
}
arr[s->counter++] = n;
return 0
}
int pop(stack *s, int *n)
{
if(isstackempty(s) || n == 0) {
printf("Stack is empty\n");
return -1;
}
*n = arr[--s->counter];
return 0;
}
The issue with your example is you're writing the function definitions like we have a class-based object structure, which C doesn't have. The easiest way to think about how it's done in C is that you're writing methods that require you to explicitly pass in the 'this' parameter.
Also you can have the equivalent of constructors and destructors, which can further abstract your 'object'.
stack* newStack() {
stack* s = malloc(sizeof(stack));
s->counter = 0;
return s;
}
void freeStack(stack* s) {
free(s);
}
One (extremely simplistic) way of going about it is to define a struct that represents a stack:
typedef struct {
int arr[MAX];
int counter = 0;
} myStack;
and then rewrite push() and pop() to operate on an instance of myStack:
int push(myStack *s, int n)
{
if (s->counter >= MAX) {
printf("Stack is full. Couldn't push %d", n);
return -1;
}
s->arr[(s->counter)++] = n;
return s->counter;
}
int pop(myStack *s, int* n)
{
if(0 == s->counter || 0 == n) {
printf("Stack is empty\n");
return -1;
}
*n = s->arr[--(s->counter)];
return 1;
}
(Also added a meaningful return value and error value to push(). YMMV.)
I hope you find this paper useful. It gives more than one answer to your question :)
Sixteen Ways to Stack a Cat
Simply make your 'this' pointer explicit:
struct stack* create_stack();
void push(struct stack* mystack, int n);
void pop(struct stack* mystack, int* n);
My answer to this other question has a complete working example of an OO data buffer structure in C.
A dynamically allocated structre-per-instance is the right way to go. A point of detail - if you are writing a more generally used API it is probably a good idea to engage in data hiding for better abstraction.
The simplest way of doing this is keep the definition of the internal structure in the C file (or a private header file), and typedef a void pointer to (e.g.) 'stack_handle_t'. It is this type that is returned from your 'constructor' and is passed back in to each other function.
The implementation is aware that the value of the handle is in fact a pointer to a structure and at the beginning of each function simply does:
int pop(stack_handle_t handle, int* n)
{
stack *p_stack = (stack *)handle;
...
Even better than that is to use an internally allocated identifier instead, whether this is an index into an array of these structs or simply an identifier which can be matched against one of a (linked?) list of structs.
Obviously all this is irrelevant if its only for use internal to your project, in those circumstances it is just making unnecessary work and over-complication.