I have a program that creates a struct named Stack that holds a pointer to an array of ints and an int that shows the size of this array.
I have functions to:
Initialize the struct with empty values
Push integers to the array (dynamically allocate more memory and write a value to it)
Pop an int from the array
However, when I try to pop the last element by freeing the memory it occupies, my program crashes.
What am I doing wrong here?
Is my process correct?
I realize the problem is probably that I'm trying to free a segment of memory that has not been allocated dynamically, but I just don't see where the issue is exactly.
#include <stdio.h>
#include <stdlib.h>
#include <mem.h>
struct Stack{
int *array;
int size;
};
typedef struct Stack Stack;
void initStack(Stack *stack);
void push(Stack *stack, int value);
int pop(Stack *stack);
int main()
{
Stack firstStack;
initStack(&firstStack);
push(&firstStack, 1222);
pop(&firstStack);
push(&firstStack, 555);
for(int i = 0; i < firstStack.size; ++i){
printf("#%d: %d (%p) ", i , firstStack.array[i], &firstStack.array[i]);
}
return 0;
}
void initStack(Stack *stack){
stack->array = NULL;
stack->size = 0;
}
void push(Stack *stack, int value){
int size = stack->size;
int newSize = size + 1;
stack->array = realloc(stack->array, newSize * sizeof(int));
if(stack->array != NULL){
stack->array[size] = value;
stack->size = stack->size + 1;
}
else{
printf("MALLOC ERROR");
}
}
int pop(Stack *stack){
int lastValue = stack->array[stack->size];
int lastIndex = (stack->size)-1;
int* lastAddress = (stack->array)+lastIndex;
free(lastAddress);
stack->size = (stack->size) - 1 ;
printf("memory free\n");
return lastValue;
}
int* lastAddress = (stack->array)+lastIndex;
free(lastAddress);
is wrong because lastAddress may not be an address allocated via malloc() family by adding lastIndex.
Remove the line
free(lastAddress);
If you want the system to change tha allocated size, you should change the line to
stack->array = realloc(stack->array, ((stack->size) - 1) * sizeof(int));
This is a problem:
int* lastAddress = (stack->array)+lastIndex;
free(lastAddress);
The argument to free must be an address value returned from malloc, calloc, or realloc - you cannot free memory at an arbitrary address, even within a dynamically allocated block.
Related
I am trying to implement on my own (in order to understand it better) the Stack data structure in C language.
Here is what I've got so far:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct stack{
//Data_Strucure: Stack of intgers
int *stack;
int size_of_stack;
int elem_in_stack;
};
struct stack *creat_stack(unsigned int);
int push(struct stack *, int);
int pop(struct stack *);
int empty(struct stack *);
int peek(struct stack *);
int main(int argc, char *argv[]){
int new_elem = 13;
struct stack *new_stack = creat_stack(5);
printf("%d %d\n", new_stack->size_of_stack, new_stack->elem_in_stack);
//Crashes from here
push(new_stack, new_elem);
printf("%d\n", new_stack->stack[new_stack->size_of_stack]);
}
struct stack *creat_stack(unsigned int size){
struct stack tmp;
struct stack *ret_stack = &tmp;
if((ret_stack->stack = malloc(sizeof(int) * size)) == NULL){
fprintf(stderr, "Unable to allocate memory for the Stack.\n");
exit(1);
}
ret_stack->size_of_stack = size;
ret_stack->elem_in_stack = 0;
return ret_stack;
}
int push(struct stack *stack, int nw_elem){
int pos = stack->size_of_stack - stack->elem_in_stack;
if(stack->size_of_stack == 0)
return 1;
stack->stack[pos] = nw_elem;
}
The compiler returns me no error. Though I don't understand why it crashes after push() is called.
Please, if possible, instead of solution code, can you just tell me where the error is? This way I can understand how it effect the whole program and try to solve it on my own (so next time won't happen again).
Thanks is advance for any of your usefull answers.
At least the function creat_stack is incorrect.
struct stack *creat_stack(unsigned int size){
struct stack tmp;
struct stack *ret_stack = &tmp;
//...
return ret_stack;
}
It returns a pointer to the local object tmp that will not be alive after exiting the function. So the returned pointer will be invalid and dereferencing such a pointer invokes undefined behavior.
Instead you could return the object itself from the function. That is the function declaration could look like
struct stack creat_stack(unsigned int size);
And in main you can write
struct stack new_stack = creat_stack(5);
Also the function push does not change the data member elem_in_stack And again it invokes undefined behavior because when elem_in_stack is equal to 0 then the function tries to write to memory outside the dynamically allocated array. That is in this case pos is equal to size_of_stack.
int push(struct stack *stack, int nw_elem){
int pos = stack->size_of_stack - stack->elem_in_stack;
if(stack->size_of_stack == 0)
return 1;
stack->stack[pos] = nw_elem;
}
This is the code here. Even after debugging I'm not able to find the problem. The code was working fine if I'm not using the pointer.
#include <stdio.h>
#include <stdlib.h>
struct stack{
int size;
int top;
int *arr;
};
int isEmpty(struct stack *ptr){
if ((*ptr).top == -1){
return 1;
}
else{
return 0;
}
}
int main()
{
struct stack *s;
(*s).size = 80;
(*s).top = -1;
(*s).arr = (int *)malloc((*s).size * sizeof(int));
// Check if stack is empty
if(isEmpty(s)){
printf("The stack is empty");
}
else{
printf("The stack is not empty");
}
return 0;
}
You did not allocate any memory for your struct. You may decalre it on the stack: struct stack s; or allocate memory for it: struct stack *s = (struct stack *)malloc(sizeof(struct stack));.
When you have a pointer to a struct, please use the -> operator to access its members like so s->size.
I'm trying to implement stack in C.
What I'm going for:
Design a Stack structure with push and pop functions for the implementation.
Create a Memory structure owns number of block, block size, and stack attributes.
Stack attribute represents memory blocks. Number of block attribute represents the length of the stack. Block size represents the maximum value that each element in the stack can get.
Write an allocate function that takes a size parameter. If the given size is bigger than block size of the Memory, the allocation will be distributed to the different blocks in the stack attribute.
For example, calling allocate(27) updates the stack as:
allocate(27) = [10, 10, 7, 0, 0]
for a Memory with number of block = 5, block size = 10. The remaining of the elements which don't have maximum value can be sealed until the element is flushed. Therefore, the next allocation can start from next element position after 7 given above.
Write a deallocate function that flushes the last used block.
My Work:
First, created the structs:
stack attribute represents memory blocks.
number of block attribute represents the length of the stack.
Block size represents the maximum value that each element in the stack can get.
#include <stdio.h>
#include <stdlib.h> // Provides function For memory locating. allocate & deallocate.
struct Stack {
int top;
};
struct Memory{
int stack;
int number_of_block; // 5
int block_size; // 10
};
Then I have tried to create allocate & push function but they are not working.
int main(){
allocate(30);
return 0;
}
int allocate(int size){
struct Stack* stack = (struct Stack*)malloc(sizeof(struct Stack));
struct Memory* memory = (struct Memory*)malloc(sizeof(struct Memory));
memory->block_size = 10;
stack->top = -1;
memory->stack = (int*)malloc(memory->block_size * sizeof(int));
struct Memory memory = {1, 5, 10};
for(int i = 0; i < 5; i++){
if(size > 10){
size = size - 10; //27 - 10 = 17 -> 17 - 10 = 7
push(stack, 10);
}
}
if(size % 10 != 0){
int size_mod = size % 10; //27 % 10 = 7
push(stack, size_mod);
}
}
void push(struct Stack* stack, struct Memory* memory, int item){
if(stack->top == memory->block_size - 1){
return;
}
memory->stack[++stack->top] = item;
printf("%d ", item);
}
The Memory structure contains a pointer to the first block, as well as the number of blocks and the maximum size of each block. Each block then contains the data and a pointer to the next block, meaning all the blocks are stored in a linked list.
The function allocate returns a pointer to the Memory structure created.
#include <stdio.h>
#include <stdlib.h>
struct Block {
int data;
struct Block *next;
};
struct Memory {
int block_count;
int block_size;
struct Block *head;
};
/* Push a new block onto the stack */
void push(struct Block **head, int data)
{
struct Block *new = malloc(sizeof *new);
if (!new) {
printf("Error: memory allocation failed");
exit(EXIT_FAILURE);
}
new->data = data;
*head = new;
/* `printf` is not needed */
printf("%d\n", data);
}
/* Returns a pointer to the `Memory` structure */
struct Memory *allocate(int size)
{
struct Memory *memory = malloc(sizeof *memory);
if (!memory) {
printf("Error: memory allocation failed");
exit(EXIT_FAILURE);
}
memory->block_count = 5;
memory->block_size = 10;
struct Block *head = NULL;
for (int i = 0; i < memory->block_count; ++i) {
int data = 0;
if (size > 10)
data = 10;
else if (size > 0)
data = size;
size -= data;
push(&head, data);
}
memory->head = head;
return memory;
}
int main(void)
{
struct Memory *memory = allocate(27);
return EXIT_SUCCESS;
}
And as you can see, you don't need to cast malloc, because it returns void *, which is automatically and safely promoted to any other pointer.
Can we dynamically allocate memory for structures? Is this a correct procedure to approach a dynamically allocated structures? Please tell me how to malloc() and realloc() a structure.
newnode is of type struct List * but when start indexing it converts to struct List.How this conversion possible?My insert function accepts only (struct List*) Am I wrong somewhere?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct List {
char val[20];
};
void insert(struct List *);
int main(void) {
int i = 0;
int size = 1;
struct List *newnode = (struct List *)malloc(size * sizeof(struct List));
for (i = 0; i < 5; i++) {
if (size <= i) {
size = size + size;
newnode = (struct List *)realloc(newnode, size * sizeof(struct List));
}
scanf("%s", newnode[i].val);
insert(newnode[i]);
}
for (i = 0; i < 5; i++) {
printf("%s\n", newnode[i].val);
}
return 0;
}
void insert(struct List *node) {
printf("%s\n", node->val);
}
The code works except for 3 problems:
You do not test for memory allocation failure. Both malloc() and realloc() will return NULL if memory cannot be allocated: you will get undefined behavior when dereferencing newnode should this happen.
to handle the case of realloc() failure gracefully, you should store the reallocated pointer to a different variable so you can still access the previous array that has not been deallocated and free it.
scanf("%s", newnode[i].val); is a security flaw: you should limit the number of bytes that can be stored to the destination array with
scanf("%19s", newnode[i].val);
you do not test the return value of scanf() to detect invalid or missing input.
insert() does not insert anything.
Here is a modified version with error handling and less confusing names:
#include <stdio.h>
#include <stdlib.h>
struct Item {
char val[20];
};
//void insert(struct Item *);
int main(void) {
int i, j;
int size = 0;
struct Item *array = NULL;
for (i = 0; i < 5; i++) {
if (i >= size) {
int newsize = size ? 1 : size + size;
struct Item *newarray = realloc(array, sizeof(*array) * size);
if (newarray == NULL) {
perror("cannot reallocate the array");
break;
}
size = newsize;
array = newarray;
}
if (scanf("%19s", array[i].val) != 1) {
fprintf(stderr, "missing input\n");
break;
}
//insert(array[i]);
}
for (j = 0; j < i; i++) {
printf("%s\n", array[i].val);
}
free(array);
return 0;
}
Yes, this is fine except that you are assigning the return value to your original array pointer. realloc() returns NULL if it can't resize the memory. You need to assign it to a temporary variable and, if the value is NULL, don't overwrite a.
The main thing you have to watch out for are pointers, which your struct doesn't have. In those cases, the memory pointed to is not part of the allocated array.
i have a problem inside my program, i've implemented a simple stack in C
the problem is that when i try to reallocate the stack array for the second time, the program triggers a brekapoint just inside the realloc function, i don't know what could be wrong since i'm using a buffer to check whether realloc fails or not. probably, this code is where i use the realloc function:
struct stack {
void** data;
int top;
int initial_size;
};
static void stack_resize(struct stack* instance, int capacity)
{
if (instance->initial_size == instance->top)
{
int new_sz = capacity * sizeof *instance->data;
// THIS REALLOC crashes
void** buffer = realloc(instance->data, new_sz); // realloc the stack array
printf("reallocating memory\n");
if (buffer) {
instance->data = buffer;
instance->initial_size = new_sz;
}
}
}
the following function instead, is where the stack_resize() gets called
void stack_push(struct stack* instance, void* data)
{
if (instance->top >= instance->initial_size)
{
// shrink the array
stack_resize(instance, instance->initial_size);
}
instance->data[++instance->top] = data;
printf("pushing onto the stack!\n");
}
This is the constructor where i initialize all the data.
struct stack* stack_new(int initial_size)
{
struct stack* new_stack = (struct stack*)malloc(sizeof(struct stack));
if (!new_stack) {
fprintf(stderr, "no memory available from the operative system\n");
return NULL;
}
memset(new_stack, 0, sizeof(struct stack));
new_stack->data = (void**)malloc(sizeof(void*) * initial_size);
if (!new_stack->data) {
fprintf(stderr, "could not allocate memory for the buffer\n");
return NULL;
}
printf("created a stack with %d slot(s)\n", initial_size);
new_stack->top = -1;
new_stack->initial_size = initial_size;
return new_stack;
}
and this is the entry point of the program:
int main(int argc, char** argv)
{
struct stack* new_stack = stack_new(2);
for (int i = 0; i < 55; i++)
{
stack_push(new_stack, (void*)i);
}
getchar();
return 0;
}
Any help would be much appreciated! thanks to all.
Crash is seen because you are assigning new_sz to instance->initial_size.
since new_sz holds actual size of array in bytes, which is capacity*sizeof(void *)
int new_sz = capacity * sizeof *instance->data;
instance->initial_size = new_sz;
your stack top and initial_size will mismatch.
if (instance->top >= instance->initial_size)
Your top will always less then initial_size and you will not allocate new memory.
In order to your program to work you need to make the following changes.
int new_sz = (capacity+1) * sizeof(void *);
instance->initial_size = capacity+1;//instead of new_size