hashtable printing slightly out of order - c

I'm trying to create a basic hash table in c that takes in integers. I'm trying to get it to print the numbers 1-10, in order. Everything compiles and seems fine when I input integers, but when I use the printlist function I made, it print 10,1,2,3,4,5,6,7,8,9. I've tried for hours but I can't figure out what's causing it.
#include <stdlib.h>
#include <stdio.h>
typedef struct node {
struct node* next;
int data;
}node;
void printlist(node *ht[]);
node* insert_node(node *ht[]);
int main() {
int index = 0;
int input;
int option;
node* ht[10] = { NULL };
do {
printf("Press 1 to input a node\n");
printf("Press 2 to print the list\n");
printf("Press 3 to exit:\n");
printf("Select Option: ");
scanf("%i", &option);
if (option == 1) {
insert_node(ht);
continue;
}
if (option == 2) {
printlist(ht);
}
} while (option != 3);
}
void printlist(node* ht[]) {
node *prvptr;
node *curptr;
int j = 9;
int index = 0;
for (index = 0; j >= index; index++) {
curptr = ht[index];
curptr = curptr->next;
while (curptr != NULL) {
printf("%i\n", curptr->data);
curptr = curptr->next;
break;
}
}
}
node* insert_node(node* ht[]) {
node *newptr;
node *curptr;
node *prvptr;
node *head;
int count = 0;
int choice;
int index = 0;
int input = 0;
printf("Input negative 1 to cancel\n");
printf("What number would you like to add to the list?: ");
scanf("%i", &input);
index = input % 10;
while (input != -1) {
newptr = (node*)malloc(sizeof(node)); // creates a node for the input data
newptr->data = input;
newptr->next = NULL;
if (ht[index] == NULL) { // if there is no head
ht[index] = (node*)malloc(sizeof(node));
ht[index]->data = NULL;
ht[index]->next = newptr;
count++;
}
else {
curptr = ht[index];
while (curptr->next != NULL) {
prvptr = curptr;
curptr = curptr->next;
if (curptr->data > input) { // if in-between two nodes
prvptr->next = newptr;
newptr->next = curptr;
break;
}
else if (curptr->next == NULL) { // if at the end of the list
curptr->next = newptr;
break;
}
}
}
printf("Input negative 1 to cancel\n");
printf("What number would you like to add to the list?: ");
scanf("%i", &input);
index = input % 10;
}
return ht;
}

Your index calculation is index = input % 10;. The number 10, mod 10, is 0, so it goes in the first index (index 0) of your table, before 1-9 (which would go in indices 1 through 9). Since your printer prints the buckets in order from index 0 to 9 inclusive, 10 is output first.
The nature of hash tables is to have limited ordering (most languages and hash table libraries give no guarantees at all on the iteration order of a hash table); I wouldn't be bothered by 10 happening to appear first in the output.

Just as #ShadowRanger mentioned, it is not wrong for the 10 to come out first.
Instead, I see another error in your printlist code :
while (curptr != NULL) {
printf("%i\n", curptr->data);
curptr = curptr->next;
break;
}
the break statement should not be there, you will end up printing just one of your elements per hash value.

Related

C program with linked list to add/delete integers & calculate avg [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 11 months ago.
Improve this question
I am trying to modify this code to add new numbers to the list with symbol "+" and delete with symbol "-". If the number entered is even, it should insert the number at the start of the list, if its odd, it should insert it at the end. The program will end after 0 (+0 or -0) is entered. Here is my code:
#include <stdio.h>
#include <stdlib.h>
typedef struct node{
int data;
struct node *ptr;
} node;
node * insert(node *head, int num)
{
node *temp = malloc(sizeof(node));
temp->data = num;
if (head == NULL || head->data > num)
{
temp->ptr = head;
head = temp;
}
else
{
node *current = head;
while ((current->ptr != NULL) && !(num < current->ptr->data))
{
current = current->ptr;
}
temp->ptr = current->ptr;
current->ptr = temp;
}
return head;
}
node * delete_if_less( node *head, int data )
{
while ( head != NULL && head->data < data )
{
node *temp = head;
head = head->ptr;
free( temp );
}
if ( head != NULL )
{
for ( node *current = head; current->ptr != NULL; )
{
if ( current->ptr->data < data )
{
node *temp = current->ptr;
current->ptr = current->ptr->ptr;
free( temp );
}
else
{
current = current->ptr;
}
}
}
return head;
}
void free_list(node *head) {
node *prev = head;
node *cur = head;
while(cur) {
prev = cur;
cur = prev->ptr;
free(prev);
}
}
int main(){
int num, min;
node *head, *p;
head = NULL;
do {
printf("Enter a number: ");
scanf("%d",&num);
if(num) {
head = insert(head, num);
for ( p = head; p != NULL; p = p->ptr )
{
printf("%d ", p->data);
}
printf("\n");
}
} while(num);
p = head;
printf("\nThe entered numbers are:\n");
while(p) {
printf("%d ", p->data);
p = p->ptr;
}
free_list(head);
head = delete_if_less( head, num );
if ( num != 0 ) {
printf( "There are deleted %zu nodes.\n", num );
}
printf("\nEnter minimum: ");
scanf("%d", & min);
return 0;
}
I want it then to calculate 1) the sum of all added integers 2) the sum of all deleted integers 3) the total sum of the remaining numbers of the list 4) the number of integers left and 5) the arithmetic average of the remaining numbers. The input should look like something like this:
Enter +/- to add/del a number: +1
1
Enter +/- to add/del a number: +2
2 1
Enter +/- to add/del a number: +3
2 1 3
Enter +/- to add/del a number: +1
2 1 3 1
Enter +/- to add/del a number: +5
2 1 3 1 5
Enter +/- to add/del a number: -4
Numbers not in list.
2 1 3 1 5
Enter +/- to add/del a number: -3
2 1 1 5
Enter +/- to add/del a number: -1
2 1 5
Enter +/- to add/del a number: +0
2 1 5
add sum: 13
del sum: 5
total sum: 8
elements: 3
average: 2.67
Can anyone help me with this? I would appreciate it alot. :)
Here is my approach to your code!
I used linked lists with a sentinel to optimize a bit. Also since in your example you wanted to keep the information about the deleted values, there are actually two linked lists in the program, one for present values, and another for bin values.
It works exactly as you have described in the input section,though I have added several more functionalities.
Here are the possible inputs:
in each of them n is an integer from 0 to 9
+on -> adds n to a linked list
-on -> deletes n from a linked list if it exists, if n not present prints an error message
-an -> deletes all occurrences of n from a linked list, if n not present prints an error message
+m -> deletes the maximum of a linked list
-m -> deletes the minimum of a linked list
0 -> terminates the function
Of course you could parse it differently to include larger int values but I guess I will leave that part to you!
At each operation the two linked lists will be printed out on the terminal so you can see the result of your operation and the current state of the two lists. If your message did not match the parsing, an error will be raised and will be printed on the terminal. Same goes for deleting a value that does not exist in the linked list.
After entering 0 the program will calculate different properties of the list based on what you have asked in your example.
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <err.h>
#include <errno.h>
#include <string.h>
#include <limits.h>
typedef struct node
{
int value;
struct node *next;
} node;
// Prints a string of characters.
static inline void print(const char* f, ...)
{
va_list args;
va_start(args, f);
vprintf(f, args);
va_end(args);
}
// Prints a string of characters followed by a new line.
static inline void println(const char* f, ...)
{
va_list args;
va_start(args, f);
vprintf(f, args);
va_end(args);
printf("\n");
}
static inline void* mem_alloc(size_t size)
{
void* p = malloc(size);
if (p == NULL)
{
err(EXIT_FAILURE, "Problem with malloc().");
}
return p;
}
// Verify if node is empty
int node_is_empty(node * head)
{
return head == NULL;
}
// Verify if node is not empty
int node_is_not_empty(node * head)
{
return head != NULL;
}
//Builds the sentinell of the node structure
node* node_build_sentinel()
{
// Creates the sentinel.
node* head = mem_alloc(sizeof(node));
head->value = 0;
head->next = NULL;
// Returns the head of the node which is the sentinell.
return head;
}
//Prints the contents of a node
void node_print(node* head)
{
print("{");
while(head->next)
{
head = head->next;
print(" %d", head->value);
}
println(" }");
}
//Frees the allocated node
void node_free(node* head)
{
node* previous;
while (head)
{
previous = head;
head = head->next;
free(previous);
}
}
// Inserts a value right after the head
/*
HEAD -> 1 -> 2 -> ..... -> 8
node_insert_beg(node* HEAD, int 42);
HEAD -> 42 -> 1 -> 2 -> ..... -> 8
*/
void node_insert_beg(node* head, int value)
{
node* tmp = mem_alloc(sizeof(node));
tmp->value = value;
tmp->next = head->next;
head->next = tmp;
}
// Inserts a value right after the head
/*
HEAD -> 1 -> 2 -> ..... -> 8
node_insert_end(node* HEAD, int 42);
HEAD -> 1 -> 2 -> ..... -> 8 -> 42
*/
void node_insert_end(node* head, int value)
{
node* tmp = mem_alloc(sizeof(node));
for (; node_is_not_empty(head->next); head = head->next)
{
//This loop runs to the last node and quits with head being that last node
continue;
}
tmp->value = value;
tmp->next = head->next;
head->next = tmp;
}
//Inserts odd values to the end and even values to the beginning
void node_insert_num(node* head, int value)
{
//odd
if(value % 2)
{
node_insert_end(head, value);
}
//even
else
{
node_insert_beg(head, value);
}
}
//Extracts the minimum value of the node (in other words deletes it from the node)
void node_extract_min(node* list,node *sup)
{
node *before_min = list;
while (list->next != NULL)
{
if (list->next->value < before_min->next->value)
{
before_min = list;
}
list = list->next;
}
node *output = before_min->next;
before_min->next = before_min->next->next;
output->next = NULL;
while (sup->next!=NULL)
{
sup = sup->next;
}
sup->next = output;
}
//Extracts the maximum value of the node (in other words deletes it from the node)
void node_extract_max(node* list, node* sup)
{
node *before_max = list;
while (list->next != NULL)
{
if (list->next->value > before_max->next->value)
{
before_max = list;
}
list = list->next;
}
node *output = before_max->next;
before_max->next = before_max->next->next;
output->next = NULL;
while (sup->next!=NULL)
{
sup = sup->next;
}
sup->next = output;
}
//Deletes the first occurence of value in node
int node_delete_first_occurence(node* head, node* sup, int value)
{
int seen = 0;
node *tmp = head;
while (head->next != NULL)
{
if (head->next->value == value)
{
tmp = head;
seen+=1;
break;
}
head = head->next;
}
if(seen == 0)
{
return seen;
}
node *output = head->next;
tmp->next = tmp->next->next;
output->next = NULL;
while (sup->next!=NULL)
{
sup = sup->next;
}
sup->next = output;
return seen;
}
//Deletes all occurences of value in node
int node_delete_all_occurences(node* head, node* sup, int value)
{
int seen = 0;
node *tmp = head;
while (head->next != NULL)
{
if (head->next->value == value)
{
seen+=1;
tmp = head;
node *output = head->next;
tmp->next = tmp->next->next;
output->next = NULL;
while (sup->next!=NULL)
{
sup = sup->next;
}
sup->next = output;
continue;
}
head = head->next;
}
return seen;
}
//Get a node at index if index invalid return NULL
//DOES NOT DELETE THE NODE
node * node_get_at(node* node, unsigned long index)
{
while (node != NULL && index > 0)
{
node = node->next;
index--;
}
if (node != NULL)
{
node = node->next;
}
return node;
}
int* node_sum(node * head)
{
int * sum_elem = malloc(sizeof(int)*2);
int sum = 0;
int elements = 0;
while (head->next != NULL)
{
elements+=1;
sum += head->next->value;
head = head->next;
}
sum_elem[0] = sum;
sum_elem[1] = elements;
return sum_elem;
}
int main()
{
node * present_node = node_build_sentinel();
node * deleted_nodes = node_build_sentinel();
char message[4];
while (1)
{
printf("Enter +/- followed by type (o = one/a = all/m = min or max) followed by the number to add/del a number or 0 to quit the app:");
scanf("%3s",message);
if(message[0] == '+')
{
if(message[1] == 'o')
{
node_insert_num(present_node,message[2] - '0');
node_print(present_node);
node_print(deleted_nodes);
continue;
}
if(message[1] == 'm')
{
node_extract_max(present_node,deleted_nodes);
node_print(present_node);
node_print(deleted_nodes);
continue;
}
if(message[1] == 'a')
{
printf("Invalid syntax on opperand 2 after + (no a is possible) please try again!\n");
}
else
{
printf("Invalid syntax on opperand 2 after + please try again!\n");
}
continue;
}
if(message[0] == '-')
{
if(message[1] == 'o')
{
int err = node_delete_first_occurence(present_node,deleted_nodes,message[2] - '0');
if(err == 0)
{
printf("The number to delete was not present in the node!\n");
}
node_print(present_node);
node_print(deleted_nodes);
continue;
}
if(message[1] == 'a')
{
int err = node_delete_all_occurences(present_node,deleted_nodes,message[2] - '0');
if(err == 0)
{
printf("The number to delete was not present in the node!\n");
}
node_print(present_node);
node_print(deleted_nodes);
continue;
}
if(message[1] == 'm')
{
node_extract_min(present_node,deleted_nodes);
node_print(present_node);
node_print(deleted_nodes);
continue;
}
else
{
printf("Invalid syntax on opperand 2 after - please try again!\n");
}
continue;
}
if(message[0] == '0')
{
break;
}
else
{
printf("Invalid syntax on opperand 1 please try again!\n");
}
}
int * present_sum_elem = node_sum(present_node);
printf("The sum of present node: %d \n",present_sum_elem[0]);
printf("The number of elements in present node: %d\n",present_sum_elem[1]);
if(present_sum_elem[1]!=0)
{
printf("The average of the present node %4f \n", (float)present_sum_elem[0]/(float)present_sum_elem[1]);
}
int * deleted_sum_elem = node_sum(deleted_nodes);
printf("The sum of deleted node: %d \n",deleted_sum_elem[0]);
printf("The number of elements in deleted node: %d\n",deleted_sum_elem[1]);
if(deleted_sum_elem[1] != 0)
{
printf("The average of the deleted node %4f \n", (float)deleted_sum_elem[0]/(float)deleted_sum_elem[1]);
}
free(present_sum_elem);
free(deleted_sum_elem);
node_free(present_node);
node_free(deleted_nodes);
return 0;
}

Skip list getting lost when either inserting with a new level or adding a new node to lower level

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <limits.h>
#define Malloc(n, type) (type *)malloc((unsigned)((n) * sizeof(type)))
#define Realloc(ptr, n, type) (type *)realloc(ptr, (n) * sizeof(type))
typedef struct Node
{
int key;
struct Node *next;
struct Node *down;
} Node;
typedef struct
{
int level;
struct Node *header;
} skiplist;
int level()
{
/*
This function takes the coin flip and decides the level of the node with each
level having a probability of 0.25.
arg: void
return: a number from the set {1,2,3, 4}
*/
int level = 1;
for (int i = 0; i < 3; i++)
{
unsigned int coin = (unsigned int)rand();
coin = coin % 2;
if (coin)
{
level++;
}
else
break;
}
return level;
}
skiplist skip_list_init();
Node *Traverse_Express(Node *, int);
Node *skip_list_search(skiplist, int);
Node *insert_level(Node *, int, int, int);
void skip_list_insert(skiplist *, int);
void skip_print(skiplist);
int main()
{
srand(time(0));
int arr[10000];
for (int i = 0; i < 10; i++)
{
arr[i] = (int)rand();
}
printf("The array is initialised\n");
skiplist list;
list = skip_list_init();
printf("The Skip list is initialised\n");
if (list.header == NULL)
{
printf("List is null\n");
}
for (int i = 0; i < 10; i++)
{
skip_list_insert(&list, arr[i]);
printf("The %d element is initialised with key: %d\n", i, arr[i]);
}
printf("The skip list is:\n");
skip_print(list);
return 0;
}
void skip_print(skiplist list)
{
/*
The function prints the skip list level-wise.
arg: list
return: none
*/
Node *temp = list.header;
int count = 0;
for (int i = list.level; i > 0; i--)
{
printf("The Keys at level %d:\n", i);
while (NULL != temp->next)
{
printf("%d ->", temp->key);
temp = temp->next;
}
printf("%d\n", temp->key);
int dummy = count;
temp = list.header;
while (dummy)
{
temp = temp->down;
dummy--;
}
count++;
}
}
skiplist skip_list_init()
{
/*
This function creates the first node in the skip list with key value
to be negative infinity and level of the list =1.
arg: None
return: Skiplist initialised with a Node having key as INT_MIN.
*/
skiplist list;
Node *head;
if (NULL == (head = Malloc(1, Node)))
{
exit(1);
}
list.header = head;
list.level = 1;
head->key = INT_MIN;
head->next = NULL;
head->down = NULL;
return list;
}
Node *skip_list_search(skiplist list, int key)
{
/*
The function returns a pointer to the either the key itself if present
or the key immediatedly smaller than the searched key.
arg:
list:The skiplist to be searched. Type: skiplist
key: A key to be searched. Type: int.
return: Type: Node pointer
A pointer to the searched key or immediately smaller it.
*/
if (list.header == NULL)
exit(1);
else
skip_print(list);
int level = list.level; // Number of levels already present in the list
Node *curr = list.header;
printf("Inside Skip search\n");
printf("The value of level %d\n", level);
for (; level > 0; level--)
{
curr = Traverse_Express(curr, key);
if ((curr->key == key) && (INT_MIN != curr->key))
{
return curr;
}
if (NULL != curr->down)
curr = curr->down;
}
printf("The value at current node %d\n", curr->key);
printf("Leaving Skip_search\n");
return curr;
}
Node *Traverse_Express(Node *temp, int key)
{
printf("On the express way\n");
printf("We are searching the key: %d\n", key);
while (key > temp->key && NULL != temp->next)
{
printf("Loop of expressway\n");
printf("The current key : %d\n", temp->key);
if (key >= temp->next->key)
temp = temp->next;
else
break;
}
printf("Left the express way\n");
return temp;
}
Node *insert_level(Node *nod, int key, int lev, int list_lev)
{
/*
Inserting the key till the required level
arg:
nod: a pointer to the exsiting skip list
key: key to be inserted
lev: the level of the key
list_lev: the number of levels in the given skiplist
return: A Node pointer to the head of the skiplist with the key
inserted to the existing list.
*/
Node *temp1 = nod, *temp3 = NULL;
printf("\nStarting of insert at level procedure\n");
// Procedure to cut-off the extra levels in the list if any
if (lev < list_lev)
{
for (int i = list_lev - lev; i > 0; i--)
{
printf("Searching on the level: %d\n", i + lev);
temp1 = Traverse_Express(temp1, key);
temp1 = temp1->down;
}
}
printf("The value of first node: %d\n", temp1->key);
// Procedure to insert from the required level till level 1
for (int i = 0; i < lev; i++)
{
Node *temp2 = Malloc(1, Node);
temp2->key = key;
temp2->next = NULL;
temp2->down = NULL;
temp1 = Traverse_Express(temp1, key);
printf("Temp1 current key:%d\n", temp1->key);
if (NULL == temp1->next)
{
temp1->next = temp2;
printf("Node inserted at level: %d\n", lev - i);
}
else
{
printf("Entered the else procedure\n");
temp2->next = temp1->next;
temp1->next = temp2;
printf("%d\n", temp1->next->key);
}
if (i > 0)
{
temp3->down = temp2;
}
temp1 = temp1->down;
temp3 = temp2;
/*
free(temp2);
if(temp3==NULL)
{
printf("did a fuck up\n");
exit(1);
}*/
}
skiplist list;
// list = skip_list_init(list);
list.header = nod;
list.level = list_lev;
printf("Printing skip list from insert level\n");
skip_print(list);
printf("End insert level procedure\n\n\n");
temp1 = temp3 = NULL;
return nod;
free(temp1);
free(temp3);
}
void skip_list_insert(skiplist *list, int key)
{
/*
This function finds the key value and if already present, then returns back
else it inserts the key at its right place.
arg: a skilplist by reference and a key
return: None
*/
printf("Inside skip_list_insert\n");
Node *req = skip_list_search(*list, key);
printf("The value returned by skip search %d\n", req->key);
if (key == req->key)
{
printf("Key %d is already present in skip list\n", key);
}
Node *temp1 = list->header;
int list_lev = list->level;
printf("The list level = %d\n", list_lev);
int lev = level();
printf("The prob level %d\n", lev);
Node *hold_prev = NULL;
// creating a skip list if level returned is greater than existing one.
if (lev > list_lev)
{
for (int i = lev - list_lev; i > 0; i--)
{
skiplist l = skip_list_init();
Node *inser = Malloc(1, Node);
printf("The value of i in loop %d\n", i);
inser->key = key;
inser->down = NULL;
inser->next = NULL;
l.header->next = inser;
Node *trans = l.header;
// Zipping the previous levels with new level
while (NULL != hold_prev)
{
trans->down = hold_prev;
trans = trans->next;
hold_prev = hold_prev->next;
}
hold_prev = l.header;
l.header = NULL;
if (hold_prev == NULL)
{
printf("Big Mistake");
exit(1);
}
else
{
printf("You are doing it correct way\n");
}
}
list->header = hold_prev;
list->level = lev - list_lev;
skip_print(*list);
// Returning a pointer to the zeroth element of last level in this list.
while (NULL != hold_prev->down)
{
hold_prev = hold_prev->down;
}
}
// Inserting the node till the min(list_lev, level())
if (list_lev > lev)
{
temp1 = insert_level(temp1, key, lev, list_lev);
}
else
{
temp1 = insert_level(temp1, key, list_lev, list_lev);
}
skiplist l1 = skip_list_init();
l1.header = temp1;
l1.level = list_lev;
skip_print(l1);
printf("\n Now the Zipping procedure with level()>list_lev starts\n");
// Zipping Procedure only if level()>list_lev
if (lev > list_lev)
{
hold_prev->down = temp1;
skiplist l1 = skip_list_init();
l1.header = list->header;
l1.level = lev;
skip_print(l1);
printf("the key at the first node:%d\n", temp1->key);
hold_prev = hold_prev->next;
while (temp1->key != key)
{
temp1 = temp1->next;
printf("Zipping over keys:\n");
printf("Current key: %d\n", temp1->key);
}
hold_prev->down = temp1;
list->level = lev;
}
if (list_lev > lev)
{
list->level = list_lev;
}
printf("\n\n\n");
}
The above is my implementation. I have tried with all my might to debug the code but I am falling to implement a skip list for past 1 month. I genuinely request with pleading hands 🙏🙏🙏 to look into the implementation and please do let me know the fixes, I can do.
It would be a great help. Thank you.
I have tried with all my might to debug the code but I am falling to implement a skip list for past 1 month.
You will have much easier time debugging if you fill the list with some non-random values (you can switch back to random values once the program is working for all hand-coded combinations).
Also fix your comments so they match the code. E.g. here the comments are clearly wrong:
skiplist skip_list_init()
{
/*
This function creates the first node in the skip list with key value
to be negative infinity and level of the list =1.
arg: It takes a list by reference
return: None
*/
There is no arg and the return is not None.
You should avoid making a copy of the list when calling skip_list_search (pass a pointer to the list).
You should avoid this construct:
if (hold_prev == NULL)
{
printf("Big Mistake");
exit(1);
}
else
{
printf("You are doing it correct way\n");
}
It make your code way too long. Instead, do this:
assert(hold_prev != NULL);
Giving your variables meaningful names will also go a long way helping you and others understand the code.
With the value inputs by Gene and Employed Russian, the skip list implementation has a mistake in the function skip_print which unfortunately didn't transverse all the levels of the skip-list.
See here:
int count=0;
and
int dummy = count;
temp = list.header;
while (dummy)
{
temp = temp->down;
dummy--;
}
count++;
When count=0 implies dummy=0. This doesn't let your pointer temp transverse to the bottom level till the next iteration when count=1. Thus, effectively only transversing and printing till list.level-1.
Hence, the implementation doesn't work correctly.
Please incorporate the following code for skip_print:
void skip_print(skiplist list)
{
/*
The function prints the skip list level-wise.
arg: list
return: none
*/
Node *temp = list.header;
int count = 1;
while (temp)
{
Node *n1 = temp;
printf("Printing the keys at level: %d\n", count);
while (NULL != n1->next)
{
printf("%d ->", n1->key);
n1 = n1->next;
}
printf("%d\n", n1->key);
temp = temp->down;
count++;
}
}
The rest of the code seems to be working fine for me.

Problems regarding an multiple choice question program

I have created a program to generate the result of a multiple choice exam. The program was supposed to show the total number of mistakes, blank answers and the number of the question which were answered incorrectly. For the following input:
6
1..223
(Here . means blank answer)
123124
The output was supposed to be:
Your result:
Mistakes: 3
Blanks: 2
Your mistakes are following:
4 5 6
Your blanks are following:
2 3
But the code shows undefined behavior. It seems to go through infinite loop. Expecting solution to my problem shortly. Thanks in advance.
#include <stdio.h>
#include <stdlib.h>
typedef struct node
{
char data;
struct node* next;
}node;
void printNode(node* head)
{
node* local = head;
int i = 0;
if(local -> data == 0)
{
printf("0");
return;
}
while(local != NULL)
{
if(i == 3)
{
i = 0;
printf("\n");
}
printf("%d\t", local -> data);
local = local -> next;
++i;
}
}
void freeNode(node** head)
{
node* temp = (*head);
while((*head) != NULL)
{
(*head) = (*head) -> next;
free(temp);
temp = (*head);
}
}
int main()
{
int n, i, flagB, flagM, blnk, mstk;
blnk = mstk = flagB = flagM = 0;
printf("Enter the number of questions: ");
scanf("%d", &n);
char ques[n], ans[n];
if(n == 0)
return 0;
node* headM = (node*)malloc(sizeof(node));
node* nodeM;
node* headB = (node*)malloc(sizeof(node));
node* nodeB;
printf("Enter your given answers: ");
fflush(stdin);
for(i = 0; i < n; ++i)
{
scanf("%c", &ques[i]);
}
fflush(stdin);
ques[n] = '\0';
printf("Enter the solution: ");
for(i = 0; i < n; ++i)
{
scanf("%c", &ans[i]);
}
ans[n] = '\0';
for(i = 0; i < n; ++i)
{
if(ques[i] == '.')
{
++blnk;
if(flagB == 0)
{
headB -> data = i + 1;
headB -> next = NULL;
nodeB = headB;
continue;
}
nodeB -> next = (node*)malloc(sizeof(node));
nodeB = nodeB -> next;
nodeB -> data = i + 1;
nodeB-> next = NULL;
flagB = 1;
}
else if(ques[i] != ans[i])
{
++mstk;
if(flagM == 0)
{
headM -> data = i + 1;
headM -> next = NULL;
nodeM = headM;
continue;
}
nodeM -> next = (node*)malloc(sizeof(node));
nodeM = nodeM -> next;
nodeM -> data = i;
nodeM-> next = NULL;
flagM = 1;
}
}
printf("Your result:\n\tMistakes: %d\n\tBlanks: %d\n", mstk, blnk);
printf("Your mistakes are follwing:\n");
printNode(headM);
printf("\nYour blanks are follwing:\n");
printNode(headB);
freeNode(&headM);
freeNode(&headM);
return 0;
}
Here are some additional thoughts. What makes your code very convoluted and hard to debug and keep the logic straight is you are mixing your linked-list Add function within the logic of your blanks and mistakes and using special conditions to handle adding the first node and subsequent nodes. This make things difficult to test and debug. If you need to add nodes to a linked-list, then write an add() function that you can thoroughly test and debug before putting it to use in your code.
Your VLAs ques and ans are too short to hold a string of n characters, at minimum they must be n + 1 characters long to provide storage for the nul-termining character that marks the end of the string. Ideally, you will make them at least 2-character longer to also hold the '\n' which will allow you to take input with fgets() rather than looping scanf() a character at a time -- which is just nuts.
You do not need to pass the address of the pointer to freeNode() simply pass a pointer. Sure freeNode() will receive a copy of the pointer -- but it will contain the original address -- and since you don't have to make any changes to that pointer available back to the caller, there is no need to pass the address of the pointer (there won't be any list left to worry about when you are done...)
So putting those pieces together, adding an add() function to add to your linked lists (See Linus on Understanding Pointers for why a pointer-to-pointer is used to iterate to the end), and adding a simple empty_stdin() function to remove the '\n' left in stdin from reading n with scanf() before making calls to fgets() later for ques and ans, you could do:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* simple function to empty stdin to end-of-line */
void empty_stdin (void)
{
int c = getchar();
while (c != '\n' && c != EOF)
c = getchar();
}
typedef struct node
{
int data;
struct node *next;
} node;
node *add(node **head, int v)
{
node **ppn = head, /* pointer to pointer to head */
*pn = *head, /* pointer to head */
*newn = malloc (sizeof *newn); /* allocate new node */
if (!newn) { /* validate allocation */
perror ("malloc-node");
return NULL;
}
newn->data = v; /* initialize members values */
newn->next = NULL;
while (pn) { /* iterate to end of list */
ppn = &pn->next;
pn = pn->next;
}
return *ppn = newn; /* add & return new node */
}
void printNode (node *head)
{
for (; head; head = head->next)
printf (" %d", head->data);
putchar ('\n');
}
void freeNode(node *head)
{
while (head != NULL)
{
node *victim = head;
head = head->next;
free(victim);
}
}
int main()
{
int n, i, blnk, mstk;
blnk = mstk = 0;
node *headM = NULL; /* declare pointers and initialize NULL */
node *headB = NULL;
printf ("Enter the number of questions: ");
/* you must VALIDATE every user-input */
if (scanf ("%d", &n) != 1) {
fputs ("error: invalid integer input.\n", stderr);
return 1;
}
empty_stdin(); /* remove '\n' (and any other chars from user) */
/* before calling fgets() below */
if (n == 0) /* check 0 BEFORE VLA declaration */
return 0;
char ques[2*n], ans[2*n]; /* declare question/answer VLAs, don't skimp */
printf("Enter your given answers: ");
if (!fgets(ques, sizeof ques, stdin)) /* read ques from stdin */
return 1;
ques[strcspn(ques, "\r\n")] = 0; /* trim '\n' from end of ques */
printf("Enter the solution: ");
if (!fgets(ans, sizeof ans, stdin)) /* read ans from stdin */
return 1;
ans[strcspn(ans, "\r\n")] = 0; /* ditto for ans */
for(i = 0; i < n; ++i) /* loop n times */
{
if(ques[i] == '.') /* if blank */
{
add (&headB, i + 1); /* add to list headB */
++blnk; /* increment counter */
}
else if(ques[i] != ans[i]) /* if mistake */
{
add (&headM, i + 1); /* add to list headM */
++mstk; /* increment counter */
}
}
printf ("Your result:\n\tMistakes: %d\n\tBlanks: %d\n"
"Your mistakes are following:\n", mstk, blnk);
printNode(headM);
printf("\nYour blanks are following:\n");
printNode(headB);
freeNode(headM); /* no need to pass the address of the pointer to free */
freeNode(headB); /* there won't be a list left when freeNode is done */
return 0;
}
There is a lot there, so go through it slowly.
Example Use/Output
$ ./bin/llquestions
Enter the number of questions: 6
Enter your given answers: 1..223
Enter the solution: 123124
Your result:
Mistakes: 2
Blanks: 2
Your mistakes are following:
4 6
Your blanks are following:
2 3
(note: in 1..223 and 123124, 5 is not a mistake, the 2 is in the correct position at the end)
Look things over and let me know if you have further questions.
I made some changes to this code, check this out.
#include <stdio.h>
#include <stdlib.h>
typedef struct Node node;
struct Node
{
int data;
struct Node * next;
};
void printNode(node *head)
{
node *local = head;
while (local != NULL)
{
printf("%d ", local->data);
local = local->next;
}
}
void freeNode(node **head)
{
node *temp = (*head);
while ((*head) != NULL)
{
(*head) = (*head)->next;
free(temp);
temp = (*head);
}
}
int main()
{
int n, i, flagB = 0, flagM = 0, blnk = 0, mstk = 0;
blnk = mstk = flagB = flagM = 0;
printf("Enter the number of questions: ");
scanf("%d", &n);
char ques[n], ans[n];
if (n == 0)
return 0;
node *headM = (node*) malloc(sizeof(node));
headM->data = 0;
node *nodeM = headM;
node *headB = (node*) malloc(sizeof(node));
headB->next = 0;
node *nodeB = headB;
printf("Enter your given answers: ");
for (i = 0; i < n; ++i)
{
scanf("%s", &ques[i]);
}
ques[n] = '\0';
fflush(stdin);
printf("Enter the solution: ");
for (i = 0; i < n; ++i)
{
scanf("%s", &ans[i]);
}
ans[n] = '\0';
fflush(stdin);
for (i = 0; i < n; ++i)
{
if (ques[i] == '.')
{ ++blnk;
if (flagB == 0)
{
nodeB->data = i + 1;
nodeB->next = NULL;
flagB = 1;
continue;
}
nodeB->next = (node*) malloc(sizeof(node));
nodeB = nodeB->next;
nodeB->data = i + 1;
nodeB->next = NULL;
}
else if (ques[i] != ans[i])
{ ++mstk;
if (flagM == 0)
{
nodeM->data = i + 1;
nodeM->next = NULL;
flagM = 1;
continue;
}
nodeM->next = (node*) malloc(sizeof(node));
nodeM = nodeM->next;
nodeM->data = i + 1;
nodeM->next = NULL;
//flagM = 1; //You made a mistake here
}
}
nodeM = headM;
nodeB = headB;
printf("Your result:\n\tMistakes: %d\n\tBlanks: %d\n", mstk, blnk);
printf("Your mistakes are following question numbers:\n");
if (mstk != 0)
printNode(headM);
else
printf("No Mistakes\n");
printf("\nYour blanks are following question numbers:\n");
if (blnk != 0)
printNode(headB);
else
printf("No Blanks\n");
freeNode(&headM);
freeNode(&headM);
return 0;
}

Why is C not creating my Linked List head? [duplicate]

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

How do I insert scanf() data into an array of linked list?

I have created an array of linked lists which is organized in four levels (the parameters defined in the case 1 switch statement for party size) that correlate to array[0]-array[3], respectively.
I am trying to find out how to take the users input (from the scanf statement) and push it into its respective index in the array.
Can I get some help figuring out how to implement this strategy after the else logic?
Here is the code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define NODE struct node
struct node
{
char partyname[20];
int partysize;
NODE *next;
};
struct node* array[4]; // array to be inserted into
//
// proto
//
void add_party(char name[], int age);
void delete_party(char name[]);
void list_parties(void);
void change_p_size(void);
//
// globals
//
NODE *head=NULL;
NODE *tail=NULL;
//
// main function
//
int main()
{
int x;
while (1)
{
printf("Enter 1 to add a party\nEnter 2 to remove a party\nEnter 3 for the list of the party\nEnter 4 to quit\n");
// user interface
scanf("%d",&x);
switch(x)
{
char name[20]; //local variables
int size;
case 1:
printf("Party Name: ");
scanf("%s", name);
printf("\nParty Size: ");
scanf("%d", &size);
if(size >= 1 && size <= 2)
{
//put into array[0]
}
else if(size >= 3 && size <= 4)
{
//put into array[1]
}
else if(size >= 5 && size <= 6)
{
//put into array[2]
}
else(size >= 7)
{
//put into array[3]
}
add_party(name, &size)
break;
case 2:
printf("\nSize of party to delete: ");
scanf("%i", &size);
if(size >= 1 && size <= 2)
{
//traverse array[0] and delete
}
else if(size >= 3 && size <= 4)
{
//traverse array[0] and delete
}
else if(size >= 5 && size <= 6)
{
//traverse array[0] and delete
}
else(size >= 7)
{
//traverse array[0] and delete
}
delete_party(size)
break;
case 3:
list_parties();
break;
case 4:
change_partysize();
break;
case 5:
return 0;
default:
continue;
}
}
}
//
//add function
//
void add_party(char *name, int size)
{
//create a new node
NODE *p;
NODE *q;
int i=0;
q = (NODE *)malloc(sizeof(NODE)); // allocate memory the size of the struct
strcpy(q->name,partyname); // (source,destination)
q->size = partysize;
if(head == NULL) // if an empty list, create a head and tail
{
head = q;
tail = head;
q->next = NULL;
return;
}
//traversal
p = head;
while(p != NULL)
{
//check that no repeating names. delete nodes that do have repeating names
if(strcmp(p->name,name) == 0)
{
printf("\nSorry, that name is already taken\n");
free(q);
return;
}
p = p->next; //go to the next node in the list
}
tail->next = q;
q->next = NULL;
tail = q;
}
//
//delete function
//
void delete_party(int size)
{
NODE *p = head;
if(p == NULL)
return;
if(head == tail) // case 1
{
if(head->size <= size)
{
head=NULL;
tail=NULL;
free(p);
}
return;
}
while(p->next->next != NULL)
{
if(p->next->size <= size) // check that its not going too far?
{
p->next=p->next->next;
return;
}
}
if(p->size <= size) // case 2, multiple elements
{
head=p->next;
free(p);
return;
}
if(p->next->size <= size) // case 3, one element
{
node *q=p->next;
p->next=NULL;
free(q);
tail=p;
}
}
//
// list function
//
void list_parties(void)
{
node *p=head;
while(p!=NULL)
{
printf("%s, %d\n", p->name, p->size);
p=p->next;
}
}
Just add a destination parameter to your add_party function which specifies the array location.
Something like
add_party(node *dest, char *name, int age) then pass the location from your switch statementsand then call if like so
if(size >= 1 && size <= 2)
{
add_party(&array[0], name, age);
}
The same with delete function pass the array location as an argument.

Resources