I'm trying to create a stack in C for fun, and came up with the idea of using struct to represent the stack. Then I add function pointers to the struct for push() and pop() operations.
So far all is good it seems, but, for the implementation of the push() and pop() functions I need to refer to *this somehow. How can that (can it?) be done?
This is my struct
struct Stack {
int *data;
int current_size;
int max_size;
int (*push)(int);
int (*pop)();
};
And as an example here's push
int push(int val) {
if(current_size == max_size -1)
return 0;
data[current_size] = val;
current_size++;
return 1;
}
As you can imagine, the compiler has no idea what current_size is, as it would expect something like stack->current_size.
Is this possible to overcome somehow?
There's no implicit this in C. Make it explicit:
int push(Stack* self, int val) {
if(self->current_size == self->max_size - 1)
return 0;
self->data[self->current_size] = val;
(self->current_size)++;
return 1;
}
You will of course have to pass the pointer to the struct into every call to push and similar methods.
This is essentially what the C++ compiler is doing for you when you define Stack as a class and push et al as methods.
The typical approach in C is to have functions expect this as the first parameter.
int push(Stack *self, int val)
{
if (self->current_size == self->max_size -1) return 0;
self->data[self->current_size++] = val;
return 1;
}
This has the added benefit that, unless you need polymorphism, you don't need to put the functions in the stack, because you could just call push(stack, 10) instead of stack->push(stack,10).
C doesn't work like that. It's not an object oriented language. Functions that manipulate data structures need to take a pointer to the structure as an argument.
In header file you can declare static this variable
static struct Stack *this;
And then in push method you can use this variable
static int push(int val) {
if(this->current_size == this->max_size - 1)
return 0;
this->data[this->current_size] = val;
(this->current_size)++;
return 1;
}
The caveat is you have to manually set this variable through some method before you want to invoke other methods, eg:
struct Stack {
struct Stack (*_this)(struct Stack *); // <-- we create this method
int *data;
int current_size;
int max_size;
int (*push)(int);
int (*pop)();
};
And then we can implement _this method as
static struct Stack *_this(struct Stack *that)
{
retrun this = that;
}
The example:
struct Stack stack1, stack2;
... some initialization ...
stack1->_this(&stack1)->push(0);
stack1->push(1);
stack1->push(2);
stack2->_this(&stack2);
stack2->push(10);
stack2->push(20);
Your function pointers aren't methods so they don't have any information about the calling object. The only way to do what you want is to either pass in a pointer to the object, or make that pointer global (the latter is not recommended).
Obviously you can have a Stack * member in the struct and then just initialize it with the address of the struct before you use the function pointers. Then make the Stack * a parameter on the function pointers.
Since your are going to have only one Stack structure (that you named stack, apparently), you could define it as a global variable. This would allow pop/push to refer to the stack variable directly.
You would do something like:
stack.current_size += 4;
or use the -> operator if you decide to declare stack as a memory pointer to Stack.
Related
Lets say I have this structure
typedef struct Stack
{
int firstPlayerScore;
int secondPlayerScore;
int gamesCount;
}Stack;
and this function to ini the values:
void initStack(Stack *g)
{
g->firstPlayerScore = 0;
g->secondPlayerScore = 0;
g->gamesCount = 0;
}
The problem is here, I need to be able to reset other values, but keep g.gamescount and add +1 each time gameStart function runs. Its probably a simple solution ,but I am starting to lose my mind, thank you.
void gameStart(int choice) {
Stack g;
initStack(&g);
++g.gamesCount; // this works only once, then is reset again to 0.
{
// do stuff
}
}
Cant do differently, since I believe Structure need to be inicialized. Maybe it is possible to inicialize only once somehow?
P.S I cant use global variables
Pass a pointer to the state to your function:
void gameStart(Stack *g, int choice) {
++g.gamesCount; // this works only once, then is reset again to 0.
{
// do stuff
}
}
Then inside main():
int main() {
Stack g;
initStack(&g);
gameStart(&g, 49);
}
You need to allocate memory for the struct Stack variable g. You do not need global variables, what you need is to just while declaring g you need to call malloc function to allocate memory of the size of the struct type. It looks like this:
void gameStart(int choice) {
Stack *g = (Stack *) malloc(sizeof(Stack));
initStack(g);
++g->gamesCount; // this works only once, then is reset again to 0.
{
// do stuff
}
}
Malloc returns you void *, so it is better to typecast to Stack *. Also, you need to create Stack *, as it is a struct type and requires pointer tpye.
Hope this will help you.
I am trying to create a struct object (stack) which consists of:
typedef struct node {
int val;
struct node * next;
}node_t;
typedef struct {
node_t * top;
int max_size;
int used_size;
} Stack;
However, when I try to initialize the object and allocate it some memory space using the function:
Stack * newStack(int max_size) {
Stack * S = malloc(sizeof(Stack));
S->top = NULL;
S->max_size = max_size;
S->used_size = 0;
return S;
}
Stack * S = newStack(256); //error here
I get the error referred to above -
function call is not allowed in constant expression
I have never come across this type of error before, and I don't know how to tackle it. Any help is appreciated.
In C language objects with static storage duration can only be initialized with constant expressions.
You are initializing a global variable S, which is an object with static storage duration. Your expression newStack(256) is not a constant expression. As the compiler told you already, you are not allowed to call functions in constant expressions. Hence the error. That's all there is to it.
If you want to have a global variable S, then the only way to "initialize" it with newStack(256) is to do it inside some function at program startup. E.g.
Stack * S;
int main()
{
S = newStack(256);
...
}
When in C, Make sure that your call to a function is done inside a function. For instance:-
#include <stdlib.h>
int return_something()
{
return 100;
}
int something = return_something();
This would obviously through an error, to resolve the issue, call int_something() from inside some other function frame
I'm trying to learn c using learncodethehardway c book. In ex19 I have the following code:
int Monster_init(void *self)
{
Monster *monster = self;
monster->hit_points = 10;
return 1;
}
int Monster_attack(void *self, int damage)
{
Monster *monster = self;
printf("You attack %s!\n", monster->proto.description);
monster->hit_points -= damage;
if(monster->hit_points > 0) {
printf("It is still alive.\n");
return 0;
} else {
printf("It is dead.\n");
return 1;
}
}
Object MonsterProto = {
.init = Monster_init,
.attack = Monster_attack
};
This is the Object structure:
typedef struct {
char *description;
int (*init)(void *self);
void (*describe)(void *self);
void (*destroy)(void *self);
void *(*move)(void *self, Direction direction);
int (*attack)(void *self, int damage);
} Object;
And this is the Monster structure:
struct Monster {
Object proto;
int hit_points;
};
I'm having a tough time wrapping my head around the Monster_init and Monster_attack functions. I have a MonsterProto variable of type Object defined and inside there .init is set to the Monster_initfunction and .attack is set to the Monster_attack function.
I think I understand the notion of void in terms of declaring a function that has side effects but doesn't need to return something. What I don't understand is what exactly is the void *self pointer pointing at and why does it allow me to call a function with no arguments? What is the purpose of the self pointer?
I didn't want to include too much code here but if this is not enough context to answer the question, then you can find all the code here.
I appreciate any pointers in the right direction; nu pun intended :)
This code seems to be effectively implementing a kind of object-oriented approach.
self is the address of the struct Monster that you pass to those functions. Each of those functions operates on an individual object, and passing in the pointer to that object is how they know which one to work on.
This:
.init = Monster_init,
is not "calling a function with no arguments" - the init member of your struct is a pointer to a function returning an int and accepting a single void * parameter, and that line assigns the address of Monster_init() to it. This way, if you have a pointer to an object, you can call int n = myobject->proto.init(&myobject); or similar without knowing which actual function gets called. With a different object, you might be calling a different function with the same line of code.
My college professor taught us that a generic stack looks something like this (I basically copy-pasted this from the course support files):
typedef struct
{ size_t maxe, dime;
char *b, *sv, *vf;
} TStiva, *ASt;
#define DIME(a) (((ASt)(a))->dime)
#define BS(a) (((ASt)(a))->b)
#define SV(a) (((ASt)(a))->sv)
#define VF(a) (((ASt)(a))->vf)
#define DIMDIF(s,d) (DIME(s) != DIME(d))
#define VIDA(a) (VF(a) == BS(a))
#define PLINA(a) (VF(a) == SV(a))
// Function Declarations
void* InitS(size_t d,...);
int Push(void* a, void* ae);
int Pop (void* a, void* ae);
int Top (void* a, void* ae);
void *InitS(size_t d,...)
{ ASt a = (ASt)malloc(sizeof (TStiva));
va_list ap;
if (!a) return NULL;
va_start(ap,d);
a->maxe = va_arg(ap,size_t);
va_end(ap);
a->dime = d;
a->b = (char*)calloc(a->maxe, d);
if (!a->b) { free(a); return NULL; }
a->vf = a->b;
a->sv = a->b + d * a->maxe;
return (void *)a;
}
int Push(void *a, void *ae)
{ if( PLINA(a)) return 0;
memcpy (VF(a), ae, DIME(a));
VF(a) += DIME(a);
return 1;
}
int Pop(void *a, void *ae)
{ if(VIDA(a)) return 0;
VF(a) -= DIME(a);
memcpy (ae, VF(a), DIME(a));
return 1;
}
int Top(void *a, void *ae)
{ if(VIDA(a)) return 0;
memcpy (ae, VF(a)-DIME(a), DIME(a));
return 1;
}
Anyway, what this wants to be is a generic stack implementation with vectors, from which I don't understand why in the Top, Push and Pop functions need to refer to the stack data structure as a void *.
By generic, doesn't it want to mean that the value the data structure wants to hold is generic? This meaning that if you refer to your generic data structure as the typedef instead of void * it doesn't certainly mean that it's not generic.
I am asking this because I am about to create a Generic Stack implemented with Linked Lists and I am a bit confused.
This is my generic linked list data structure:
typedef struct Element {
struct Element *next;
void *value;
} TElement, *TList, **AList;
And for the Stack:
typedef struct Stack {
size_t size;
TList top;
} TStack, *AStack;
/* Function Definitions */
TStack InitStack(size_t);
void DeleteStack(AStack);
int Push(TStack, void*);
int Pop(TStack, void*);
int Top(TStack, void*);
Does anything seem not generic in my implementation?
Generic means that it can hold ANY data type (char*, int*, etc..), or contain any data type. Void pointers void * in C allow you to cast items as such and get those items out(having to re-cast them on retrieval.
So, it allows the program to be ignorant of the data types that you have in your custom data structure.
Referring to the structure itself(as long as you are not specifying the data that is held in said structure), does not break generalities. So, you can specifically mention your TStack in your functions as long as the data that is manipulated inside of that stack is general(id est void *).
void* is for generic purposes. Imagine it as a pointer to the memory, where of course the memory can hold anything. By void* you mean that you do not know what you point to, but you know that you point to something.
Yes a void*can correctly implement a generic stack, but that creates a problem that you have no idea about the type of data you are storing in the Stack. The concept of void* is that it is pointing to some valid block of memory, but there is absolutely no clue as to the type of the memory. So, the code that is using this generic stack has to do type conversion explicitly. void* are used only to store data, manipulation with them are disallowed.
In a project I'm writing code for, I have a void pointer, "implementation", which is a member of a "Hash_map" struct, and points to an "Array_hash_map" struct. The concepts behind this project are not very realistic, but bear with me. The specifications of the project ask that I cast the void pointer "implementation" to an "Array_hash_map" before I can use it in any functions.
My question, specifically is, what do I do in the functions to cast the void pointers to the desired struct? Is there one statement at the top of each function that casts them or do I make the cast every time I use "implementation"?
Here are the typedefs the structs of a Hash_map and Array_hash_map as well as a couple functions making use of them.
typedef struct {
Key_compare_fn key_compare_fn;
Key_delete_fn key_delete_fn;
Data_compare_fn data_compare_fn;
Data_delete_fn data_delete_fn;
void *implementation;
} Hash_map;
typedef struct Array_hash_map{
struct Unit *array;
int size;
int capacity;
} Array_hash_map;
typedef struct Unit{
Key key;
Data data;
} Unit;
functions:
/* Sets the value parameter to the value associated with the
key parameter in the Hash_map. */
int get(Hash_map *map, Key key, Data *value){
int i;
if (map == NULL || value == NULL)
return 0;
for (i = 0; i < map->implementation->size; i++){
if (map->key_compare_fn(map->implementation->array[i].key, key) == 0){
*value = map->implementation->array[i].data;
return 1;
}
}
return 0;
}
/* Returns the number of values that can be stored in the Hash_map, since it is
represented by an array. */
int current_capacity(Hash_map map){
return map.implementation->capacity;
}
You can cast it each time you use it, or you can cast it once and save the value to a temporary variable. The latter is usually the cleanest method.
For example, you could use something like:
void my_function (Hash_Map* hmap) {
Array_hash_map* pMap;
pMap = hmap->implementation;
// Now, you are free to use the pointer like it was an Array_hash_map
pMap->size = 3; // etc, etc
}