I'm doing an exercise, and want support about it. The problem is this: I have two structures (1 for the nodes of the stack, 1 for the stack). In the node structure, there is a void* data field.
I've tried to push a value on the stack but, because of void* data instead of simple data, I failed.
This is the code about the structures and the push() function.
struct upo_stack_node_s
{
void *data;
struct upo_stack_node_s *next;
};
typedef struct upo_stack_node_s upo_stack_node_t;
struct upo_stack_s
{
upo_stack_node_t *top;
size_t size;
};
/*Function for create the stack*/
upo_stack_t upo_stack_create()
{
upo_stack_t stack = malloc(sizeof(struct upo_stack_s));
if (stack == NULL)
{
fprintf(stderr, "Unable to create a stack!\n");
abort();
}
stack->top = NULL;
stack->size = 0;
return stack;
}
/*Push() function:*/
void upo_stack_push(upo_stack_t stack, void *data)
{
/* TO STUDENTS:
* Remove the following two lines and put here your implementation
*/
upo_stack_node_t *node = malloc(sizeof(struct upo_stack_node_s));
node->data = data; /*<-- Here's the problem */
node->next = stack->top;
stack->top = node;
++stack->size;
}
/*Top() function*/
void* upo_stack_top(const upo_stack_t stack)
{
/* TO STUDENTS:
* Remove the following two lines and put here your implementation
*/
return (void *)(stack->top); //<---
}
/*Function for testing (there are other functions in the code)*/
void test_top()
{
int value1 = 1;
int value2 = 2;
upo_stack_t stack;
stack = upo_stack_create();
upo_stack_push(stack, &value1); //<----
upo_stack_push(stack, &value2); //<----
assert( upo_stack_top(stack) != NULL );
assert( *((int*) upo_stack_top(stack)) == value2 ); <-- Here's the error
upo_stack_pop(stack, 0);
assert( upo_stack_top(stack) != NULL );
assert( *((int*) upo_stack_top(stack)) == value1 );
upo_stack_pop(stack, 0);
assert( upo_stack_top(stack) == NULL );
upo_stack_destroy(stack, 0);
}
You always have to pass a void pointer. That means if you want to pass a simple value, like 1, what you need to do is, is to allocate an integer value, and pass the pointer to it (as a void pointer).
Thus something like:
int x = 4;
upo_stack_push(upo_stack, &x);
Of course you have to make sure the int variable x does not go out of scope, otherwise the pointer will point to freed memory, which results in nasty memory problems.
Update
It is assumed above, that the void pointer you pass is stored already in memory for the scope of the stack. In case, you want the stack itself to copy the data, you have also to malloc space for that, thus not only mallocing the node, but also mallocing and copy the data type passed. Also to know the size of the data (since it is a void pointer, which is unaware of its type), you have to add an int size parameter to the push function.
For an integer value to be stored, pass it as a pointer, with size: sizeof(int). Than for copying the data structure, use memcpy. This only works for simple types and structures without pointers. If you have to copy structures with pointers (thus you need so called deep-copying), than it is more tricky.
Related
stack.h
#define MAX_STACK 10
typedef int STACK_ITEM;
typedef struct Stack *STACK ;
stack.c
#include"stack.h"
struct Stack{
STACK_ITEM contents[MAX_STACK];
int tos;
};
_Bool create_stack(STACK s){
s = malloc(sizeof(struct Stack));
if(s == NULL )
return 0;
s->tos = 0;
return 1;
}
When calling the create_stack function, it doesn't affect s (pointer to structure) at all. So, my question is: why is s not changing, even though it is a pointer, not a value, passed?
Remember, all parameters are passed by value in C.
When you pass a pointer as a function parameter, you can access the object (or array of objects) pointed to by that pointer.
Your create_stack() is passed a pointer to a struct Stack, that is the s parameter. It then ignores the original value of s and reassigns it. That is allowed, but note that it does not change the original pointer in the caller of create_stack() because function parameters are passed by value.
There are two ways to do what you want.
The first way is to pass a pointer to a pointer:
_Bool create_stack(STACK *s){
*s = malloc(sizeof(struct Stack));
if(*s == NULL )
return 0;
(*s)->tos = 0;
return 1;
}
Call it e.g.:
STACK mystack;
_Bool ret;
ret = create_stack(&mystack);
if (!ret) {
/* error */
}
The second way is to not pass anything and return a pointer to the allocated stack:
STACK create_stack(void){
STACK s = malloc(sizeof(struct Stack));
if(s != NULL ) {
s->tos = 0;
}
return s;
}
Call it e.g.:
STACK s;
s = create_stack();
if (s == NULL) {
/* error */
}
Finally, as a point of programming style, do not typedef pointers in the way you have done. It is clearer if the pointer is explicit, for example, use typedef struct Stack STACK; instead of typedef struct Stack *STACK; and adjust the usage accordingly, for example, replacing STACK s with STACK *s and replacing STACK *s with STACK **s.
Function parameters are its local variables. That is the parameters hold copies of the passed arguments. To change an original argument in a function you have to pass it by reference through pointer.
So change the function like
_Bool create_stack(STACK *s){
*s = malloc(sizeof(struct Stack));
if(*s == NULL )
return 0;
( *s )->tos = 0;
return 1;
}
In order for a C function to modify an argument, the argument must be given as a pointer to the value to be changed. Thus, for a simple integer argument:
void Inc(int *value) {
++(*value);
}
will do the trick, but:
void Inc(int value) {
++value;
}
will do absolutely nothing to any argument given in a call to Inc, as the function just gets a copy of the 'value' given.
The same goes for a pointer! Your function just changes a copy of the pointer it is passed. So, you should change your function to take a pointer to the pointer:
_Bool create_stack(STACK *s){ // Pointer to a pointer to Stack
*s = malloc(sizeof(struct Stack)); // Change the value of the STACK object pointed to
if (*s == NULL )
return 0;
(*s)->tos = 0; // And, again, we need to (singly) dereference to 'double' pointer
return 1;
}
Then, in your calling code, where you originally have something like:
_Bool answer = create_stack(myStackPointer);
you would need to add the address of your pointer:
_Bool answer = create_stack(&myStackPointer);
Feel free to ask for further clarification and/or explanation.
I'm making a HashMap in C but am having trouble detecting when a Node has been initialized or not.
Excerpts from my code below:
static struct Node
{
void *key, *value;
struct Node *next;
};
struct Node **table;
int capacity = 4;
table = malloc(capacity * sizeof(struct Node));
// At this point I should have a pointer to an empty Node array of size 4.
if (table[0] != NULL)
{
// This passes
}
I don't see what I can do here. I've read tons of other posts of this nature and none of their solutions make any sense to me.
malloc does not initialize the memory allocated. You can use calloc to zero-initialize the memory.
// Not sizeof(struct Node)
// table = calloc(capacity, sizeof(struct Node));
table = calloc(capacity, sizeof(*table));
After that, it will make sense to use:
if (table[0] != NULL)
{
...
}
I suggest you consider something like a HashMapCollection type that you create with a set of functions to handle the various memory operations you need.
So you might have code something like the following. I have not tested this nor even compiled it however it is a starting place.
The FreeHashMapCollection() function below would process a HashMapCollection to free up what it contains before freeing up the management data structure. This may not be what you want to do so that is something for you to consider.
The idea of the following is to have a single pointer for the HashMapCollection struct and the array or list of HashMapNode structs immediately follows the management data so a single free() would free up everything at once.
typedef struct _TAGHashMapNode {
void *key, *value;
struct _TAGHashMapNode *next;
} HashMapNode;
typedef struct {
int iCapacity; // max number of items
int iSize; // current number of items
HashMapNode *table; // pointer to the HashMapNode table
} HashMapCollection;
Then have a function to allocate a HashMapCollection of a particular capacity initialized properly.
HashMapCollection *AllocateHashMapCollection (int iCapacity)
{
HashMapCollection *p = malloc (sizeof(HashMapCollection) + iCapacity * sizeof(HashMapNode));
if (p) {
p->table = (HashMapNode *)(p + 1);
p->iCapacity = iCapacity;
p->iSize = 0;
memset (p->table, 0, sizeof(HashMapNode) * iCapacity);
}
return p;
}
HashMapCollection *ReallocHashMapCollection (HashMapCollection *p, int iNewCapacity)
{
HashMapCollection *pNew = realloc (p, sizeof(HashMapCollection) + sizeof(HashMapNode) * iNewCapacity);
if (pNew) {
pNew->table = (HashMapNode *)(pNew + 1);
if (p == NULL) {
// if p is not NULL then pNew will have a copy of that.
// if p is NULL then this is basically a malloc() so initialize pNew data.
pNew->iCapacity = pNew->iSize = 0;
}
if (iNewCapacity > pNew->iCapacity) {
// added more memory so need to zero out that memory.
memset (pNew->table + iCapacity, 0, sizeof(HashMapNode) * (iNewCapacity - pNew->iCapacity));
}
pNew->iCapacity = iNewCapacity; // set our new current capacity
p = pNew; // lets return our new memory allocated.
}
return p; // return either old pointer if realloc() failed or new pointer
}
void FreeHashMapCollection (HashMapCollection *p)
{
// go through the list of HashMapNode items and free up each pair then
// free up the HashMapCollection itself.
for (iIndex = 0; iIndex < p->iCapacity; iIndex++) {
if (p->table[iIndex].key) free (p->table[iIndex].key);
if (p->table[iIndex].value) free (p->table[iIndex].value);
// WARNING ***
// if these next pointers are actually pointers inside the array of HashMapNode items
// then you would not do this free as it is unnecessary.
// this free is only necessary if next points to some memory area
// other than the HashMapNode table of HashMapCollection.
if (p->table[iIndex].next) free (p->table[iIndex].next);
// even though we are going to free this, init to NULL
p->table[iIndex].key = NULL;
p->table[iIndex].value = NULL;
p->table[iIndex].next = NULL;
}
free (p); // free up the memory of the HashMapCollection
}
I have been doing excercises from a book. And I am stuck on the meaning of this qustion. Assuming that you store integer values on the stac and that using a static array to store data provide a createStack() deleteStack(stack) methods.
My interpretation is
typedef struct {
int values;
char data[50];
} StackData;
typedef struct n {
StackData d; // store some data in node
struct n *successor; // store successor of node
// as typedef is not yet completed
// name StackNode cannot be used
} SatckNode;
typedef struct {
StackNode *head;
StackNode *current;
} Stacklist;
I know these arent the methods. But i want to know if I am going about it the right way
If you're using a static array for the values, then you don't technically need createStack() and deleteStack() functions, because you can just create a struct stack or whatever on the stack (pun intended) and you're done.
If you do want to, though, (and you might legitimately want to, e.g. to avoid having to explicitly initialize top, or to hide the implementation behind an opaque type, or to be able to return one from a function without copying a potentially large array) this'll do it:
#include <stdio.h>
#include <stdlib.h>
#define STACKSIZE 50
typedef struct stack * Stack;
struct stack {
size_t top;
int values[STACKSIZE];
};
Stack createStack(void)
{
Stack new_stack = malloc(sizeof *new_stack);
if ( !new_stack ) {
perror("couldn't allocate memory");
exit(EXIT_FAILURE);
}
new_stack->top = 0;
return new_stack;
}
void deleteStack(Stack stack)
{
free(stack);
}
void push(Stack stack, const int n)
{
if ( stack->top < STACKSIZE ) {
stack->values[stack->top++] = n;
}
else {
fprintf(stderr, "Stack full - exiting.\n");
exit(EXIT_FAILURE);
}
}
int pop(Stack stack)
{
if ( stack->top > 0 ) {
return stack->values[--stack->top];
}
else {
fprintf(stderr, "Stack empty - exiting.\n");
exit(EXIT_FAILURE);
}
}
int main(void)
{
Stack mystack = createStack();
push(mystack, 3);
push(mystack, 1);
push(mystack, 4);
push(mystack, 1);
push(mystack, 5);
for ( size_t i = 0; i < 5; ++i ) {
printf("Popped %d from stack.\n", pop(mystack));
}
deleteStack(mystack);
return 0;
}
Right now you seem to want a stack with values in a static array, but then you start defining structs for nodes and lists, as if you want a linked list implementation. The two implementations are obviously pretty different.
I think you're on the right way - just a couple of comments.
In Stacklist, I don't get why you have pointers to two of the nodes in the stack.
Usually, stacks only keep a reference to the item on the top of the stack.
In addition, they either keep a counter of how big is the stack, or a pointer to the node on the bottom of the stack (which is what you probably mean by head, and reference the head node by current?).
And don't forget to initialize everything whenever you create any of those structures :P usually ends up in endless hours of headache.
Keep up the good work.
I'm trying to implement a Queue in C (using a Linked List) to store pointers to data. The en-queuing seems to be working fine, but some trouble with pointers upon de-queuing.
In my main():
void* data = malloc(sizeof(int));
dequeue(&Q, data);
printf("(%d) %d\n", k, *(int*)data);
dequeue():
int dequeue(struct queue *q, void *value)
{
struct queue_node *tmp;
if (!q->first) {
value = 0;
return 1;
}
value = q->first->data;
tmp = q->first;
if (q->first == q->last)
q->first = q->last = NULL;
else
q->first = q->first->next;
free(tmp);
return 0;
}
Based on my debugging, it seems that the value of the *data pointer in the main() for loop doesn't retain the value that it's set to in dequeue(). What am I missing?
Edit:
struct queue_node
{
struct queue_node *next;
void* data;
};
struct queue
{
struct queue_node *first;
struct queue_node *last;
};
The queue_node's data holds a pointer to some value (here it is an int, but it may not be true always, otherwise you'd use an int instead...)
Since this value was allocated with malloc (and is not a local variable) you need to also free it at some point.
So, change the function's signature to accept a void**, don't allocate space for an int in main() but call dequeue with &data as a parameter, where void * data = 0. Don't forget to free data when done.
In dequeue, set *value = q->first->data.
You're setting the value of the "value" variable, which is a pointer local to the function.
If you want to set the value to which it points, use:
*value = 0;
and:
*value = q->first->data;
Edit (after question edit): Since queue_node.data is itself a pointer, it makes more sense to pass a void**, as #Andrei notes above.
Assuming data is a (void *) and you want the (int) value pointed to by data, you'll have to replace
value = q->first->data;
with
*(int *)value = *(int *)q->first->data;
in the function deque();
when I'm trying to push elements to a stack I get segmentation fault, but if I open address for stack(i marked them with "!!!") and it's symbols it accepts it. But this time in each push, it creates new address and doesn't increase top value.
typedef struct
{
struct table **symbols; // array of the stack
int top; //index of the top element
int size; //maximum size of the stack
}stack;
void push(stack *stck,struct table *element)
{
if(stck->top == stck->size)
{
printf("stack is full");
return;
}
stck = malloc(sizeof(stack)); !!!
stck->symbols = (struct table **)malloc(50 * sizeof(struct table*)); !!!
printf("top : %d\n",stck->top);
stck->top = stck->top++;
printf("%d"&stck->top);
stck->symbols[stck->top] = element;
printf("top : %d\n",stck->top);
}
You have to construct your stack before you can push anything onto it. Eg. create function stack_new that will allocate memory for your stack and initialize its members:
stack * stack_new (size_t size)
{
stack * stck = malloc(sizeof(stack));
stck->top = -1;
stck->size = size
stck->symbols = (struct table **)malloc(size * sizeof(struct table*));
return stck;
}
Now, once you properly constructed your stack with above function, you may pass it to push function.
You are passing one stack in a variable called stck, but then allocating a new structure and assigning it to the same pointer. So the stack you pass in is never modified. I don't think you need the first malloc call.
Before you ever call push, you are going to want to malloc space for the stack.
With the !!! lines, you are allocating new memory with each push, which is wrong.
Without the !!! lines, you are never allocating the memory
If you pass a single pointer stack *stck and then malloc inside the function, it will not reflect once you get out the function.
Also, why do you need to allocate memory for table for 50 pointers each time you want to push?
Do it like below:
struct table
{
//members go here
};
typedef struct
{
struct table **symbols;
int top;
int size;
}stack;
struct table *get_elem(void)
{
//logic for getting elements go here
}
void stack_push(stack *stck, struct table *element)
{
if(stck->top==stck->size)
{
printf("Stack Full\n");
return;
}
stck->top++;
stck->symbols[stck->top] = element;
return;
}
void stack_func()
{
struct table *elem = NULL;
stack *stck = (stack *)malloc(sizeof(stack));
if(NULL==stck)
{
return;
}
stck->top = -1;
stck->symbols = (struct table **)malloc(50 * sizeof(struct table *));
if(NULL == stck->symbols)
{
free(stck);
return;
}
stck->size = 49;
elem = get_elem();
//do check here for correctness of elem returned from get_elem
stack_push(stck, elem);
return;
}
Hope this helps! : )