I'm trying to implement generic stack in C, but I can't print value that I pushed. Here is the code
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <memory.h>
typedef struct{
void *elems;
int sizeOfElems;
int allocated;
int lenght;
}stack;
void allocate_stack(stack *s, int sizeOfElements){
assert(sizeOfElements > 0);
s->sizeOfElems = sizeOfElements;
s->allocated = 2;
s->lenght = 2;
s->elems = malloc(sizeOfElements * s->allocated);
}
void deallocate_stack(stack *s){
free(s->elems);
}
void push_elem(stack *s, void *elem){
s->lenght += 1;
if(s->allocated == s->lenght){
realloc(s, s->lenght * s->sizeOfElems);
s->lenght *= 2;
}
void *target = (char *)s->elems + s->lenght * s->sizeOfElems;
memcpy(target, elem, s->sizeOfElems);
}
void pop_elem(stack *s, void *elemAddr){
void *source = (char *)s->elems + (s->lenght-1) * s->sizeOfElems;
memcpy(elemAddr, source, s->sizeOfElems);
s->lenght -=1;
}
int main(){
stack s;
allocate_stack(&s, 1);
char a = 'a';
push_elem(&s, &a);
char *elem = NULL;
pop_elem(&s, elem);
printf("%s", elem);
deallocate_stack(&s);
return 0;
}
The problem is that I don't get anything when I run the program, just press return to close the window. I'm programming on Linux using GCC toolkit.
You are missing the allocation of your stack struct. When you do allocate_stack you must call allocate to create a stack object before assigning things to it. For instance the s you pass in is null and you start trying to assign values to the various fields of it. This is undefined behavior and likely the reason your program isn't working.
Try changing the signature of your allocate_stack function to return a stack pointer and then the first step should be to malloc(sizeof struct stack) . You should return the pointer you got from the malloc at the and and assign it to s.
Edit: unless you want the stack to be on the stack in which case allocate it like you would a normal variable.
In your push_elem:
s->lenght += 1;
if(s->allocated == s->lenght){
realloc(s, s->lenght * s->sizeOfElems);
s->lenght *= 2;
}
It seems like you are trying to re-allocate space if you run out, but your default value of 2 for allocated is going to stay as it is, you should probably do something like:
if (s->allocated < s->lenght) {
realloc(s->elems, ....)
//Increase both allocated and length to represent the current state of the stack
}
Notice that in the realloc() call you are passing s, which is in the stack, this won't do what you want:
http://pubs.opengroup.org/onlinepubs/7908799/xsh/realloc.html
As per your structure you should be passing
s->elems
Also, before calling pop_elem, you are assigning NULL to elem. Inside your pop_elem, this is where you are trying to do a memcpy() to. To do this you will have to allocate memory:http://pubs.opengroup.org/onlinepubs/009695399/functions/memcpy.html
Related
I was trying to write a stack in C, but i had some problems regarding realloc. Finally i managed to write a working program but i don't get why does it work and why i have to give on the input of my functions put_on_fun_stack and get_from_fun_stack a pointer to my table of structures.
When i tried to give it like put_on_fun_stack(stack_t *s, ...) it didin't work. Why do i have to put pointer in realloc and why do i have to write a (*s)[*l], and i can't write *s[*l]. Can somebody please explain the pointers to structures?
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
typedef struct {
int *n;
char *name;
}stack_t;
void init(stack_t **s){
*s=malloc(0);
}
void put_on_fun_stack(stack_t **s, char *name, int *l, int n){
*s = realloc(*s, (*l+1) * sizeof(stack_t));
(*s)[*l].name = name; //why do i need (*s) ?
(*s)[*l].n = n;
*l=*l+1;
}
char* get_from_fun_stack(stack_t **s, int *l){
char *temp = (*s)[*l-1].name;
*s = realloc(*s, (*l - 2) * sizeof(stack_t));
*l=*l-2;
return temp;
}
void rm(stack_t *s){
free(s);
}
int main(int argc, char **argv){
char *name;
stack_t* s;
init(&s);
int i;
int l=0;
srand(time(0));
if (argc>1)
for(i=1;i<argc;i++){
printf("%s\n", argv[i]);
put_on_fun_stack(&s, argv[i], &l, rand()%10);
printf("name=%s, n=%d, l=%d \n", s[l-1].name,s[l-1].n, l-1);
}
rm(s);
return 0;
}
C is pass by value so when you call put_on_fun_stack() and you just pass s you have a copy of main's value of s and not the address of s. You can't change the value of s that's in main. In other words, when you had it coded as s = realloc(s, (*l - 2) * sizeof(stack_t)); you're only changing the value of s in put_on_fun_stack() and it doesn't affect the s from main.
You fixed that by passing the address of s in main to put_on_fun_stack() and so as coded *s = realloc(*s, (*l - 2) * sizeof(stack_t)); the value of s in main gets set as you need it to.
As for (*s)[*l] vs *s[*l], it's a matter of operator precedence. [] binds tighter than * so *s[*l] is the same as *(s[*l]). Not what you want.
If your question is, why does (*s)[*l] work you have to look at what s is. s is a stack_t **, (*s) then is a stack_t * and (*s)[*l] then is the *lth element of the array pointed to by (*s).
Looking at why the other one doesn't work, (s[*l]) is the *lth element of an array of stack_t * and then *s(*l]) is the 0th element of the *lth stack_t *. It will only work when *l is 0.
It would be confusing but you can avoid the () by coding it as s[0][*l]. A cleaner way to clean it up is to dereference s and save it in a local variable, sort of like this:
void put_on_fun_stack(stack_t **ps, char *name, int *pl, int n){
stack_t *s;
int l=*pl;
s = realloc(*ps, (l+1) * sizeof(stack_t));
s[l].name = name;
s[l].n = n;
// return the updated values
*pl=l+1;
*ps=s;
}
So when I pass a data type like a struct to assign some memory to it I find that the pointer doesn't change within the main scope. This further becomes a problem when I try to free the memory but obviously if its using the original pointer it will be pointing at the stack address.
void allocate(int *value){
value = malloc(10 * sizeof(int));
}
int main(){
int val2;
allocate(&val2);
free(&val2);
return 0;
}
I can fix this by using a double pointer to be passed into the allocate function but some course work I'm doing requires to only pass a pointer and I cant get it to update the pointer when it returns to main. I have looked around for a while but cant find a straight forward answer, I feel like my coursework is wrong but that might be my lack of understanding.
The requirement to "only pass a pointer" seems contrived, and you could argue that a pointer to pointer (not a "double pointer") is a pointer, but perhaps you could use void * to punch a hole in the type system. Or use a struct:
#include <stdlib.h>
#include <stdio.h>
struct intbuffer {
int *d;
size_t cap;
};
void *
xmalloc(size_t s)
{
void *r = malloc(s);
if( r == NULL ){
perror("malloc");
exit(1);
}
return r;
}
void
allocate(void *p, size_t s)
{
*(int **)p = xmalloc(s * sizeof(int));
}
void
allocate2(struct intbuffer *p)
{
p->d = xmalloc(p->cap * sizeof *p->d);
}
int
main(void)
{
int *val2;
struct intbuffer v;
allocate(&val2, 10);
free(val2);
v.cap = 10; /* Horrible api!! */
allocate2(&v);
free(v.d);
return 0;
}
Note that setting the capacity in the struct prior to making the call to allocate is a violation of many principles of software design, but this whole thing is absurdly contrived due to the bizarre artificial limitations.
There are not enough *'s in each place, but you will have to figure out what that means.
void allocate(int** value){
*value = malloc(10 * sizeof(int));
}
int main(){
int* val2;
allocate(&val2);
free(val2);
return 0;
}
I am experiencing a problem in shrinking the size of a stack in a personal implementation of the data structure.
I suppose is due to bad usage of realloc(). When the execution comes it (spop(), empty()) (If I remove the realloc and decrement the number of elements, the implementation works fine), the program just ends (crash).
What would be a better way to use the function in my implementation, or what might the problem be?
stack.h
/*Stack.h*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stddef.h>
typedef struct Stack{
char **storage; //Elements container;
size_t capacity; //Total amount of elements POSSIBLE in the stack;
size_t size; //Total amount of elements within the stack;
}Stack;
Stack *salloc(size_t);
void spush(Stack *, char *);
char *spop(Stack *);
void speek(Stack *);
void empty(Stack *);
void print_stack(Stack *); //Useful but non-conventional
stack.c
/*Stack.c*/
#include "stack.h"
Stack *salloc(size_t size){
Stack *s = (Stack *)malloc(sizeof(s));
s->storage = (char **)malloc(sizeof(char *) * size);
s->capacity = size;
s->size = 0;
}
static int expand_stack(Stack *s){
s->storage = realloc(s->storage, (s->capacity * 2));
}
static void shrink_stack(Stack *s){
s->storage = realloc(s->storage, (s->capacity / sizeof(char *)));
}
void spush(Stack *s, char *elem){
char *p = elem;
int k = (s->capacity-1) - s->size; //Next free position
if(s->size == s->capacity)
expand_stack(s);
s->storage[k] = (char *)malloc(sizeof(char) * (strlen(p) + 1));
memcpy(s->storage[k], p, (strlen(p) + 1));
// *(s->storage[k] + (strlen(p) + 1)) = '\0';
s->size++;
}
char *spop(Stack *s){
int k = s->capacity - s->size;
if(s->size == 0)
return NULL;
free(s->storage[k]);
s->size--;
shrink_stack(s);
}
void speek(Stack *s){
int k = s->capacity - s->size;
printf("'%s'\n", s->storage[k]);
}
void empty(Stack *s){
s->storage = realloc(s->storage, 0);
s->capacity = 0;
s->size = 0;
}
void print_stack(Stack *s){
printf("[STACK] = {\n");
int k = s->capacity - s->size;
for(int i = k; i <= s->capacity-1; i++)
printf(" '%s'\n", s->storage[i]);
printf("}\n");
}
main.c
#include "stack.h"
#define COM1 "echo"
#define COM2 "start"
#define COM3 "sort"
int main(){
Stack *s = salloc(5);
spush(s, COM1);
spush(s, COM2);
spush(s, COM3);
// speek(s);
print_stack(s); //Full Stack
spop(s);
print_stack(s);
spush(s, "cd");
print_stack(s);
empty(s);
print_stack(s);
}
Stack *salloc(size_t size){
Stack *s = (Stack *)malloc(sizeof(s));
s->storage = (char **)malloc(sizeof(char *) * size);
s->capacity = size;
s->size = 0;
}
Your first malloc call only allocates enough space for a Stack*, not enough space for the actual Stack structure. You want:
Stack *s = (Stack *)malloc(sizeof(*s));
or
Stack *s = (Stack *)malloc(sizeof(Stack));
There are quite a few issues in your code:
salloc is missing return s.
spop does not return anything (except for the NULL case).
salloc is not allocating enough memory for a Stack object (sizeof(s) is the size of the pointer, not the Stack object).
In all the calls in the form: s->storage = realloc(...) - the result from realloc (void*) should be cast to char**.
expand_stack is defined to return an int but nothing is actually returned. Should probably be changed to return void.
shrink_stack is not calculating the size properly. As a result in your case realloc can actually allocate a 0 size memory (Note:: this is a cause for an access violation exception in print_stack after calling spop). I suggest you use a debugger to catch this bug.
There's a lot of problems here. Both in design and in implementation, but all lessons worth learning.
Here are a summary of the changes:
salloc - We should store the initial capacity. empty was just freeing all storage which would make the stack unusable. By storing initial capacity, shrink_stack can avoid shrinking below that.
expand_stack - capacity must be modified after the expansion or we lose track of what the actual allocation is. Also, we wouldn't be able to add beyond the initial capacity without running into problems. Going by the int return, I suspect you intended to return the new capacity (which should be size_t.
shrink_stack should not just keep dividing the capacity, or eventually we hit zero. So using the initial_capacity we keep things no smaller than at the outset. It also needs to only shrink if the size has dropped to the point where there is value doing so.
spush - I don't know why you chose to allocate from the end of the storage but this fundamentally would break when the capacity increased and expansion occurred. Much simpler to add according to size, and pop off from size back towards zero. Note that const is added or some compilers will complain about passing a non-const pointer to a string literal, which is dangerous.
spop - As per spush, pop from size - 1 back towards zero. The other bug here was that the string is stored in a malloc'd buffer, so we should be freeing that, and that means we can't just return the pointer, but need the spop signature to provide a buffer and max size in which to put it. Given that we are dealing with null terminated strings, this can be an strncpy. Note that the return value is the passed address, or NULL if there is no element to pop. There are other ways to perhaps handle this that help remove the risk of elem == NULL etc.
speek - Again, just use size - 1
empty - Uses spop to remove all elements without discarding the initial capacity storage.
print_stack - From zero to size.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stddef.h>
typedef struct Stack{
char **storage; //Elements container;
size_t capacity; //Total amount of elements POSSIBLE in the stack;
size_t size; //Total amount of elements within the stack;
size_t initial_capacity;
}Stack;
Stack *salloc(size_t size){
Stack *s = (Stack *)malloc(sizeof(s));
s->storage = (char **)malloc(sizeof(char *) * size);
s->capacity = s->initial_capacity = size;
s->size = 0;
return s;
}
static int expand_stack(Stack *s){
s->storage = (char **)realloc(s->storage, (sizeof(char *) * s->capacity * 2));
s->capacity = s->capacity * 2;
return s->capacity;
}
static void shrink_stack(Stack *s){
if (s->capacity > s->initial_capacity && s->size < s->capacity / 2) {
s->storage = (char **)realloc(s->storage, (sizeof(char *) * (s->capacity / 2)));
s->capacity = s->capacity / 2;
}
}
void spush(Stack *s, char const * elem){
if(s->size == s->capacity)
expand_stack(s);
size_t size = strlen(elem) + 1;
s->storage[s->size] = (char *)malloc(sizeof(char) * size);
memcpy(s->storage[s->size], elem, size);
s->size++;
}
char *spop(Stack *s, char * elem, size_t size){
if(s->size == 0)
return NULL;
if (size > 0) {
strncpy(elem, s->storage[s->size - 1], size);
}
free(s->storage[s->size - 1]);
s->storage[s->size - 1] = NULL;
s->size--;
shrink_stack(s);
return elem;
}
void speek(Stack *s){
printf("'%s'\n", s->storage[s->size - 1]);
}
void empty(Stack *s){
char notused;
while (spop(s, ¬used, 0) != NULL);
}
void print_stack(Stack *s){
printf("[STACK] = {\n");
for(int i = 0; i < s->size; i++)
printf(" '%s'\n", s->storage[i]);
printf("}\n");
}
#define COM1 "echo"
#define COM2 "start"
#define COM3 "sort"
int main(){
Stack *s = salloc(5);
spush(s, COM1);
spush(s, COM2);
spush(s, COM3);
// speek(s);
print_stack(s); //Full Stack
char string[64];
spop(s, string, sizeof(string)/sizeof(string[0]));
print_stack(s);
spush(s, "cd");
print_stack(s);
empty(s);
print_stack(s);
}
I'm working on a stack ADT and I'm trying to execute the stack_push (pushing an item on top of a stack). Note, instead of a stack with integers, I'm working with strings. This is what I have:
char *strdup(const char *s) {
char *new = malloc((strlen(s) + 1) * sizeof(char));
strcpy(new, s);
return new;
}
void stack_push(const char *str, struct stack *s) {
assert(s);
assert(str);
char *copied_str = strdup(str);
if (s->len == s->maxlen) {
s->maxlen *= 2;
s->data = realloc(s->data, (sizeof(s->data) +
((strlen(str) + 1) * sizeof(char))));
}
strcpy(s->data[s->len], copied_str);
s->len += 1;
}
Also, my stack implementation is simply:
struct stack {
char **data;
int len;
int maxlen;
};
When I run this, my strcpy function (the third to last line of stack_push) is giving me a memory error, specifically segmentation-fault-on-null-address, and I have no idea why this is happening. I already have the string ADT included in my code so functions like strlen, strcmp, and even strcpy, should be in here already.
Can anyone help me figure out my problem?
The size passed to your realloc call is incorrect. Since you want to be able to store maxlen strings in s->data, the size calculation should make use of that variable. Specifically, the size to allocate should be sizeof(*s->data) * s->maxlen
This question already has answers here:
How do I modify a pointer that has been passed into a function in C?
(7 answers)
Closed 8 years ago.
I want to make a function in C that would dynamically allocate memory for a pointer in parameter of the function.
#include <stdio.h>
#include <stdlib.h>
int allocate(char * arr, int size){
int code = -1;
arr = malloc(size);
if(arr != NULL) code = size;
return code;
}
void main(){
char * array;
if(allocate(array,4) != -1){
printf("allocated!\n");
if(array == NULL) printf("Oops it actually didn't allocate!\n");
}
}
When I execute the program; it will only display "allocated!" and "Oops it actually didn't allocate!". That means the memory allocation did happen (because the return code of the function is not -1. But then when I check if array is equal to NULL; it actually is!
This is a programming problem that I've had and sadly in some cases I can't use a workaround like this char * allocate(char * arr, int size); and assigning the return value to char * array.
You lack a level of indirection, you need char**.
Excuse the bad formatting, I write from my phone.
Char* array, array is bound to a memory slot (that will contain a value that points to another memory slot that would be interpreted as a char).
So you copy that value to the function and modify that value locally in allocate, but the modification never reaches the outside scope.
#include <stdio.h>
#include <stdlib.h>
int allocate(char ** arr, int size){
int code = -1;
*arr = malloc(size);
if(*arr != NULL) code = size;
return code;
}
void main(){
char * array;
if(allocate(&array,4) != -1){
printf("allocated!\n");
if(array == NULL) printf("Oops it actually didn't allocate!\n");
}
}
Not done C in something like 10 years but it should be OK.
You can allocate memory inside your function and return the address as shown below
There are also changes like instead of void main it should be int main()
#include <stdio.h>
#include <stdlib.h>
char *allocate( int size){
char *arr;
arr = malloc(size);
return arr;
}
int main(){
char * array;
if((array = allocate(4)) != NULL){
printf("allocated!\n");
}
return 0;
}
Arguments to functions in C are passed by value. This means following function has no sense:
void f(int x) {
x = 1;
}
int y = 0;
f(y);
// y is still 0
When f is invoked, y is copied to x. Any change to x changes that copy and won't affect y. To work around this, you need to either use return value or pass a pointer to y:
void f(int* x) {
*x = 1;
}
int y = 0;
f(&y);
// y is now 1
Here x is still a copy (of a pointer) but it points to y. Changes to x wont be visible outside that function. But changing *x modifies y.
The same rules apply to pointer arguments. You just need one more * for arguments you want to modify:
int allocate(char** arr, int size) {
*arr = malloc(size);
}
char *ptr;
allocate(&ptr);
Also note that checking array for NULL isn't sufficient here, because a locally defined variable could contain garbage value (thus, not being NULL). You have to assign NULL to it before the allocation:
char *array = NULL;