I'm writing this code for an assignment and the functions are supposed to be generic and it's up to the user to decide whether to work with integers or strings. Obviously I wrote specific functions for operations for both types. The only problem left in the code is when I try to free int type allocated memory I get the following:
Exception thrown at 0x0F24904D (ucrtbased.dll) in ConsoleApplication7.exe: 0xC0000005: Access violation reading location 0x00000006.
I get this only when debugging but compiling without debugging will simply stop when I try to perform the operation and freeze for a few seconds before ending the program.
Here's the entire code:
Header:
#ifndef _HEADER_H
#define _HEADER_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>
typedef enum { FALSE, TRUE } BOOL;
/* defining specific function names*/
typedef int(*compare_func)(void*, void*);
typedef void(*print_func)(void*);
typedef void(*free_func)(void*);
/* defining struct names and pointers*/
typedef struct set Set;
typedef struct set* PSet;
typedef struct list List;
typedef struct list* PList;
/* creating and initialzing a set*/
List* createSet(compare_func cmp_fnc, print_func prnt_fnc, free_func free_fnc);
/* finding the biggest value in the set*/
void* findMax(PList List);
/* finding the smallest value in the set*/
void* findMin(PList List);
/* finding an element in the set*/
BOOL findInSet(PList List, void* val);
/* function for finding the size of the list*/
int setSize(PList list);
/* inserting a new element.*/
BOOL addToSet(PList List, void *data);
/* deleting an element, pointered by todel*/
BOOL deleteFromSet(PList list, void *todel);
/* print the elements in the set */
void printAll(PList list);
/* deleting the entire set */
void deleteSet(PList list);
#endif
Implementation:
#include "Header.h"
struct set // Set struct for doubly-linked list
{
void* data;
struct set *next, *prev;
};
struct list // List struct
{
int ListSize;
Set *head;
Set *tail;
compare_func compare;
print_func print;
free_func free;
};
List* createSet(compare_func cmp_fnc, print_func prnt_fnc, free_func free_fnc) // Function for initializing and creating a set
{
PList LIST;
LIST = (PList)malloc(sizeof(List));
if (LIST == NULL)
{
printf("Error! Memory allocation failed.\n");
exit(1);
}
LIST->ListSize = 0;
LIST->head = NULL;
LIST->tail = NULL;
LIST->compare = cmp_fnc;
LIST->print = prnt_fnc;
LIST->free = free_fnc;
return LIST;
}
void* findMax(PList List) // Function for finding the biggest value in a set
{
if (List->head == NULL) // If the set is empty
return NULL;
PSet temp;
void* max = List->head->data;
temp = List->head;
while (temp)
{
if (List->compare(temp->data, max) == 1) // Finding the biggest value
max = temp->data;
temp = temp->next; // Moving to the next node
}
return max;
}
void* findMin(PList List) // Function for finding the smallest value in a set
{
if (List->head == NULL) // If the set is empty
return NULL;
PSet temp;
void* min = List->head->data;
temp = List->head;
while (temp)
{
if (List->compare(temp->data, min) == -1) // Finding the smallest value
min = temp->data;
temp = temp->next; // Moving to the next node
}
return min;
}
BOOL findInSet(PList List, void* val) // Function for checking whether a given character is in the set
{
if (List->head == NULL) // If the list is empty
return FALSE;
PSet temp;
temp = List->head;
while (temp)
{
if (List->compare(temp->data, val) == 0) // If the character exists
return TRUE;
temp = temp->next; // Moving to the next node
}
return FALSE;
}
int setSize(PList list)
{
return list->ListSize;
}
BOOL addToSet(PList List, void *data) // Function for adding an item to the set
{
PSet temp, CurrentNode;
CurrentNode = List->head;
temp = (PSet)malloc(sizeof(Set));
if (temp == NULL) // If the allocation failed return false
return FALSE;
temp->data = data; // Filling the temp with the data
temp->next = NULL;
temp->prev = NULL;
if (List->head == NULL) // If the list is empty
{
List->head = temp;
List->tail = temp;
List->ListSize++;
return TRUE;
}
else {
while (CurrentNode) // Loop for checking whether the inserted character exists in the list
{
if (List->compare(data, CurrentNode->data) == 0) return FALSE;
CurrentNode = CurrentNode->next;
}
List->tail->next = temp; // Adding the node to the list
temp->prev = List->tail;
List->tail = temp; // Updating the tail
List->ListSize++;
return TRUE;
}
}
BOOL deleteFromSet(PList list, void *todel) // Function for deleteing an item from a set
{
PSet nodeToDel;
if (list->head == NULL) // If the list is empty
return FALSE;
if (list->compare(todel, list->head->data) == 0) // If the node to be deleted is the head
{
nodeToDel = list->head;
list->head = list->head->next;
if (list->head != NULL)
list->head->prev = NULL;
list->free(nodeToDel->data);
free(nodeToDel);
list->ListSize--;
return TRUE;
}
else if (list->compare(todel, list->tail->data) == 0) // If the node to be deleted is the tail
{
nodeToDel = list->tail;
list->tail = list->tail->prev;
list->tail->next = NULL;
list->free(nodeToDel->data);
free(nodeToDel);
list->ListSize--;
return TRUE;
}
else
{
nodeToDel = list->head;
while (nodeToDel->next) // Any node other than the head or the tail
{
if (list->compare(todel, nodeToDel->data) == 0) // If the character exists in the list
{
nodeToDel->next->prev = nodeToDel->prev;
nodeToDel->prev->next = nodeToDel->next;
list->free(nodeToDel->data);
free(nodeToDel);
list->ListSize--;
return TRUE;
}
nodeToDel = nodeToDel->next; // Moving to the next node
}
}
return FALSE; // If the character wasn't found in the list return false
}
void printAll(PList list) // Funciton for printing all items in a set
{
PSet temp;
if (list->head == NULL) // If the list is empty
printf("\nThe list is empty.");
else
{
printf("\nThe list is:\n");
temp = list->head;
while (temp) // While there are still nodes left
{
list->print(temp->data); // Call specific function for printing
temp = temp->next; // Move to the next node
}
printf("\n");
}
}
void deleteSet(PList list) // Function for deleting a set
{
PSet temp;
if (!(list->head)) // If the list is empty
printf("\nThe set is empty.\n");
else
{
while (list->head)
{
temp = (list->head);
list->head = list->head->next; // Moving to the next node
if (list->head != NULL)
list->head->prev = NULL;
list->free((temp->data)); // Call specific function for freeing memory
free(temp);
}
list->ListSize = 0;
list->head = NULL;
list->tail = NULL;
printf("\nThe set has been deleted.\n");
}
}
Main:
#include "Header.h"
void prnt_string(void* str) // specific function for printing strings
{
printf("%s ", (char*)str);
}
void free_string(void* str) // specific function for freeing memory
{
free((char*)str);
}
int cmp_str(void* s1, void* s2) // specific function for comparing two strings
{
if (strcmp((char*)s1, (char*)s2) == 0)
return 0;
else if (strcmp((char*)s1, (char*)s2) == 1)
return 1;
else return -1;
}
void prnt_int(void* a) // Specific function for printing integers
{
printf("%d ", (int*)a);
}
void free_int(void* a) // Specific function for freeing integers
{
free(a);
}
int int_comp(void* a, void* b) // Specific function for comparing integers
{
if ((int*)a == (int*)b)
return 0;
else if ((int*)a > (int*)b)
return 1;
else return -1;
}
int main()
{
char ch, tempstr[31], *str;
int n, option, *num, item;
void *temp;
BOOL status;
PList list;
printf("Choose the type you want to work with:\n");
printf("1. Integers\n");
printf("2. Strings\n");
printf("Enter input: ");
scanf("%d", &n);
switch (n)
{
case 1:
list = createSet(int_comp, prnt_int, free_int);
do
{
printf("\n\nChoose the desired action: ('-1' to exit)\n");
printf("1. Create a Set\n");
printf("2. Add To Set\n");
printf("3. Delete From Set\n");
printf("4. Find an Item in The Set\n");
printf("5. Show The Size of The Set\n");
printf("6. Find The Biggest Value In The Set\n");
printf("7. Find The Smallest Value In The Set\n");
printf("8. Delete The Set\n");
printf("Enter input: ");
scanf("%d", &option);
switch (option)
{
case 1:
list = createSet(int_comp, prnt_int, free_int);
printf("\nThe Set Has Been Initialized.\n\n");
break;
case 2:
num = (int*)malloc(sizeof(int));
if (num == NULL)
{
printf("Memory allocation failed!");
deleteSet(list);
return 1;
}
else
{
printf("\nEnter a number: ");
scanf("%d", &num);
status = addToSet(list, num);
if (status == TRUE)
{
printf("Number successfully added to set.\n\n");
printAll(list);
printf("\n");
}
else
{
printf("Operation failed!\nThe number already exists in the set or memory allocation failed.\n\n");
deleteSet(list);
return 1;
}
}
break;
case 3:
printf("\nEnter number: ");
scanf("%d", &item);
status = deleteFromSet(list, item);
if (status == TRUE)
{
printf("Number successfully deleted.\n\n");
printAll(list);
}
else
{
printf("Operation failed!\nThe number does not exist in the set.\n\n");
printAll(list);
printf("\n");
}
break;
case 4:
printf("\nEnter number: ");
scanf("%d", &item);
if (findInSet(list, item) == TRUE)
printf("Item exists in the set.\n\n");
else printf("Item does not exist in the set or the set is empty.\n\n");
break;
case 5:
printf("\nThe size of the set is %d.\n\n", setSize(list));
break;
case 6:
temp = findMax(list);
if (temp == NULL) printf("\nThe set is empty.\n\n");
else printf("\nThe biggest value in the set is %d.\n\n", (int*)temp);
break;
case 7:
temp = findMin(list);
if (temp == NULL) printf("\nThe set is empty.\n\n");
else printf("\nThe smallest value in the set is %d.\n\n", (int*)temp);
break;
case 8:
deleteSet(list);
break;
case -1:
printf("\nExiting Program\n\n");
break;
default:
printf("\nWrong input!\n\n");
break;
}
} while (option != -1);
deleteSet(list);
free(list);
break;
case 2:
list = createSet(cmp_str, prnt_string, free_string);
do
{
printf("\n\nChoose the desired action: ('-1' to exit)\n");
printf("1. Create a Set\n");
printf("2. Add To Set\n");
printf("3. Delete From Set\n");
printf("4. Find an Item in The Set\n");
printf("5. Show The Size of The Set\n");
printf("6. Find The Biggest Value In The Set\n");
printf("7. Find The Smallest Value In The Set\n");
printf("8. Delete The Set\n");
printf("Enter input: ");
scanf("%d", &option);
switch (option)
{
case 1:
list = createSet(cmp_str, prnt_string, free_string);
printf("\nThe Set Has Been Initialized.\n\n");
break;
case 2:
printf("\nEnter a string(max of 30 characters):\n");
scanf("%s", tempstr);
str = (char*)malloc(strlen(tempstr) + 1 * sizeof(char));
if (str == NULL)
{
printf("Memory allocation failed!\n\n");
deleteSet(list);
return 1;
}
strcpy(str, tempstr);
status = addToSet(list, str);
if (status == TRUE)
{
printf("String successfully added to set.\n\n");
printAll(list);
}
else
{
printf("Operation failed!\nThe string already exists in the set or memory allocation failed.\n\n");
deleteSet(list);
return 1;
}
break;
case 3:
printf("\nEnter string(max of 30 characters): ");
scanf("%s", tempstr);
status = deleteFromSet(list, tempstr);
if (status == TRUE)
{
printf("String successfully deleted.\n\n");
printAll(list);
}
else
{
printf("Operation failed!\nThe string does not exist in the set.");
printAll(list);
printf("\n");
}
break;
case 4:
printf("\nEnter string: ");
scanf("%s", tempstr);
if (findInSet(list, tempstr) == TRUE)
printf("Item exists in the set.\n\n");
else printf("Item does not exist in the set.\n\n");
break;
case 5:
printf("\nThe size of the set is %d.\n\n", setSize(list));
break;
case 6:
temp = findMax(list);
if (temp == NULL) printf("\nThe set is empty.\n\n");
else
{
printf("\nThe biggest value in the set is ");
puts((char*)temp);
printf("\n");
}
break;
case 7:
temp = findMin(list);
if (temp == NULL) printf("\nThe set is empty.\n\n");
else
{
printf("\nThe smallest value in the set is ");
puts((char*)temp);
printf("\n");
}
break;
case 8:
deleteSet(list);
break;
case -1:
printf("\nExiting Program\n\n");
break;
default:
printf("\nWrong input!\n\n");
break;
}
} while (option != -1);
deleteSet(list);
free(list);
break;
default:
printf("\nWrong input!\n\n");
break;
}
getch();
return 0;
}
This is the function causing the problem:
void free_int(void* a) // Specific function for freeing integers
{
free(a);
}
The code works perfectly with strings but not with ints. If someone can point out the problem I'd be really grateful. Thanks in advance.
Your program may crash because you are overwriting pointer value:
int* num; // [1]
num = (int*)malloc(sizeof(int)); // [2]
scanf("%d", &num); // [3] you are changing value of pointer !!
// scanf ("%d", num); // [4] USE THIS LINE
status = addToSet(list, num);
[1] declaration pointer to int
[2] memory was allocated, it is pointed by num
[3] you are passing pointer to pointer as argument to scanf
function, then you are modifing value of pointer (you are not writing some integer value into memory area pointed by num
!). So when free
function is called it tries to release invalid pointer. It is UB.
[4] scanf("%d",num);
use this line to avoid problem with invalid pointer value
User contributions licensed under CC BY-SA 3.0