Use realloc() in function - arrays

#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.

Related

How do I allocate memory for a new string in a C Multiarray?

I am trying to find a way to create a dynamically allocated array of C strings. So far I have come with the following code that allows me to initialize an array of strings and change the value of an already existing index.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void replace_index(char *array[], int index, char *value) {
array[index] = malloc(strlen(value) + 1);
memmove(array[index], value, strlen(value) + 1);
}
int main(int argc, const char * argv[]) {
char *strs[] = {"help", "me", "learn", "dynamic", "strings"};
replace_index(strs, 2, "new_value");
// The above code works fine, but I can not use it to add a value
// beyond index 4.
// The following line will not add the string to index 5.
replace_index(strs, 5, "second_value");
}
The function replace_index will work to change the value of a string already include in the initializer, but will not work to add strings beyond the maximum index in the initializer. Is there a way to allocate more memory and add a new index?
First off, if you want to do serious string manipulation it would be so much easier to use almost any other language or to get a library to do it for you.
Anyway, onto the answer.
The reason replace_index(strs, 5, "second_value"); doesn't work in your code is because 5 is out of bounds-- the function would write to memory unassociated with strs. That wasn't your question, but that's something important to know if you didn't. Instead, it looks like you want to append a string. The following code should do the trick.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
char **content;
int len;
} string_array;
void free_string_array(string_array *s) {
for (int i = 0; i < s->len; i++) {
free(s->content[i]);
}
free(s->content);
free(s);
}
int append_string(string_array *s, char *value) {
value = strdup(value);
if (!value) {
return -1;
}
s->len++;
char **resized = realloc(s->content, sizeof(char *)*s->len);
if (!resized) {
s->len--;
free(value);
return -1;
}
resized[s->len-1] = value;
s->content = resized;
return 0;
}
string_array* new_string_array(char *init[]) {
string_array *s = calloc(1, sizeof(string_array));
if (!s || !init) {
return s;
}
while (*init) {
if (append_string(s, *init)) {
free_string_array(s);
return NULL;
}
init++;
}
return s;
}
// Note: It's up to the caller to free what was in s->content[index]
int replace_index(string_array *s, int index, char *value) {
value = strdup(value);
if (!value) {
return -1;
}
s->content[index] = value;
return 0;
}
int main() {
string_array *s = new_string_array((char *[]) {"help", "me", "learn", "dynamic", "strings", NULL});
if (!s) {
printf("out of memory\n");
exit(1);
}
free(s->content[2]);
// Note: No error checking for the following two calls
replace_index(s, 2, "new_value");
append_string(s, "second value");
for (int i = 0; i < s->len; i++) {
printf("%s\n", s->content[i]);
}
free_string_array(s);
return 0;
}
Also, you don't have to keep the char ** and int in a struct together but it's much nicer if you do.
If you don't want to use this code, the key takeaway is that the array of strings (char ** if you prefer) must be dynamically allocated. Meaning, you would need to use malloc() or similar to get the memory you need, and you would use realloc() to get more (or less). Don't forget to free() what you get when you're done using it.
My example uses strdup() to make copies of char *s so that you can always change them if you wish. If you have no intention of doing so it might be easier to remove the strdup()ing parts and also the free()ing of them.
Static array
char *strs[] = {"help", "me", "learn", "dynamic", "strings"};
This declares strs as an array of pointer to char and initializes it with 5 elements, thus the implied [] is [5]. A more restrictive const char *strs[] would be more appropriate if one were not intending to modify the strings.
Maximum length
char strs[][32] = {"help", "me", "learn", "dynamic", "strings"};
This declares strs as an array of array 32 of char which is initialized with 5 elements. The 5 elements are zero-filled beyond the strings. One can modify this up to 32 characters, but not add more.
Maximum capacity singleton for constant strings
static struct str_array { size_t size; const char *data[1024]; } strs;
This will pre-allocate the maximum capacity at startup and use that to satisfy requests. In this, the capacity is 1024, but the size can be any number up to the capacity. The reason I've made this static is this is typically a lot to put the stack. There is no reason why it couldn't be dynamic memory, as required.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
static struct { size_t size; const char *data[1024]; } strs;
static const size_t strs_capacity = sizeof strs.data / sizeof *strs.data;
/** Will reserve `n` pointers to strings. A null return indicates that the size
is overflowed, and sets `errno`, otherwise it returns the first string. */
static const char **str_array_append(const size_t n) {
const char **r;
if(n > strs_capacity - strs.size) { errno = ERANGE; return 0; }
r = strs.data + strs.size;
strs.size += n;
return r;
}
/** Will reserve one pointer to a string, null indicates the string buffer is
overflowed. */
static const char **str_array_new(void) { return str_array_append(1); }
int main(void) {
const char **s;
size_t i;
int success = EXIT_FAILURE;
if(!(s = str_array_append(5))) goto catch;
s[0] = "help";
s[1] = "me";
s[2] = "learn";
s[3] = "dynamic";
s[4] = "strings";
strs.data[2] = "new_value";
if(!(s = str_array_new())) goto catch;
s[0] = "second_value";
for(i = 0; i < strs.size; i++) printf("->%s\n", strs.data[i]);
{ success = EXIT_SUCCESS; goto finally; }
catch:
perror("strings");
finally:
return success;
}
Dynamic array
struct str_array { const char **data; size_t size, capacity; };
I think you are asking for a dynamic array of const char *. Language-level support of dynamic arrays is not in the standard C run-time; one must write one's own. Which is entirely possible, but more involved. Because the size is variable, it will probably be slower, but in the limit as the problem grows, by a constant average.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
/** A dynamic array of constant strings. */
struct str_array { const char **data; size_t size, capacity; };
/** Returns success allocating `min` elements of `a`. This is a dynamic array,
with the capacity going up exponentially, suitable for amortized analysis. On
resizing, any pointers in `a` may become stale. */
static int str_array_reserve(struct str_array *const a, const size_t min) {
size_t c0;
const char **data;
const size_t max_size = ~(size_t)0 / sizeof *a->data;
if(a->data) {
if(min <= a->capacity) return 1;
c0 = a->capacity < 5 ? 5 : a->capacity;
} else {
if(!min) return 1;
c0 = 5;
}
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; } /* Unlikely. */
c0 = c1;
}
if(!(data = realloc(a->data, sizeof *a->data * c0)))
{ if(!errno) errno = ERANGE; return 0; }
a->data = data, a->capacity = c0;
return 1;
}
/** Returns a pointer to the `n` buffered strings in `a`, that is,
`a + [a.size, a.size + n)`, or null on error, (`errno` will be set.) */
static const char **str_array_buffer(struct str_array *const a,
const size_t n) {
if(a->size > ~(size_t)0 - n) { errno = ERANGE; return 0; }
return str_array_reserve(a, a->size + n)
&& a->data ? a->data + a->size : 0;
}
/** Makes any buffered strings in `a` and beyond if `n` is greater then the
buffer, (containing uninitialized values) part of the size. A null on error
will only be possible if the buffer is exhausted. */
static const char **str_array_append(struct str_array *const a,
const size_t n) {
const char **b;
if(!(b = str_array_buffer(a, n))) return 0;
return a->size += n, b;
}
/** Returns a pointer to a string that has been buffered and created from `a`,
or null on error. */
static const char **str_array_new(struct str_array *const a) {
return str_array_append(a, 1);
}
/** Returns a string array that has been zeroed, with zero strings and idle,
not taking up any dynamic memory. */
static struct str_array str_array(void) {
struct str_array a;
a.data = 0, a.capacity = a.size = 0;
return a;
}
/** Erases `a`, if not null, and returns it to idle, not taking up dynamic
memory. */
static void str_array_(struct str_array *const a) {
if(a) free(a->data), *a = str_array();
}
int main(void) {
struct str_array strs = str_array();
const char **s;
size_t i;
int success = EXIT_FAILURE;
if(!(s = str_array_append(&strs, 5))) goto catch;
s[0] = "help";
s[1] = "me";
s[2] = "learn";
s[3] = "dynamic";
s[4] = "strings";
strs.data[2] = "new_value";
if(!(s = str_array_new(&strs))) goto catch;
s[0] = "second_value";
for(i = 0; i < strs.size; i++) printf("->%s\n", strs.data[i]);
{ success = EXIT_SUCCESS; goto finally; }
catch:
perror("strings");
finally:
str_array_(&strs);
return success;
}
but will not work to add strings beyond the maximum index in the initializer
To do that, you need the pointer array to be dynamic as well. To create a dynamic array of strings is one of the very few places where using a pointer-to-pointer to emulate 2D arrays is justified:
size_t n = 5;
char** str_array = malloc(5 * sizeof *str_array);
...
size_t size = strlen(some_string)+1;
str_array[i] = malloc(size);
memcpy(str_array[i], some_string, size);
You have to keep track of the used size n manually and realloc more room in str_array when you run out of it. realloc guarantees that previous values are preserved.
This is very flexible but that comes at the cost of fragmented allocation, which is relatively slow. Had you used fixed-size 2D arrays, the code would perform much faster but then you can't resize them.
Note that I used memcpy, not memmove - the former is what you should normally use, since it's the fastest. memmove is for specialized scenarios where you suspect that the two arrays being copied may overlap.
As a side-note, the strlen + malloc + memcpy can be replaced with strdup, which is currently a non-standard function (but widely supported). It seems likely that strdup will become standard in the upcoming C23 version of C, so using it will become recommended practice.

How do you return a pointer from a function outside of main()

My question is aboutt dynamic memory allocation in C. I have been asked to dynamically allocate an array of n longs, and return the pointer to the first element of this array. I have some code to test the output of this but the memory allocation is failing.
long* make_long_array(long n)
{
int i;
int *a;
a = (int*)malloc(sizeof(int)*n);
if (a == NULL) {
printf("ERROR: Out of memory\n");
return 1;
}
for (i = 0; i < n; *(a + i++) = 0);
return *a;
}
Im getting an error on two lines saying
'error: return makes pointer from integer without cast'
this occurs for the lines
return 1;
and
return *a;
I'm not entirely sure how to fix this. I think the error in return 1; being that I am trying to return an integer when it is looking for a pointer? But I am not sure how to fix it for the return of the pointer. Any help would be much appreciated.
To fix your original version:
long* make_long_array(/* long not the correct type for sizes of objects */ size_t n)
{
// int i; define variables where they're used.
/* int you want to return a */ long *a; // array.
a = /* (int*) no need to cast */ malloc(sizeof(/* int */ you want */ long /*s, remember? *) */ ) * n);
if (a == NULL) {
printf("ERROR: Out of memory\n"); // puts()/fputs() would be sufficient.
return /* 1 */ NULL; // 1 is an integer. Also it is uncommon to return
} // anything other than NULL when a memory allocation
// fails.
for (size_t i = 0; i < n; /* *(a + i++) = 0 that falls into the category obfuscation */ ++i )
/* more readable: */ a[i] = 0;
// return *a; you don't want to return the first long in the memory allocated
return a; // but the address you got from malloc()
}
A Better Waytm to write such allocations is
FOO_TYPE *foo = malloc(NUM_ELEMENTS * sizeof(*foo)); // or
BAR_TYPE *bar = calloc(NUM_ELEMENTS, sizeof(*bar));
By using *foo and *bar as the operand of sizeof you don't have to worry about changing it when the type of foo or bar changes.
Your function can be simplified to
#include <stddef.h> // size_t
#include <stdlib.h> // calloc()
long* make_long_array(size_t size) // size_t is guaranteed to be big enough to hold
{ // all sizes of objects in memory and indexes
return calloc(size, sizeof(long)); // into them. calloc() initializes the memory
} // it allocates with zero.
// if you really want an error-message printed:
long* make_long_array(size_t size)
{
long *data = calloc(size, sizeof(long));
if (!data) // calloc() returned NULL
fputs("Out of memory :(\n\n", stderr); // Error messages should go to stderr
return data; // since it is unbuffered*) and
} // might be redirected by the user.
*) so the user gets the message instantly.
Also there is no need to cast the result of *alloc() since they return a void* which is implicitly convertible in every other pointer type.
Could be written as a macro so it not only works for long but for any type:
#include <stddef.h>
#include <stdlib.h>
#define MAKE_ARRAY(TYPE, COUNT) calloc((COUNT), sizeof((TYPE)))
// sample usage:
int main(void)
{
int *foo = MAKE_ARRAY(*foo, 12);
long *bar = MAKE_ARRAY(*bar, 24);
char *qux = MAKE_ARRAY(*qux, 8);
free(qux);
free(bar);
free(foo);
}

Initialize array of pointers to NULL with realloc without iteration

Is it possible to automatically initialize to NULL the pointers inside an array reallocated with realloc without iterate over it? I would like to do something like calloc but i need te resize an already existent block of memory.
For example:
#DEFINE N 50
typedef int *pointerToInt;
typedef pointerToInt *pointerToPointer;
int main(){
pointerToInt p;
pointerToPointer pp;
pp = malloc(sizeof(p)*N);
//Now i want to resize and initialize my resized vector
pp = realloc(pp, sizeof(p)*(N+10));
}
In first approximation I could change the mallocto calloc, but when I use realloc there's nothing that guarantees me initialized pointers.
Is it necessary to iterate over the whole array and set each single pointer to NULL? Or there's a better way using only callocand realloc?
The short answer is: No, there is no standard function to reallocate a block of memory and initialize its newly allocated portion to all bits zero.
The solution is either:
to not require initialization by keeping track of the valid portion of the array. You obviously must have a way to do this, otherwise how would you decide to reallocate the object.
to initialize the newly allocated portion explicitly.
There are several problems in your code:
#DEFINE N = 50 is incorrect, it should just be #define N 50
hiding pointers behind typedefs is bad: it makes the code obscure and error prone. To do it twice is evil.
you did not include <stdlib.h>
you do not test for malloc failure
you do not initialize the array allocated by malloc() either.
Here is a modified version:
#include <stdlib.h>
#define N 50
int main(void) {
int i;
int **pp, **pp1;
pp = malloc(sizeof(*pp) * N);
if (pp) {
for (i = 0; i < N; i++) {
pp[i] = NULL;
}
//Now I want to resize and initialize my resized vector
pp1 = realloc(pp, sizeof(*pp) * (N + 10));
if (pp1) {
pp = pp1;
for (i = N; i < N + 10; i++) {
pp[i] = NULL;
}
}
free(pp);
}
return 0;
}
Note that you could write a utility function for your purpose:
#include <stdlib.h>
#include <string.h>
void *realloc_zero(void *p, size_t size, size_t new_count, size_t count, int *err) {
void *newp;
if (p == NULL)
count = 0;
newp = realloc(p, size * new_count);
if (newp == NULL) {
*err = 1;
return p;
} else {
if (new_count > count) {
memset((unsigned char*)newp + size * count, 0, size * (new_count - count));
}
*err = 0;
return newp;
}
}
#define N 50
int main(void) {
int err;
int **pp;
pp = calloc(sizeof(*pp), N);
...
//Now I want to resize and initialize my resized vector
pp = realloc_zero(pp, sizeof(*pp), N + 10, N, &err);
if (err) {
// could not resize
free(pp);
return 1;
}
...
free(pp);
return 0;
}
Note however that both calloc and realloc_zero initialize the block to all bits zero, which is not guaranteed by the C Standard to be a proper representation of NULL, although most current architectures do represent the null pointer this way.
No, there is no automatic way. You must iterate and set each uninitialized pointer.

Why crash program by access pointer? In C

I tried to access a pointer but the program crashes. With memory access error.
I receive the pointer from a stack. (pop- function). As a void*-pointer.
Why an I getting this behavior?
int main()
{
int MAX = 5;
int field[MAX];
int i; /* for the loop */
int *pInt = NULL;
initStack();
for (i = 0; i < MAX; i++)
{
field[i] = i;
push((field + i)); // HERE CRASH
}
for (i = 0; i < MAX; i++)
{
pInt = pop(); /* fetch next integer */
printf("%d\n", *pInt); /* print value */
}
return EXIT_SUCCESS;
}
UPDATE:
I have tested my stack. And it works. But with for-loops it crashes.
My stack implementation.
I get the error always I access to the pointer.
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "stack.h"
/*
actual stack data structure
This pointer will pointing at the actual field (of void * pointers)
that represents the stack.
*/
void **array;
/* the current capacity of the stack */
int max = 10;
/* counter variable for counting the elements of the stack. */
int counter = 0;
/*
offset address
points at the top element of the stack.
*/
int offset = -1;
void initStack(void)
{
array = malloc(sizeof(void) * max);
assert(array); /* tests whether pointer is assigned to memory. */
}
/*
grow: increases the stack by 10 elements.
This utility function isn't part of the public interface
*/
void grow(void)
{
max += 10; /* increases the capacity */
int i; // for the loop
void **tmp = malloc(sizeof(void) * max);
/* copies the elements from the origin array in the new one. */
for (i = 0; i < max - 10; i++)
{
*(tmp + i) = *(array + i);
}
array = tmp; /* setups the new one as basis */
}
/* push: pushs the argument onto the stack */
void push(void *object)
{
assert(object); /* tests whether pointer isn't null */
if (offset < max)
{
offset++; /* increases the element-pointer */
/*
moves pointer by the offset address
pushes the object onto stack
*/
*(array + offset) = object;
}
else /* stack is full */
{
/* TODO */
grow();
push(object); /* recursive call */
}
}
/*
pop: pops the top element of the stack from the stack.
*/
void *pop(void)
{
printf("\tBEFORE\n"); //DEBUG
void *top = *(array + offset);
assert(top);
assert(array + offset);
printf("\tAFTER void *top = *(array + offset);\n"); //DEBUG
// int *pInt = top;
// printf("\tpop: value= %d\n", *top); /* DEBUG */
/* decreases the offset address for pointing of
the new top element */
offset--;
return top;
}
There is an error in your stack implementation. In both initStack and grow, you do this:
malloc(sizeof(void) * max);
This is invalid, as void doesn't have a size, although some compilers will evaluate this to 1. So you aren't allocating enough space for an array of void *. As a result, you write past the end of allocated memory which invokes undefined behavior.
Change the type you're getting the size of to void * in both places.
malloc(sizeof(void *) * max);
the issue is that kind of allocation:
void initStack()
{
array = malloc(sizeof(void) * max);
}
sizeof(void) is illegal but some compilers consider it legal like gcc, which in that case returns 1, which isn't enough for your int pointer.
So you could fix those by passing the size of the element:
void initStack(int sz)
{
array = malloc(sz * max);
call by
initStack(sizeof(int *));

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);

Resources