Shrinking a stack in personal implementation crashes when using realloc - c

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, &notused, 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);
}

Related

Use realloc() in function

#include <stdio.h>
#include <stdlib.h>
void Increase(int *array1,int *Nums) {
int*array2 = realloc(array1,(*Nums+1)*sizeof(int));
array2[*Nums] = 13;
array2[*Nums-1] = 14;
++(*Nums);
}
int main() {
int NumOfElements=0,i;
int*array=(int*)malloc(0*sizeof(int));
Increase(array,&NumOfElements);
for(i=0;i<NumOfElements;i++) {
printf("%d ", array[i]);
}
free(array);
}
How many elements will be in the array in main() if I run this program?
Does the Increase() function increase the number of memory cells of the array in main(), or will the array in main() still just have 0 memory cells?
From the realloc manual page:
The realloc() function returns a pointer to the newly allocated
memory, which is suitably aligned for any kind of variable and may be
different from ptr, or NULL if the request fails.
... so the answer to your question will depend on whether the call to realloc() was able to change the memory-allocation's size in-place, or not.
If realloc() was able to do an in-place resize (e.g. because the heap had allocated a larger-than-necessary array for the original malloc() call, allowing realloc() to simply mark some of the extra bytes in the buffer as in-use), then realloc() would return the same pointer that was passed in to it as an argument, which is the same memory-location that main() points to via array. In this scenario, main() could access the now-larger-array via array without any problems.
On the other hand, if realloc() wasn't able to do an in-place resize, then realloc() would be forced to allocate a newer/larger array, copy over the contents of the old array, free() the old array, and return the pointer to the larger array. In that case, array2 would point to a different location in memory than array and array1, and (worse), after Increase() returns, main() would invoke undefined behavior by dereferencing array, which is (at that point) a dangling pointer because realloc() freed the memory it used to point to.
I think one is intending to implement a common container known a dynamic array for use in a stack (or similar structure.)
#include <stddef.h>
struct int_stack { int *data; size_t size, capacity; };
struct int_stack int_stack(void);
void int_stack_(struct int_stack *);
int *int_stack_new(struct int_stack *);
This is what I'd use as int_stack.h. Notice that it's logical size and it's capacity are not necessarily the same, but size <= capacity.
#include "int_stack.h"
#include <stdlib.h>
#include <errno.h>
/** Initialises `s` to idle. */
struct int_stack int_stack(void) {
struct int_stack s;
s.data = 0;
s.capacity = s.size = 0;
return s;
}
/** Destroys `s`; returns it idle. */
void int_stack_(struct int_stack *const s) {
free(s->data);
*s = int_stack();
}
/** Ensures `min_capacity` of `s`. Returns success, otherwise, `errno` will be
set. */
static int int_stack_reserve(struct int_stack *const s, const size_t min) {
size_t c0;
int *data;
const size_t max_size = (size_t)-1 / sizeof *s->data, min_size = 3;
if(s->data) {
if(min <= s->capacity) return 1;
c0 = s->capacity < min_size ? min_size : s->capacity;
} else { /* Idle. */
if(!min) return 1;
c0 = min_size;
}
if(min > max_size) return errno = ERANGE, 0;
/* `c_n = a1.625^n`, approximation golden ratio `\phi ~ 1.618`. */
while(c0 < min) {
size_t c1 = c0 + (c0 >> 1) + (c0 >> 3);
if(c0 > c1) { c0 = max_size; break; }
c0 = c1;
}
if(!(data = realloc(s->data, sizeof *s->data * c0)))
{ if(!errno) errno = ERANGE; return 0; }
s->data = data, s->capacity = c0;
return 1;
}
/** Increases the capacity of `s` to at least `n` elements beyond the size.
Returns the start of the buffered space at the back of the array or null and
`errno`. */
static int *int_stack_buffer(struct int_stack *const s, const size_t n) {
if(s->size > (size_t)-1 - n) { errno = ERANGE; return 0; } /* Unlikely. */
return int_stack_reserve(s, s->size + n) && s->data ? s->data + s->size : 0;
}
/** Adds `n` elements to the back of `s` and returns a pointer to the elements.
Null indicates an error and `errno` will be set. */
static int *int_stack_append(struct int_stack *const s, const size_t n) {
int *buffer;
if(!(buffer = int_stack_buffer(s, n))) return 0;
return s->size += n, buffer;
}
/** Adds one new element of `s` and returns it as an uninitialized pointer or
null and `errno`. */
int *int_stack_new(struct int_stack *const s) { return int_stack_append(s, 1); }
This is an example of what I'd use as the implementation int_stack.c. The function int_stack_reserve is where the realloc is called once the size reaches the capacity. A temporary data is assigned the realloc; this is checked for error, then assigned into s->data. Reserving a geometrically increasing capacity will avoid the cost of expanding each time. Thus, the array will have amortized cost of O(n) to insert n elements.
#include <stdio.h>
#include <stdlib.h>
#include "int_stack.h"
int main(void) {
int status = EXIT_SUCCESS;
int *e1, *e2;
struct int_stack stack = int_stack();
if(!(e1 = int_stack_new(&stack)) || !(e2 = int_stack_new(&stack))) {
status = EXIT_FAILURE;
perror("stack");
} else {
*e1 = 13;
*e2 = 14;
for(size_t i=0; i<stack.size; i++) {
printf("%d ", stack.data[i]);
}
fputc('\n', stdout);
}
int_stack_(&stack);
return status;
}
Instead of a fixed-size, we now have unlimited size, but one has to check for out-of-memory condition.

how to use malloc () in Double Pointer in Structure in C

I have structs:
typedef struct accont
{
char **tel;//list of tel
char **email;//list of emails
}acc;
and
typedef struct _strcol
{
int count; //total of accounts
acc **list;
} strcol ;
I access the structure with a pointer:
strcol index;
contato *p;
p = (index.list + index.count);
the question, how i use malloc() in this function?
i try:
(*p)->tel = (char **) malloc(i * sizeof (char*))
p.tel = (char **) malloc(i * sizeof (char*))
&(*p)->tel = (char **) malloc(i * sizeof (char*))
and then as I do the second malloc to save data email or tel
my first post, excuse anything
So this:
(*p)->tel = (char **) malloc(i * sizeof (char*))
allocates space to store i pointers to char - so you can have i telephone number strings. But you don't actually have any space allocated to store those telephone number strings themselves yet. To do that, you need (for the first telephone number):
(*p)->tel[0] = malloc(j);
If this call to malloc() succeeds, you can now store nul-terminated string of length j-1 in the space pointed to by (*p)->tel[0]. You can then do the same for the other pointers in (*p)->tel up to (*p)->tel[i-1].
Using malloc() is simple if code follows:
some_type *p;
p = malloc(number_of_elements * sizeof *p);
if (p == NULL) Handle_OutOfMemory();
So with p.tel,
// p.tel = (char **) malloc(i * sizeof (char*));
p.tel = malloc(i * sizeof *(p.tel));
if (p.tel == NULL) exit(EXIT_FAILURE);
I'm going to assume 'p' is acc *p; (i have no idea what 'contato' is).
Anyway ... the point is to show how memory can be allocated & tel/email data stored/accessed ... Also copied tel #/email id simply to demonstrate ...
Regarding casting void pointer returns from malloc, I've seen arguments for/against ... i cast (malloc's about the only case where i cast).
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct accont
{
char **tel; //list of tel
char **email; //list of emails
}acc;
typedef struct _strcol
{
int count; //total of accounts
acc **list;
}strcol;
int main()
{
int iNumAccounts = 5; // Assume there are 5 Accounts.
int iNumTels = 2; // Each Account has 2 Tel #s.
int iNumEmails = 3; // Each Account has 3 Email ids.
strcol index;
acc *p = NULL;
index.list = (acc **)malloc(5 * sizeof(acc *)); // Master list
// of 'acc' pointers i.e. pointer to a set of pointers.
int i, j;
for(i=0; i<iNumAccounts; i++) // Go through the 5 Accounts, one at
// a time ... and allocate & store tel #s/email ids.
{
index.list[i] = (acc *)malloc(sizeof(acc));
p = index.list[i];
p->tel = (char **)malloc(iNumTels * sizeof(char*));
for(j=0; j<iNumTels; j++)
{
p->tel[iNumTels] = (char *)malloc(11 * sizeof (char)); // 10 digit tel # + 1 byte for '\0' ...
strcpy(p->tel[iNumTels], "1234567890");
}
p->email = (char **)malloc(iNumEmails * sizeof(char*));
for(j=0; j<iNumEmails; j++)
{
p->email[iNumEmails] = (char *)malloc(51 * sizeof(char)); // 50 char long email id + 1 byte for '\0' ...
strcpy(p->email[iNumEmails], "kingkong#ihop.yum");
}
}
for(i=0; i<iNumAccounts; i++) // Go through the 5 Accounts, one at a time ... and display.
{
p = index.list[i];
for(j=0; j<iNumTels; j++)
{
printf("Tel # is: %d\n", p->tel[iNumTels]);
}
for(j=0; j<iNumEmails; j++)
{
printf("Email id is: %s\n", p->email[iNumEmails]);
}
printf("----------\n");
}
}
If I've understood the case correct, a stack implementation will be best suited in this case. You can use the standard stack library header (of gcc) or create your own stack implementation suited for your own need.
An example may be something like the code below but you'd better follow the Jerry Cain's videos about the stack procedures (you'll find these videos on youtube: Stanford - Programming Paradigms videos. Stack session should be between video number 6 to 8). link from here
note: be careful! Killing stack elements (via StackPop) will not kill the char strings created by strdup. You'll need to free them individually. These are explained in the videos but I don't exactly remember how (again, you'd find some valuable info in those videos for your case).
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
typedef struct {
char *tel;
char *email;
} account;
typedef struct {
int *ptrElement; // starting address of the stack
int sizeAllocat; // total size allocated
int sizeCurrent; // current size
int sizeElement; // byte length of the stack element
} Stack;
// create a new stack pointer
void StackNew (Stack *s, int sizeElement) {
assert (s->ptrElement > 0);
s->sizeElement = sizeElement;
s->sizeCurrent = 0;
s->sizeAllocat = 4;
s->ptrElement = malloc (4 * sizeElement);
assert (s->ptrElement != NULL);
}
// kills a stack pointer
void StackDispose (Stack *s) {
free (s->ptrElement);
}
// expands stack space
static void StackGrow (Stack *s) {
s->sizeAllocat *= 2;
s->ptrElement = realloc (s->ptrElement, s->sizeAllocat * s->sizeElement);
}
// insert new stack pointer (of type account for example)
void StackPush (Stack *s, void *ptrElement) {
if (s->sizeCurrent == s->sizeAllocat) {
StackGrow (s);
}
void *target = (char *) s->ptrElement + s->sizeCurrent * s->sizeElement;
memcpy (target, ptrElement, s->sizeElement);
s->sizeCurrent++;
}
// pops (deletes) an element from stack
void StackPop (Stack *s, void *ptrElement) {
void *source = (char *) s->ptrElement +
(s->sizeCurrent - 1) * s->sizeElement;
memcpy (ptrElement, source, s->sizeElement);
s->sizeCurrent--;
}
// relocate stack element
void StackRotate (void *first, void *middle, void *after) {
int foreSize = (char *) middle - (char *) first;
int backSize = (char *) after - (char *) middle;
char tmp [foreSize];
memcpy (tmp, first, foreSize);
memmove (first, middle, backSize);
memcpy ((char *) after - foreSize, tmp, foreSize);
}
int main () {
Stack s;
account *acc;
StackNew (&s, sizeof (acc));
// your code here
// example
// acc->tel = strdup("some number");
// acc->email = strdup("some text");
// StackPush(&s, &acc);
...
// StackPop(&s, &acc);
...
...
StackDispose (&s);
return 0;
}

Generic stack don't push or pop value

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

Generic stack in C using void pointer not working for strings

I am trying to implement a generic stack in C using void pointers. This is not anything big, just for fun and learning. It is working with int and float as expected. But the problem I am facing is with char *, i.e. strings. It is not copying the address of the string instead trying to copy the actual string upto 4 bytes(as in my system pointer size is 4 bytes).
How to tell C to copy address of the string not the actual string, if possible, with out breaking the functionality of int and float already working?
My implementation so far is as follows,
typedef struct{
int top;
void *data;
int capacity;
size_t ele_size;
}stack_t;
int stack_init(stack_t *s, int capacity, size_t ele_size)
{
/* Initializes the stack with the given capacity
* #param s: Pointer to stack_t type variable
* #param capacity: capacity of the stack to be created
* Returns : Zero if succesful in allocating memory to the stack,
* -1 Otherwise
*/
s->top = -1;
s->capacity = capacity;
s->ele_size = ele_size;
s->data = calloc(s->capacity, s->ele_size);
if (s-> data != NULL || s->capacity == 0) {
return 0;
} else {
return -1;
}
}
int stack_push(stack_t *s, void *x)
{
/* Pushes an element on to the stack
* #param s: Pointer to stack_t type variable
* #param x: Value to Push on to the stack
* Returns : Zero if stack is not full when stack_push() is called,
* -1 Otherwise
*/
if (stack_len(s) capacity) {
s->top++;
memcpy(s->data + s->ele_size * s->top, x, s->ele_size);
return 0;
} else {
return -1;
}
}
int stack_pop(stack_t *s, void *value)
{
/* Value that is popped from the stack is placed in value parameter,
* #param s: Pointer to stack_t type variable
* #param x: Pointer to a variable to store the value popped from the
stack
* Returns: Zero if stack is not empty when stack_pop() is called,
* -1 Otherwise
*/
if (stack_len(s) > 0) {
memcpy(value, s->data + s->ele_size * s->top, s->ele_size);
s->top--;
return 0;
} else {
return -1;
}
}
For complete implementation of stack please refer here
Usage of the above stack is as follows:
Actually there is lot of unrelated stuff like using pseudo random number generator to
insert random numbers into stack.
#include"../src/stack.h"
START_TEST(int_push_pop)
{
stack_t s;
int n = random() % 60267;
int *a = calloc(n, sizeof (int));
ck_assert_int_eq(stack_init(&s, n, sizeof (int)), 0);
int i;
for (i = 0; i = 0; i--) {
int value;
int x = stack_pop(&s, &value);
ck_assert_int_eq(x, 0);
ck_assert_int_eq(value, a[i]);
x = stack_len(&s);
ck_assert_int_eq(x, i);
}
stack_clear(&s);
stack_destroy(&s);
}
END_TEST
START_TEST(float_push_pop)
{
/* similar to int_push_pop, so ignored here. */
}
END_TEST
START_TEST(string_push_pop)
{
stack_t s;
char *str = "stack overflow";
stack_push(&s, str);
char **popval = malloc(sizeof(char *));
stack_pop(&s, popval);
printf("%s\n", popval);
stack_destroy(&s);
}
END_TEST
Suite* stack_suite()
{
Suite *s = suite_create("Stack");
TCase *tc_int = tcase_create("int");
/* Stack int data type Test Case*/
TCase *tc_float = tcase_create("float");
/* Stack float data type Test Case*/
tcase_add_test(tc_int, int_push_pop);
tcase_add_test(tc_float, float_push_pop);
suite_add_tcase(s, tc_int);
suite_add_tcase(s, tc_float);
return s;
}
int main()
{
int number_failed;
Suite *s = stack_suite();
SRunner *sr = srunner_create(s);
srunner_run_all(sr, CK_NORMAL);
number_failed = srunner_ntests_failed(sr);
srunner_free(sr);
return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
}
Since stack_push() and stack_pop() functions are taking a void* pointer, you will need to pass a pointer to the character array(string) that needs to be pushed and not the char array itself. e.g. if you declare your string as
char str[] = "hello world";
you will have to call the function as
stack_push(s,&str);

realloc doesn't work in function

int *f, *l;
int main(){
int *a;
a = calloc(1, sizeof(int));
f = l = a;
put(&a, 1);
put(&a, 3);
put(&a, 2);
_getch();
return 0;
}
void put(int **a, int d){
printf("--%d--", sizeof(*a)); //always == 4
void *tmp = (int *)realloc(*a, sizeof(*a) + sizeof(int));
if (temp) //allocated succesfully
*a = temp;
else
printf("Allocating a failed");
l++;
}
I trying to create a queue model based on int pointers.
I've corrected the sample a bit. But it still failed.
Could you please help?
a is an int pointer (int*), therefore its size if 4 bytes (on your machine) you should keep track of the size of allocated memory.
For example:
int *f, *l;
int main(){
int *a;
size_tasize = 0;
a = calloc(1, sizeof(int));
f = l = a;
asize = sizeof(int);
put(a, 1, &asize);
put(a, 3, &asize);
put(a, 2, &asize);
_getch();
return 0;
}
void put(int *a, int d, size_t * asize){
printf("--%d--\n", asize); //always == 4
void *tmp = (int *)realloc(a, *asize + sizeof(int));
(*asize) += 4;
if (tmp)
a = tmp; //allocated succesfully
else
printf("Reallocating of 'a' size %d failed\n", asize);
l++;
}
In C, there is no way to know the size of an array which is referenced by a pointer:
int a[25]; // Known size
int *b = a; // Unknown size
so the sizeof() just prints the size of the pointer which is 4 bytes on a 32bit platform.
If you need the size, allocate a structure like so:
struct Mem {
int size;
int a[1];
}
Use sizeof(struct Mem) + sizeof(int) * amount to determine how much memory to allocate, assign it to a pointer. Now you can use the memory with ptr->a[x].
Note that it will allocate a bit more memory that necessary (usually 4 bytes) but this approach works with different alignments, pointer sizes, etc.
sizeof(a) is the size of the pointer, not what a points to.
You are modifying the local variable a within the function, not the variable a in your main function. You either need to return the new value of a from put() or pass in a pointer to your pointer (int **a) to modify it.
For example:
int *put(int *a, int d);
int main(){
int *a;
a = calloc(1, sizeof(int));
a = put(a, 1);
...
}
int *put(int *a, int d){
void *tmp = (int *)realloc(a, sizeof(a) + sizeof(int));
if (tmp)
a = tmp; //allocated succesfully
else
printf("Reallocating of 'a' size %d failed\n", sizeof(a));
return a;
}
sizeof(a) will always return 4 in your case. It returns the size of the pointer, not the size of the memory allocated that the pointer is pointing to.
Instead of doing
if (tmp)
a = tmp;
return tmp and assign it to a in main.
If you want to re-assign a new block to the pointer in a function other then one in which it has been defined , you have to pass a pointer to this pointer or return the newly allocated block and collect it into the same older block in caller function, as otherwise you'd be updating a copy.
The whole concept does not work the way you would it have to.
The sizeof a stuff does not work the way you intend to.
The reallocation itself is wrong, as you don't return the new address to the caller.
You have no information about the length of your data.
I would propose the following:
struct memblock {
unsigned int alloced;
unsigned int len;
int * data;
}
// in order to prealloc
char add_realloc(struct memblock * mb, unsigned int add) {
add += mb->alloced;
int * tmp = realloc(mb->data, sizeof(*mb) + add * sizeof(*(mb->data)));
if (!tmp) return 0;
mb->data = tmp;
mb->alloced = add;
return 1;
}
char put(struct memblock * mb, int d) {
if (mb->len == mb->alloced) {
// realloc
if (!add_realloc(mb, 1)) return 0;
}
mb->data[mb->len++] = d;
return 1;
}
int main(){
struct memblock a = {} // init with all zeros.
// Calling realloc() with a NULL pointer is like malloc().
// we put 3 values. Prealloc for not to have to realloc too often.
if (add_realloc(&a, 3) {
// now we are safe. Don't check the return values - it is guaranteed to be ok.
put(&a, 1);
put(&a, 3);
put(&a, 2);
}
return 0;
}

Resources