So I'm trying to write a generic program for an assignment and the program keeps telling me that the list variable is being used without being initialized.
I've tried pretty much everything I could but it still didn't make a difference so if anyone can tell me what I'm doing wrong I'd be extremely grateful.
The code is somewhat long so bear with me on this.
Header contents:
#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*/
PList createSet(PList List, 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 File:
#include "Header.h"
typedef struct set // Set struct for bi-directional list
{
void* data;
struct set *next, *prev;
}Set, *PSet;
typedef struct list // List struct
{
int ListSize;
Set *head;
Set *tail;
compare_func compare;
print_func print;
free_func free;
}List, *PList;
PList createSet(PList LIST, 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));
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.");
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--;
}
printf("The set has been deleted.\n");
}
}
Main Function:
#include "Header.h"
void prnt_string(void* str) // specific function for printing strings
{
puts(*(char*)str);
printf(" ");
}
void free_string(void* str) // specific function for freeing memory
{
free(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 ", a);
}
void free_int(void* a) // Specific funtion for freeing integers
{
free(a);
}
int int_comp(void* a, void* b) // Specific function for printing 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(list, int_comp, prnt_int, free_int);
do
{
printf("Choose 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. Find The Biggest Value In The Set\n");
printf("6. Find The Smallest Value In The Set\n");
printf("7. Delete The Set\n");
printf("Enter input: ");
scanf("%d", &option);
switch (option)
{
case 1:
list = createSet(list, int_comp, prnt_int, free_int);
printf("The Set Has Been Initialized.\n");
break;
case 2:
num = (int*)malloc(sizeof(int));
if (num == NULL)
{
printf("Memory allocation failed!");
deleteSet(list);
return 1;
}
else
{
printf("Enter a number: ");
scanf("%d", &num);
status = addToSet(list, num);
if (status == TRUE)
{
printf("Number successfully added to set.\n");
printAll(list);
}
else
{
printf("Operation failed!\nThe number already exists in the set or memory allocation failed.\n");
deleteSet(list);
return 1;
}
}
break;
case 3:
printf("Enter number: ");
scanf("%d", &item);
status = deleteFromSet(list, &item);
if (status == TRUE)
{
printf("Number successfully deleted.\n");
printAll(list);
}
else
{
printf("Operation failed!\nThe number does not exist in the set.");
printAll(list);
}
break;
case 4:
printf("Enter number: ");
scanf("%d", &item);
if (findInSet(list, &item) == TRUE)
printf("Item exists in the set.\n");
else if (findInSet(list, &item) == FALSE) printf("Item does not exist in the set.\n");
/*else if (findInSet(list, &item) == NULL) printf("The set is empty.\n");*/
break;
case 5:
printf("The size of the set is %d", setSize(list));
break;
case 6:
temp = findMax(list);
if (temp == NULL) printf("The set is empty.\n");
else printf("The biggest value in the set is %d", (int*)temp);
break;
case 7:
temp = findMin(list);
if (temp == NULL) printf("The set is empty.\n");
else printf("The smallest value in the set is %d", (int*)temp);
break;
case 8:
deleteSet(list);
break;
}
} while (option != -1);
deleteSet(list);
break;
case 2:
list = createSet(list, cmp_str, prnt_string, free_string);
do
{
printf("Choose 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. Find The Biggest Value In The Set\n");
printf("6. Find The Smallest Value In The Set\n");
printf("7. Delete The Set\n");
printf("Enter input: ");
scanf("%d", &option);
switch (option)
{
case 1:
list = createSet(list, cmp_str, prnt_string, free_string);
printf("The Set Has Been Initialized.\n");
break;
case 2:
printf("Enter a string(max of 30 characters): ");
gets(tempstr);
str = (char*)malloc(strlen(tempstr) + 1 * sizeof(char));
if (str == NULL)
{
printf("Memory allocation failed!\n");
deleteSet(list);
return 1;
}
strcpy(str, tempstr);
status = addToSet(list, str);
if (status == TRUE)
{
printf("String successfully added to set.\n");
printAll(list);
}
else
{
printf("Operation failed!\nThe string already exists in the set or memory allocation failed.\n");
deleteSet(list);
return 1;
}
break;
case 3:
printf("Enter string(max of 30 characters): ");
gets(tempstr);
status = deleteFromSet(list, &tempstr);
if (status == TRUE)
{
printf("String successfully deleted.\n");
printAll(list);
}
else
{
printf("Operation failed!\nThe string does not exist in the set.");
printAll(list);
}
break;
case 4:
printf("Enter string: ");
gets(tempstr);
if (findInSet(list, &tempstr) == TRUE)
printf("Item exists in the set.\n");
else if (findInSet(list, &tempstr) == FALSE) printf("Item does not exist in the set.\n");
/*else if (findInSet(list, &tempstr) == NULL) printf("The set is empty.\n");*/
break;
case 5:
printf("The size of the set is %d", setSize(list));
break;
case 6:
temp = findMax(list);
if (temp == NULL) printf("The set is empty.\n");
else
{
printf("The biggest value in the set is ");
puts((char*)temp);
}
break;
case 7:
temp = findMin(list);
if (temp == NULL) printf("The set is empty.\n");
else
{
printf("The smallest value in the set is ");
puts((char*)temp);
}
break;
case 8:
deleteSet(list);
break;
}
} while (option != -1);
deleteSet(list);
break;
default:
printf("Wrong input!\n");
break;
}
getch();
return 0;
}
When I try running the program I get the error message that the list variable in the main function is being used without being initialized though I fail to understand why it needs initializing in the first place.
What could the problem be?
Every variable should be initialized before being read, because otherwise anything you read from it is garbage. In C variables don't get initialized by default like in some other languages.
In your createSet() function you dereference the variable LIST, but list in main was just declared as a pointer without initializing it to actually point at something.
You should use List in main to declare List list and not PList list. Then pass &list to the functions that take a PList argument.
Also your current createSet() function is mixing two ways of initializing objects together.
You can pass a PList to it and then initialize the List that the PList points to, so:
List fooList;
PList pFooList = &fooList;
createSet(pFooList, ...):
and then in createSet() don't allocate a new object with malloc.
But you can also create the object in createList() but then don't pass it any PList.
The advantage of the first option is that if you wanna dynamically allocate the object you can do it with:
PList pFooList = malloc(sizeof(List));
createSet(pFooList, ...);
but you don't have to, since you can still allocate the object on the stack.
Note
As #MichaelBeer commented, variables declared static actually get automatically initialized, but this wouldn't have solved the problem of the asker, since if list was declared with static PList list, then list would point to NULL instead of just garbage.
Related
#include <stdio.h>
#include <stdlib.h>
#define N 10
typedef struct music_student *StudentPtr;
typedef struct music_student
{
int student_ID;
double hw_average;
int exam_grade;
int final_grade;
StudentPtr next;
} Music_student;
StudentPtr creatnew(int id,double hw,int exam);
StudentPtr Del(int id,StudentPtr list);
StudentPtr insert(int id,double hw,int exam,StudentPtr list);
void Proportion(float prop,StudentPtr list);
int main()
{
int req,id,exam;
double avg;
float prop;
StudentPtr list=NULL;
printf("Course Management Menu\nPlease choose among the following:\n");
printf("***\n");
printf("0: Quit.\n1: Insert student at first place on the list.\n2: Delete by ID.\n3: Find lucky student.\n4: Change homework exam ratio.\n5: Print List.\n");
while (N<15)
{
if(scanf("%d",&req)!=1)
{
printf("Input Error!");
return 1;
}
while(req>6||req<0)
{
printf("Invalid Selection\n");
if(scanf("%d",&req)!=1)
{
printf("Input Error!");
return 1;
}
}
switch (req)
{
case 1:
printf("insert student ID\n");
scanf("%d",&id);
while(id<10000||id>99999)
{
printf("Invalid student id try_again: value between 10,000 and 99,999\n");
scanf("%d",&id);
}
printf("insert hw grade\n");
scanf("%lf",&avg);
while(avg>100||avg<0)
{
printf("Invalid hw grade: value between 0 and 100\n");
scanf("%lf",&avg);
}
printf("insert exam grade\n");
scanf("%d",&exam);
while(exam>100||exam<0)
{
printf("Invalid exam grade: value between 0 and 100\n");
scanf("%d",&exam);
}
list=insert(id,avg,exam,list);
break;
case 2:
printf("Enter student to expunge from records:\n");
scanf("%d",&id);
Del(id,list);
break;
case 3:
Lucky(list);
break;
case 5:
lilPrint(list);
break;
case 0:
printf ("bye bye!");
return 0;
}
}
}
void lilPrint(StudentPtr list)
{
StudentPtr temp = list;
if(list==NULL)
return;
while (temp != NULL)
{
printf("Student Id: %d\nFinal Grade: %d\n",temp->student_ID,temp->final_grade);
temp = temp->next;
}
return;
}
StudentPtr Del(int id, StudentPtr list)
{
StudentPtr curr = list, prev = NULL;
if(curr->student_ID==id)
{
list=list->next;
free(curr);
curr=list;
}
while (curr != NULL)
{
if (curr->student_ID == id)
{
if (prev == NULL)
{
list = curr->next;
}
else
{
prev->next = curr->next;
}
free(curr);
return list;
}
prev = curr;
curr = curr->next;
}
return list;
}
StudentPtr insert(int id,double hw,int exam,StudentPtr list)
{
StudentPtr cell=creatnew(id,hw,exam);
if(cell==NULL)
{
free(list);
exit(1);
}
cell->next=list;
list=cell;
return list;
}
StudentPtr creatnew(int id,double hw,int exam)
{
StudentPtr cell=(StudentPtr)malloc(sizeof(Music_student));
if(cell == NULL)
{
printf("Allocation failed!");
return NULL;
}
cell->exam_grade=exam;
cell->student_ID=id;
cell->hw_average=hw;
cell->final_grade=(my_round(0.7*cell->exam_grade)+my_round(cell->hw_average*0.3));
cell->next=NULL;
return cell;
}
im trying to enter 4 or 5 nodes in it and the use lilprint to print some info about the linked list.
when i enter some nodes and then delete the firstnode(only delting the first one does this problem)
the program doesnt delete it fully so it only delets the student_id in that node and returns the rest. so when i print it it prints normally but the student_id is trash value .
This definition and using of N with the magic number 10 along with another magic number 15
#define N 10
//...
while (N<15)
//...
makes your code unclear.
Also this typedef declaration for a pointer
typedef struct music_student *StudentPtr;
is a bad idea.
For example if you will write const StudentPtr then it will be equivalent to struct music_student * const instead of const struct music_student * and the last type specification should be used in the function lilPrint because within the function the list is not changed.
void lilPrint( const struct music_student *list);
And by the way you forgot to place the function declaration before main.
In the function insert this statement
free(list);
does not make sense because it does not free all the allocated memory.
The function Del can invoke undefined when the list is empty due to using a null pointer accessing memory as for example in this statement
if(curr->student_ID==id)
Also it seems the list should store nodes with unique student_ID but the function Del is designed such a way that it deletes at most two nodes with the same student_ID due to the following while loop after the first if statement
if(curr->student_ID==id)
{
list=list->next;
free(curr);
curr=list;
}
while (curr != NULL)
{
if (curr->student_ID == id)
{
if (prev == NULL)
{
list = curr->next;
}
else
{
prev->next = curr->next;
}
free(curr);
return list;
}
//...
That is the function should delete either all nodes with the same student_ID or only one node with the given id.
And in main you forgot to assign the returned pointer to the pointer list
Del(id,list);
Instead you need to write
list = Del(id,list);
This question already has answers here:
How do I modify a pointer that has been passed into a function in C?
(7 answers)
Closed 3 years ago.
I am currently trying to implement a Linked List in C. However, my function to create the head is not working apparently, since my other function to add a new node throws a dereferencing null pointer exception. Also, the size variable that keeps the amount of nodes is not being increased. Here is my full code.
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <math.h>
#include <time.h>
typedef struct node {
int val;
struct node* next;
} Node;
void printView(int);
bool terminate();
void createHead(Node*, int);
void addNext(Node*, int);
int main()
{
srand(time(NULL));
int size = 0;
Node* head = NULL;
bool created = false;
bool end = false;
while (!end)
{
printView(size);
int choice;
scanf_s("%d", &choice);
switch (choice)
{
case 1:
{
if (!created)
{
createHead(head, size);
created = true;
}
else
printf("The head has already been created \n");
break;
}
case 2:
{
if (created)
addNext(head, size);
else
printf("The head needs to be created first \n");
break;
}
case 0:
{
bool t = terminate();
if (t)
end = true;
break;
}
}
}
return 0;
}
void printView(int size)
{
printf("Welcome to Linked Lists! - %d Nodes in List\n", size);
printf(" Type 1 to create a head \n");
printf(" Type 2 to create a new node \n");
printf(" Type 0 to exit \n");
}
bool terminate() //Exit
{
int save;
printf("Would you like to save your Linked List? \n(Enter 1 to save or 0 for not to save) \n");
scanf_s("%d", &save);
if (save == 1)
{
printf("The Linked List has been saved. It will show up next time you start the program \n");
}
else if (save == 0)
printf("Goodbye! \n");
else
{
printf("Please type a valid option \n");
return false;
}
return true;
}
void createHead(Node* head, int size)
{
head = malloc(sizeof(Node));
if (head == NULL) {
printf("Failed to create head, aborting operation \n");
return;
}
printf("Type a value for the new node: \n(It must be an integer / Type 0 to assign a random number) \n");
int value; scanf_s("%d", &value);
if (value == 0)
{
value = rand() % 11;
head->val = value;
printf("Value set to: %d \n", value);
}
else
head->val = value;
head->next = NULL;
size++;
}
void addNext(Node* node, int size)
{
Node* current = node;
while (current->next != NULL)
current = current->next;
current->next = malloc(sizeof(Node));
if (current->next == NULL)
{
printf("Failed to create new node, aborting operation \n");
return;
}
printf("Type a value for the new node: \n(It must be an integer / Type 0 to assign a random number) \n");
int value; scanf_s("%d", &value);
if (value == 0)
{
value = rand() % 11;
current->val = value;
printf("Value set to: %d \n", value);
}
else
current->val = value;
current->next = NULL;
size++;
}
The function create_head only modifies its arguments, not the variables in the calling function main. You should change the prototype to bool createHead(Node **headp, int *sizep) and update the values indirectly`.
There are other problems:
some include files are missing
the same problem in add_next() prevents size from getting updated in main.
passing the address of head to addNext removes the need for a separate function to create the initial list node.
it would be safer to define a List structure with a head and a size fields and pass that to the different functions.
Here is a modified version:
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
typedef struct node {
int val;
struct node *next;
} Node;
void printView(int size);
bool terminate(void);
bool createHead(Node **headp, int *sizep);
bool addNext(Node **headp, int *sizep);
int main() {
srand(time(NULL));
int size = 0;
Node *head = NULL;
bool created = false;
bool end = false;
while (!end) {
printView(size);
int choice;
scanf_s("%d", &choice);
switch (choice) {
case 1:
if (!created) {
created = createHead(&head, &size);
} else {
printf("The head has already been created \n");
}
break;
case 2:
if (created)
addNext(&head, &size);
else
printf("The head needs to be created first \n");
break;
case 0:
end = terminate();
break;
}
}
}
return 0;
}
void printView(int size) {
printf("Welcome to Linked Lists! - %d Nodes in List\n", size);
printf(" Type 1 to create a head \n");
printf(" Type 2 to create a new node \n");
printf(" Type 0 to exit \n");
}
bool terminate(void) {
int save = 0;
printf("Would you like to save your Linked List? \n"
"(Enter 1 to save or 0 for not to save) \n");
scanf_s("%d", &save);
if (save == 1) {
// XXX: save the list
printf("The Linked List has been saved. It will show up next time you start the program \n");
} else if (save == 0) {
printf("Goodbye! \n");
} else {
printf("Please type a valid option \n");
return false;
}
return true;
}
bool createHead(Node **headp, int *sizep) {
Node *head = malloc(sizeof(Node));
if (head == NULL) {
printf("Failed to create head, aborting operation \n");
*headp = head;
*sizep = 0;
return false;
}
printf("Type a value for the new node: \n"
"(It must be an integer / Type 0 to assign a random number) \n");
int value;
scanf_s("%d", &value);
if (value == 0) {
value = rand() % 11;
printf("Value set to: %d \n", value);
}
head->val = value;
head->next = NULL;
*headp = head;
*sizep = 1;
return true;
}
bool addNext(Node **headp, int *sizep) {
Node *new_node = malloc(sizeof(Node));
if (new_node == NULL) {
printf("Failed to create new node, aborting operation \n");
return false;
}
printf("Type a value for the new node: \n(It must be an integer / Type 0 to assign a random number) \n");
int value;
scanf_s("%d", &value);
if (value == 0) {
value = rand() % 11;
printf("Value set to: %d \n", value);
}
current->val = value;
current->next = NULL;
if (*headp == NULL) {
*headp = new_node;
} else {
Node *current = *headp;
while (current->next != NULL)
current = current->next;
current->next = new_node;
}
*sizep += 1;
return true;
}
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
#include <stdio.h>
#include <stdlib.h>
typedef struct nodeNum
{
int num;
struct nodeNum *next;
} t_nodeNum;
// Functions declaration ----------------------------
int menu(); // display menu and return choice
t_nodeNum* addition(t_nodeNum *node, int n);
void print_list(t_nodeNum *node);
// ----------------------------------------------------
// Main program to test link list functions
int main()
{
int choice;
t_nodeNum *pnode = NULL;
t_nodeNum *head = NULL;
t_nodeNum *temp = NULL;
int numAdd = 0;
int len = 0;
int first = 1;
do
{
choice = menu();
switch (choice)
{
case 1:
{
printf("Please enter number : \n");
scanf("%d", &numAdd);
if (first)
{
pnode = (t_nodeNum *)malloc(sizeof(t_nodeNum));
if (pnode == NULL)
{
printf("\n Error in allocation\n");
exit(0);
}
pnode->num = numAdd;
pnode->next = NULL;
first = 0;
head = pnode;
}
pnode = addition(pnode, numAdd);
break;
}
case 4:
{
printf("\n Print List: ");
print_list(head);
break;
}
}
}
while (choice != 5);
return 0;
}
// function menu display menu and return choice
int menu()
{
int choice = 0;
do
{
printf("Please choose option to do: \n");
printf("1. addition\n");
printf("2. deletion\n");
printf("3. search\n");
printf("4. print\n");
printf("5. exit\n");
printf("\n option = ");
scanf("%d", &choice);
}
while (choice < 1 || choice > 5);
return choice;
}
// function addition to add item to linked list in recursion
t_nodeNum* addition(t_nodeNum *p, int numAdd)
{
int len = 0;
if (p == NULL)
{
p = (t_nodeNum *)malloc(sizeof(t_nodeNum));
if (p == NULL)
{
printf("\n Error in allocation\n");
exit(0);
}
p->num = numAdd;
p->next = NULL;
}
else
{
p = addition(p->next, numAdd);
}
return (p);
}
// function print_list to print linked list in recursion
void print_list(t_nodeNum *head)
{
printf("%d ", head->num);
if (head->next == NULL)
{
printf("\n");
return;
}
print_list(head->next);
}
There is problem with the addition function it does not work correctly to add new item to the linked list and I does not know what is wrong please help
After adding new items and do print list it display only the first item
In you main function -
pnode = addition(pnode, numAdd);
instead of pnode you need to pass pnode->next -
pnode = addition(pnode->next, numAdd);
Problem with first call is that pnode is not NULL so it just adds new element at head position replacing previous value and returns.
Therefore, new node is not being created.
I'm trying to write a program that enqueue, dequeue, delete a chosen number and print the list. I have problems with the dequeue that i think is because of the menu part when you write a number, I've tried to fix it but the it removes the last number and not the first. The print shows the wrong number and when I tried to solve that problem I got the same problem as I had in dequeue. It's sometinhg wrong in delete but i cant figure it out.
I appreciate all the help i can get
edit:
I've changed it a lot and now everything else works except delete. I want delete to find the number i enter and delete it.
queue.c
#include <stdio.h>
#include <stdlib.h>
#include<conio.h>
struct node
{
int info;
struct node *ptr;
int next;
}*first, *last, *temp, *first1;
void enq(int data);
void deq();
void empty();
void display();
void create();
void delete_queue();
int count = 0;
void main()
{
int no, ch;
printf("\n 1 - Enqueue");
printf("\n 2 - Dequeue");
printf("\n 3 - Delete");
printf("\n 4 - Display");
printf("\n 5 - Exit");
create();
while (1)
{
printf("\n Enter choice : ");
scanf_s("%d", &ch);
switch (ch)
{
case 1:
printf("Enter data : ");
scanf_s("%d", &no);
enq(no);
break;
case 2:
deq();
break;
case 3:
printf("Enter data : ");
scanf_s("%d", &no);
delete_queue(no);
case 4:
display();
break;
case 5:
exit(0);
default:
printf("Wrong choice, Please enter correct choice ");
break;
}
}
}
void create()
{
first = last = NULL;
}
void enq(int data)
{
if (last == NULL)
{
last = (struct node *)malloc(1 * sizeof(struct node));
last->ptr = NULL;
last->info = data;
first = last;
}
else
{
temp = (struct node *)malloc(1 * sizeof(struct node));
last->ptr = temp;
temp->info = data;
temp->ptr = NULL;
last = temp;
}
count++;
}
void display()
{
first1 = first;
if ((first1 == NULL) && (last == NULL))
{
printf("Queue is empty");
return;
}
while (first1 != last)
{
printf("%d ", first1->info);
first1 = first1->ptr;
}
if (first1 == last)
printf("%d", first1->info);
}
void deq()
{
first1 = first;
if (first1 == NULL)
{
printf("\n Error: Trying to display elements from empty queue");
return;
}
else
if (first1->ptr != NULL)
{
first1 = first1->ptr;
printf("\n Dequed value : %d", first->info);
free(first);
first = first1;
}
else
{
printf("\n Dequed value : %d", first->info);
free(first);
first = NULL;
last = NULL;
}
count--;
}
void delete_queue()
{
int retval = -1;
if (first)
{
struct node *temp = first;
first = first->next;
if (!first) { last = first; }
retval = temp->next;
free(temp);
}
return retval;
}
void empty()
{
if ((first == NULL) && (last == NULL))
printf("\n Queue empty");
else
printf("Queue not empty");
}
Let me start with a few points of advice about design and style:
I do not recommend this:
typedef struct node {
int data;
struct node *next;
} node;
you are typedefing struct node to node. while it is not illegal, it is confusing. I would recommend
typedef struct _node {
int data;
struct _node *next;
} node;
Additionally, I do not recommend use of global variable with static storage class to keep track of your queue, instead you should create a queue in your main. Use global variables only when you have compelling reasons to do so.
Do remember that when you get rid of your global variable, you will need to rewrite your enqueue dequeue delete etc... functions to take in a queue_c * as parameter (because it wont have access to queueref any more)
Now for the reason that your code is not working properly and #Weather Vane alluded to:
you have a big problem in your delete function.
int delete(int data)
{
int result = 0;
node *curr_ptr; //pointer just created and not initialized
node *prev_ptr; //not initialized
node *temp_ptr; //not initialized
while (curr_ptr != NULL)
//curr_ptr was just created, where is it pointing? fatal error here
{
//inside this block lets imagine curr_ptr is pointing to a valid
//node in the global queue
if (curr_ptr->data == data)
{
result = 1;
if (curr_ptr->next != NULL)
{
temp_ptr = curr_ptr;
//both pointers point to the same thing
destroy_node(temp_ptr);
//now you just destroyed both nodes
prev_ptr->next = curr_ptr->next;
//the first time this block runs prev_ptr is uninitialized
//so prev_ptr->next will most likely seg fault
//this happens for example if you call this function
//for the first time with a long queue
}
else
{
temp_ptr = curr_ptr;
queueref.last = prev_ptr;
prev_ptr->next = NULL;
destroy_node(temp_ptr);
//again you are destroying both curr_ptr and temp_ptr
}
}
curr_ptr = curr_ptr->next;
prev_ptr = prev_ptr->next;
return result;
}
}
Perhaps it would be better if you think edge cases very carefully and rethink some of the logic from scratch. (test edge cases as you go)