Creating new list of nested structures - c

I'm having a bit of trouble trying to create a new linked list of structures from an old one. The basis of the new linked list is that the dogs that belong to specific breed specified by the user will be added to the new list and all the ones from the old list will not be carried over. I don't have a problem getting one dog into the list but I think something is wrong with my code when I try to add multiple dogs. I assumed that when I created the second temp list that points to the list results that when I added to it it would modify results but that does not seem to be the case. Any direction would be appreciated.
The last function in the code struct container* list_of_breed(char* breed) is the one I seem to be having issues with. Everything else has been working as expected. I believe the else statement is where I seem to be going wrong since when there is only one dog that matches that breed it seems to be able to make the list from them.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#pragma warning(disable: 4996)
// used to create a linked list of containers, each contaning a "dog"
struct container {
struct dog *dog;
struct container *next;
} *list = NULL;
// used to hold dog information and linked list of "checkups"
struct dog {
char name[30];
char breed[30];
struct checkup *checkups;
};
// used to create a linked list of checkups containing "dates"
struct checkup {
char date[30];
struct checkup *next;
};
void flush();
void branching(char);
void helper(char);
void remove_all(struct container*);
void display(struct container*);
void add_dog(char*, char*);
struct dog* search_dog(char*);
void add_checkup(char*, char*);
struct container* list_of_breed(char*);
int main()
{
char ch = 'i';
printf("Dog Adoption Center\n\n");
do
{
printf("Please enter your selection:\n");
printf("\ta: add a new dog to the list\n");
printf("\ts: search for a dog on the list\n");
printf("\tc: add a checkup date for dog\n");
printf("\tb: display list of dogs of breed\n");
printf("\tq: quit\n");
ch = tolower(getchar());
flush();
branching(ch);
} while (ch != 'q');
remove_all(list);
list = NULL;
_CrtDumpMemoryLeaks();
return 0;
}
void flush()
{
int c;
do c = getchar(); while (c != '\n' && c != EOF);
}
void branching(char c)
{
switch (c)
{
case 'a':
case 's':
case 'r':
case 'c':
case 'l':
case 'b':
case 'n': helper(c); break;
case 'q': break;
default: printf("Invalid input!\n");
}
}
void helper(char c)
{
if (c == 'a')
{
char input[100];
printf("\nPlease enter the dog's info in the following format:\n");
printf("name:breed\n");
fgets(input, sizeof(input), stdin);
input[strlen(input) - 1] = '\0';
char* name = strtok(input, ":");
char* breed = strtok(NULL, ":");
struct dog* result = search_dog(name);
if (result == NULL)
{
add_dog(name, breed);
printf("\nDog added to list successfully\n\n");
}
else
printf("\nThat dog is already on the list\n\n");
}
else if (c == 's' || c == 'r' || c == 'c' || c == 'l')
{
char name[30];
printf("\nPlease enter the dog's name:\n");
fgets(name, sizeof(name), stdin);
name[strlen(name) - 1] = '\0';
struct dog* result = search_dog(name);
if (result == NULL)
printf("\nThat dog is not on the list\n\n");
else if (c == 's')
printf("\nBreed: %s\n\n", result->breed);
else if (c == 'c')
{
char date[30];
printf("\nPlease enter the date of the checkup:\n");
fgets(date, sizeof(date), stdin);
date[strlen(date) - 1] = '\0';
add_checkup(name, date);
printf("\nCheckup added\n\n");
}
}
else if (c == 'b')
{
char breed[30];
printf("\nPlease enter the breed:\n");
fgets(breed, sizeof(breed), stdin);
breed[strlen(breed) - 1] = '\0';
struct container* result = list_of_breed(breed);
printf("\nList of dogs with breed type %s:\n\n", breed);
display(result);
remove_all(result);
result = NULL;
}
}
void remove_all(struct container* dogs)
{
struct checkup* temp;
if (dogs != NULL)
{
remove_all(dogs->next);
while (dogs->dog->checkups != NULL)
{
temp = dogs->dog->checkups;
dogs->dog->checkups = dogs->dog->checkups->next;
free(temp);
}
free(dogs->dog);
free(dogs);
}
}
void display(struct container* dogs)
{
struct container* container_traverser = dogs;
if (container_traverser == NULL)
{
printf("\nThere are no dogs on this list!\n\n");
return;
}
while (container_traverser != NULL)
{
printf("Name: %s\n", container_traverser->dog->name);
printf("Breed: %s\n", container_traverser->dog->breed);
printf("Checkups on file: ");
struct checkup* ptr = container_traverser->dog->checkups;
if (ptr == NULL)
{
printf("No checkups documented.");
}
else
{
while (ptr != NULL)
{
printf("\n%s", ptr->date);
ptr = ptr->next;
}
}
printf("\n\n");
container_traverser = container_traverser->next;
}
}
void add_dog(char* name, char* breed)
{
struct dog *tempDog = (struct dog *) malloc(sizeof(struct dog));
strcpy(tempDog->name, name);
strcpy(tempDog->breed, breed);
struct container *tempCont = (struct container *) malloc(sizeof(struct container));
tempCont->dog = tempDog;
tempCont->next = list;
list = tempCont;
}
struct dog* search_dog(char* name)
{
struct container *temp = list;
while (temp != NULL) {
if (strcmp(temp->dog->name, name) == 0) {
return temp->dog;
}
temp = temp->next;
}
return NULL;
}
void add_checkup(char* name, char* date)
{
struct container *tempList = (struct container *) malloc(sizeof(struct container));
tempList = list;
struct checkup *tempCheck = (struct checkup *) malloc(sizeof(struct checkup));
while (tempList != NULL) {
if (strcmp(tempList->dog->name, name) == 0) {
strcpy(tempCheck->date, date);
tempList->dog->checkups = tempCheck;
}
tempList = tempList->next;
}
}
//THIS IS THE FUNCTION I AM HAVING ISSUES WITH SPECIFICALLY RETURNING MULTIPLE STRUCTURES TO THE LIST
struct container* list_of_breed(char* breed)
{
struct container* result = NULL;
struct container* temp = list;
while (temp != NULL) {
struct dog* tempDog = (struct dog*) malloc(sizeof(struct dog));
tempDog = temp->dog;
if (strcmp(temp->dog->breed, breed) == 0) {
struct container *cont_add = (struct container*) malloc(sizeof(struct container));
struct dog *dog_add = (struct dog*) malloc(sizeof(struct dog));
strcpy(dog_add->name, temp->dog->name);
strcpy(dog_add->breed, breed);
dog_add->checkups = temp->dog->checkups;
cont_add->dog = dog_add;
if (result == NULL) {
result = cont_add;
}
else {
struct container* temp2 = result;
while (temp2->next != NULL) {
temp2 = temp2->next;
}
temp2->next = cont_add;
}
}
temp = temp->next;
}
return result;
}

I noticed the following problems. You have couple of uninitialized members, and you use them. As a consequence, your program has undefined behavior.
First One
In add_doc, you are not initializing the member checkupsof the newly malloc'edstruct dog`. Add
tempDog->checkups = NULL;
after the line
strcpy(tempDog->breed, breed);
Second One
In list_of_breed, you are not setting the next member of cont_dog before using it.
Add the line
cont_add->next = NULL;
after
cont_add->dog = dog_add;
Future Problem
In list_of_breed, you have the line:
dog_add->checkups = temp->dog->checkups;
That makes a shallow copy of checkups. In order to avoid freeing checkups more than once, you will need to make deep copies of checkups.

Related

Cannot store elements in a linked list

My goal is to create a linked list and store elements inside that list.
struct node
{
int a;
struct node *b;
} p,*temp,*head;
void create ( struct node *temp)
{
char c;
temp = malloc (sizeof(struct node));
printf("enter data\n");
scanf(" %d",&temp->a);
printf("do you want to insert another node y/n\n");
scanf("%s", &c);
if (c=='y')
{
create(temp->b);
}
else if ( c=='n')
{
temp->b= NULL;
temp=&p;
return;
}
}
void traverse ( struct node *head)
{
while(head != NULL)
{
printf("%d ",head->a);
head=head->b;
}
}
int main ()
{
int i,j,k,l,m,n;
do{
if(i==1)
{
printf("enter data\n");
scanf("%d",&p.a);
create (p.b);
}
else if ( i==2)
traverse(temp);
}
while(i!=3);
printf("%d",temp->a);
}
I can't recover the elements once i've stored them. When I try to traverse the list, it only gives me the first element of the list and nothing else.
In main
do {
if(i==1)
{
...
}
else if ( i==2)
traverse(temp);
}
while(i!=3);
must be something like
do {
if (scanf("%d", &i) != 1)
break;
if(i==1)
{
...
}
else if ( i==2)
traverse(temp);
}
while(i!=3);
to know what the user want (i not initialized in your code)
in create
scanf("%s", &c);
is wrong because c is a char rather than a string
Do not mix read of int and char because you will read newline and space when reading a character, so read a string for c, for instance
char c[2];
...
scanf("%1s", &c);
if (*c == 'y')
...
else if (c == 'n')
...
the return in else branch is useless, and in case the answer is not 'y' or 'n' you do nothing so you do not set temps, probably you have to just check if 'y' and all other answers must be considered to be 'n', or you need to ask again for the choice
in create you assign the local variable temps, that has no effect on p.b in main, you need to get a node** for instance
in main temp is used but never set elsewhere, and the variables j,k,l,m,n are useless. You also ask for the data in main while you also do in create, must not be done in main. The way you manage your variables do not allow you to modify/print the list
I encourage you to not use global variables the must you can, and to not use the same name for a global and local variable like you do for temp and head because that do not help the reader of your code
A proposal solving the problems :
#include <stdlib.h>
#include <stdio.h>
struct node
{
int a;
struct node * b;
};
/* flush input up to the end of the line */
void flush()
{
int c;
while ((c = getchar()) != '\n') {
if (c == EOF)
exit(-1);
}
}
void create (struct node ** l)
{
/* go to the end of the list */
while (*l != NULL)
l = &(*l)->b;
for (;;) {
char c[2];
int v;
printf("enter data\n");
if (scanf("%d", &v) != 1) {
puts("invalid value");
flush();
}
else {
*l = malloc (sizeof(struct node));
(*l)->a = v;
(*l)->b = NULL;
l = &(*l)->b;
for (;;) {
printf("do you want to insert another node y/n\n");
scanf("%1s", c);
if (*c == 'y')
break;
else if (*c == 'n')
return;
}
}
}
}
void traverse ( struct node *head)
{
while(head != NULL)
{
printf("%d ",head->a);
head = head->b;
}
putchar('\n');
}
int main ()
{
int i;
struct node *head = NULL;
for (;;) {
puts("enter choice : 1 to create new node, 2 to print list, 3 to exit");
if (scanf("%d", &i) != 1)
flush();
switch(i) {
case 1:
create(&head);
break;
case 2:
traverse(head);
break;
case 3:
return 0;
default:
break;
}
}
}
Compilation and execution :
/tmp % gcc -pedantic -Wextra -Wall t.c
/tmp % ./a.out
enter choice : 1 to create new node, 2 to print list, 3 to exit
2
enter choice : 1 to create new node, 2 to print list, 3 to exit
1
enter data
11
do you want to insert another node y/n
y
enter data
22
do you want to insert another node y/n
n
enter choice : 1 to create new node, 2 to print list, 3 to exit
2
11 22
enter choice : 1 to create new node, 2 to print list, 3 to exit
1
enter data
3
do you want to insert another node y/n
n
enter choice : 1 to create new node, 2 to print list, 3 to exit
2
11 22 3
enter choice : 1 to create new node, 2 to print list, 3 to exit
4
enter choice : 1 to create new node, 2 to print list, 3 to exit
3
I encourage you to add the free of the list
There are several issues here:
struct node
{
int a;
struct node *b;
} p,*temp,*head;
Why do you declare global variables and use it as function parameters ? Global variables are available globally, there is no need to pass them into functions. On the other hand, global variables should be avoided and used with care, so it would be better to create local variables (e.g. in main function) and pass them as parameters into next functions.
void create ( struct node *temp)
{
char c;
temp = malloc (sizeof(struct node));
printf("enter data\n");
scanf(" %d",&temp->a);
printf("do you want to insert another node y/n\n");
scanf("%s", &c);
if (c=='y')
{
create(temp->b);
}
else if ( c=='n')
{
temp->b= NULL;
temp=&p;
return;
}
}
This function looks wrong. temp function parameter is actually an internal function's variable, that is not an in/out parameter. In that case you can assign to the temp variable, but it will not for a list. Also temp function parameter shadows temp global variable. It is also a good think to return status of operation, usually '0' means no error, any other error value.
Another thing is to keep things as simple as possible. This will allow for more reuseability and goes with single responsibility principle. If function actually performs two tasks it should be split into two functions.
One more thing, you allocate memory dynamically but never free the memory. This will lead into memory losses.
A possible implementation of your list could be:
#include <stdio.h>
#include <stdlib.h>
typedef struct _node_t
{
int a;
struct _node_t * next;
} node_t;
static node_t * head = NULL;
static node_t * tail = NULL;
node_t * create(void)
{
node_t * temp = malloc(sizeof(node_t));
if (NULL == temp)
{
return NULL;
}
printf("Enter data\n");
scanf("%d", & temp->a);
return temp;
}
void append(node_t * data)
{
if (NULL == head)
{
head = tail = data;
}
else
{
tail->next = data;
tail = tail->next;
}
tail->next = NULL;
return;
}
int add_data(void)
{
node_t * data = NULL;
char answer = 'y';
data = create();
if (NULL == data)
{
return 1;
}
append(data);
return 0;
}
void traverse(void)
{
node_t * current = NULL;
for (current = head; current != NULL; current = current->next)
{
printf("%d ", current->a);
}
printf("\n");
return;
}
void cleanup(void)
{
node_t * current = head;
while (NULL != current)
{
head = head->next;
free(current);
current = head;
}
return;
}
int main(int argc, char ** argv)
{
int option = 3;
do
{
printf("Enter option:\n 1 - add data\n 2 - traverse list\n 3 - exit\n\n");
scanf("%i", & option);
switch (option)
{
case 1:
if (0 != add_data())
{
printf("ERROR:: Cannot allocate memory.\n");
cleanup();
return 1;
}
break;
case 2:
traverse();
break;
default:
if (option > 3)
{
printf("ERROR:: Improper option, try again.\n");
}
break;
}
}
while (option != 3);
cleanup();
return 0;
}
I tried making it as simple as possible and keeping your logic there.
#include <stdio.h>
#include <stdlib.h>
struct node
{
int data;
struct node *next;
};
// create a new node
struct node* create(int data)
{
struct node *n = malloc(sizeof(struct node));
n->data = data;
n->next = NULL; // by default its not NULL, so we must set it
return n;
}
void traverse(struct node *head)
{
struct node *tmp = head;
while(tmp != NULL)
{
printf("%d\t",tmp->data);
tmp = tmp->next;
}
}
void cleanup(struct node *head)
{
struct node *cur = head;
struct node *next;
while(cur != NULL)
{
next = cur->next;
free(cur);
cur = next;
}
}
int main ()
{
int data;
struct node *head, *tmp;
// head node is always created
printf("enter data\n");
scanf("%d",&data);
head = tmp = create(data);
if(head == NULL) return -1;
// now we loop until we don't want to create any more nodes
while(1)
{
char another;
printf("do you want to insert another node y/n\n");
scanf(" %c", &another); // ignore all the previous whitespace
if(another == 'y')
{
printf("enter data\n");
scanf("%d",&data);
tmp->next = create(data);
tmp = tmp->next;
}
else break;
/*
// anything but 'y' breaks the loop, but it can be set to continue if neither 'y' nor 'n' was read:
else if(another == 'n') break;
else continue;
*/
}
traverse(head);
cleanup(head);
}
EDIT: as #Diodacus stated, i added cleanup and checking if malloc returned NULL

I have a segmentation fault that I can't seem to find in C

Hey I have a segmentation fault somewhere when I assign child. It seems to be in my for loop specifically in my add method when i==2.
When you compile the code, you input your name, the function, and "father('name of parent', 'name of child')" or respectively the same format for the mother. There are only parents no other child besides the root child.
UPDATE: I put my variables inside main.
For Example Input:
Brandon
add
father(a,Brandon)
Expected result:
father
a
Brandon
But it's:
father
a
Code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//definition of whats in a node
typedef struct BST {
char *data;
int generation;
struct BST *left;
struct BST *right;
}node;
//starting nodes
node *root = NULL;
//method declarations
node *create(char[]);
node scan(node *, char[]);
void delete (char[]);
void preorder (node *);
void add (char[]);
void ridChild (node *);
void quit(void);
int main(){
char name[12];
char array[50];
char option[12]; //options: add, remove or print
char parent[12];
node *temp;
printf ("Please enter your name :");
fgets(name, 12, stdin);
name[strlen(name) -1] = '\0';
temp = create(name); //create root
root = temp;
printf("Please specify whether to add or delete an entry, or print the tree\n");
fgets(option, 12, stdin);
option[strlen(option) -1] = '\0';
if(strcmp(option,"quit")!=0) {
do {
if(strcmp(option,"add")==0) {
add(name); //put the add method here
}
if(strcmp(option,"delete")==0) {
//put the delete method here
delete(array);
}
if(strcmp(option,"print")==0) {
preorder(root); //print method
}
printf("Please specify whether to add or delete an entry, or print the tree\n");
getchar();
fgets(option, 12, stdin);
option[strlen(option) -1] = '\0';
} while (strcmp (option, "quit") != 0);
}
quit();
}
//methods
void quit(){
exit(1);
}
node *create(char inputName[]){
node *temp;
temp = (node *) malloc (sizeof(node));
temp->data = inputName;
temp->left = temp->right = NULL;
return temp;
}
void preorder (node * root){
if (root != NULL) {
printf ("%s\n", root->data);
preorder (root->left);
preorder (root->right);
}
}
void add(char array[]){
node *child = NULL, *parent = NULL;
char *pch;
printf ("Please specify a relation to add\n");
fgets(array, 50, stdin); // store the command in array
array[strlen(array) -1] = '\0';
pch = strtok (array, "(,)");
int parentdir = 2; //father = 0, mother = 1;
for (int i = 0; pch != NULL && i < 3; i++) {
if(i==0) {
if (strcmp (pch, "father") == 0) { //father
parentdir = 0;
}
if (strcmp (pch, "mother") == 0) { //mother
parentdir = 1;
}
}
else if(i==1) { //make parent
parent = create (pch);
}
else if (i==2) {
//where we assign
if (parentdir == 0) { //father
//find function to find the node and return
*child = scan(root, pch);
//assign left of the found node as the temp (father)
child->left = parent;
}
else if (parentdir == 1) { //mother
//find function to find the node and return
*child = scan(root, pch);
//assign left of the found node as the temp (mother)
child->right = parent;
}
}
printf ("%s\n", pch); //REFERENCE PRINTING
pch = strtok (NULL, "(,)");
}
}
void delete(char array[]){
node *toDelete;
//takes in name of node to be deleted
//scan method to find the node to delete and deletes all of the children of the node first before deleting
printf ("Please specify a name to delete\n");
fgets(array, 50, stdin);
array[strlen(array) -1] = '\0';
*toDelete = scan(root, array); //return which node to delete
//helper method here to go through and delete each children
ridChild(toDelete);
}
void ridChild(node * trash){
if(trash->left == NULL && trash->right == NULL) { //no parents
free(trash);
}
else if(trash->left == NULL && trash->right != NULL) { //have mother
ridChild(trash->right);
}
else if(trash->left != NULL && trash->right == NULL) { //have father
ridChild(trash->left);
}
else if(trash->left != NULL && trash->right == NULL) { //have both
ridChild(trash->left);
ridChild(trash->right);
}
}
node scan(node * temp, char inputName[]){
//returns node that is searched for associated with one of parents
if (temp != NULL) {
if(strcmp(temp->data,inputName)==0) {
return *temp;
} else {
scan (temp->left, inputName);
scan (temp->right, inputName);
}
}
return *temp;
}
The problem is the scan function which I recommend by default should return an empty structure, for clarity. I have included some revised code below.
Insert to the beginning of the function:
node ret;
And then instead of always returning *temp at the end, use the following to conclude the function:
if (temp != NULL) {
ret=*temp;
}
return ret;
Also some minor changes along with this are needed in the add function, beginning with child now defined as follows:
node child, *parent = NULL;
...
child = scan(root, pch);
child.left = parent;

Hashtable & BST Implementation

I'm working on an assignment that can accept commands from keyboard to insert people into a hashtable. After someone is inserted into the hastable, they can be "friended" with another person in the table. The way I have to store who is friends with who is a binary search tree. What I have to do is for the hashtable the first part of the node would be the person's name, then then next is a pointer to the bst for that person's friends, and finally the end is a pointer to the next node for chaining if there is a collision. Here is a visual example...
I have been able to insert people into my table, but the problem that I can not figure out is how to access the BST and add in friends for that person. Here is my code...
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// Structures
struct linkedList{
char *name;
struct linkedList *next;
struct linkedList *tree;
};
typedef struct linkedList list;
struct hashTable{
int size;
list **table;
};
typedef struct hashTable hash;
struct bst{
char *val;
struct bst *l;
struct bst *r;
};
int main(){
char input[50];
char *ch, cmd_str[50], name[30];
// Make hash table for names
hash *profiles;
profiles = createHashTable(1001);
while(1){
// Get keyboard input
fgets(input, 50, stdin);
input[strlen(input)-1] = '\0';
// parse the input
ch = strtok(input, " ");
strcpy(cmd_str,ch);
if(strcmp("CREATE", cmd_str) == 0){
ch = strtok(NULL, " \n");
insertPerson(profiles, ch);
}
else if(strcmp("FRIEND", cmd_str) == 0){
ch = strtok(NULL, " \n");
strcpy(name, ch);
ch = strtok(NULL, " \n");
friendPerson(profiles, name, ch);
}
else if(strcmp("UNFRIEND", cmd_str) == 0){
ch = strtok(NULL, " \n");
}
else if(strcmp("LIST", cmd_str) == 0){
ch = strtok(NULL, " \n");
printFriends(profiles, ch);
}
else if(strcmp("QUERY", cmd_str) == 0){
}
else if(strcmp("BIGGEST-FRIEND-CIRCLE", cmd_str) == 0){
}
else if(strcmp("INFLUENTIAL-FRIEND", cmd_str) == 0){
}
else if(strcmp("EXIT", cmd_str) == 0){
printf("\nExiting...\n");
return 0;
}
else{
printf("\nBad Command.\n");
}
}
}
// Creates Hash Table
hash *createHashTable(int size){
int i;
hash *new_table;
if((new_table = malloc(sizeof(hash))) == NULL)
return NULL;
if((new_table->table = malloc(sizeof(list *) * size)) == NULL)
return NULL;
for(i=0; i < size; i++)
new_table->table[i] = NULL;
new_table->size = size;
return new_table;
}
// hashing function
int keyHash(char *name){
int c;
unsigned long key;
while(c = *name++)
key = ((key<<5) + key) + c;
return key%1000;
}
// insert a person into the hash table
void insertPerson(hash *profiles, char *name){
struct linkedList *item = (struct linkedList*)malloc(sizeof(struct linkedList));
int hash_val = keyHash(name);
item->name = name;
item->next = NULL;
item->tree = new_tree;
// Collision case
if(profiles->table[hash_val] != NULL){
while(profiles->table[hash_val]->next != NULL){
profiles->table[hash_val] = profiles->table[hash_val]->next;
}
profiles->table[hash_val]->next = item;
}
// Empty cell
else{
profiles->table[hash_val] = item;
}
}
// friend two people inside the hash table
void friendPerson(hash *profiles, char *name, char *_friend){
int hash1 = keyHash(name);
int hash2 = keyHash(_friend);
// check if the names are already in system
if(!profiles->table[hash1]){
printf("%s is not yet in the system", name);
return;
}
if(!profiles->table[hash2]){
printf("%s is not yet in the system", _friend);
return;
}
// add first friend
if(strcmp(profiles->table[hash1]->name, name) == 0){
insertBST(profiles->table[hash1]->tree, _friend);
}
else{
while(profiles->table[hash1]->next != NULL){
if(strcmp(profiles->table[hash1]->name, name) == 0)){
break;
}
profiles->table[hash1] = profiles->table[hash1]->next;
}
insertBST(profiles->table[hash1]->tree, _friend);
}
// add second friend
if(strcmp(profiles->table[hash2]->name, _friend) == 0){
insertBST(profiles->table[hash2]->tree, name);
}
else{
while(profiles->table[hash2]->next != NULL){
if(strcmp(profiles->table[hash2]->name, name) == 0)){
break;
}
profiles->table[hash2] = profiles->table[hash1]->next;
}
insertBST(profiles->table[hash2]->tree, name);
}
}
// creates a new bst node
struct bst *newBSTNode(char *name){
struct bst *temp = (struct bst* )malloc(sizeof(struct bst));
temp->val = strdup(name);
strcpy(temp->val, name);
temp->l = temp->r = NULL;
return temp;
}
// Inserts the a friend into a BST
struct bst *insertBST(struct bst *node, char *name){
if(!node)
return newBSTNode(name);
else{
if(strcmp(name, node->val) < 0){
node->l = insertBST(node->l, name);
}
else if(strcmp(name, node->val) > 0){
node->r = insertBST(node->r, name);
}
}
return node;
}
// Inorder print of names
void inorder(struct bst *root){
if(!root){
inorder(root->l);
printf("%s ", root->val);
inorder(root->r);
}
}
// Sends to function to print names
void printFriends(hash *profiles, char *name){
int hash_val = keyHash(name);
inorder(profiles->table[hash_val]->tree);
}
How would I be able to access the BST of said person? The struct bst *tree = profiles->table[hash1]->tree; was my previous attempt, but it was more of a shot in the dark. Thanks in advance!
Update: Okay, so I have been able to add friends (I think) and now I'm trying to print them with void printFriends(). However when I run the function nothing prints out. Would anyone know where I'm messing it up? I've updated the code above.
Your linkedList stores the name and a tree pointer. But the type of tree is linkedList. Change that to struct bst *. You'll have to reorder the declarations, or insert a forward declaration.
Implement a search. You check if the hash buckets are empty, but you don't search for the matching name.
Once you find a matching name in the bucket, the same node contains the aforementioned tree pointer. Insert the friend in the tree. Depending on your logic, you may or may not want to insert a backreference in the other person's tree. (If Alice is friends with Bob, does that make Bob friends with Alice automatically? Or wait for confirmation?)

Linked list insertion doesn't work as expected

I'm writing a function that places new nodes alphabetically into a linked list structure by sorting them by the name field. Here is my program, intended to test that it can successfully insert a new node into an existing structure:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_NAME_LENGTH 100
#define MAX_JOB_LENGTH 100
struct Employee
{
/* Employee details */
char name[MAX_NAME_LENGTH+1]; /* name string */
char sex; /* sex identifier, either ’M’ or ’F’ */
int age; /* age */
char job[MAX_JOB_LENGTH+1]; /* job string */
/* pointers to previous and next employee structures in the linked list
(for if you use a linked list instead of an array) */
struct Employee *prev, *next;
};
void place_alpha(struct Employee *new, struct Employee **root);
int main(){
struct Employee *a;
struct Employee *c;
struct Employee *b;
a = malloc(sizeof(struct Employee));
c = malloc(sizeof(struct Employee));
b = malloc(sizeof(struct Employee));
strcpy(a->name, "A");
a->sex = 'F';
a->age = 42;
strcpy(a->job, "Optician");
a->prev = NULL;
a->next = c;
strcpy(c->name, "C");
c->sex = 'F';
c->age = 22;
strcpy(c->job, "Nurse");
c->prev = a;
c->next = NULL;
strcpy(b->name, "B");
b->sex = 'M';
b->age = 34;
strcpy(b->job, "Rockstar");
b->prev = NULL;
b->next = NULL;
place_alpha(b, &a);
if(a->prev == NULL)
{
printf("a->prev is correct\n");
}else{
printf("a->prev is INCORRECT\n");
}
if(a->next == b)
{
printf("a->next is correct\n");
}else{
printf("a->next is INCORRECT");
}
if(b->prev == a)
{
printf("b->prev is correct\n");
}else{
printf("b->prev is INCORRECT\n");
}
if(b->next == c)
{
printf("b->next is correct\n");
}else{
printf("b->next is INCORRECT\n");
}
if(c->prev == b)
{
printf("c->prev is correct\n");
}else{
printf("c->prev is INCORRECT\n");
}
if(c->next == NULL)
{
printf("c->next is correct\n");
}else{
printf("c->next is INCORRECT\n");
}
}
void place_alpha(struct Employee *new, struct Employee **root) //Places a new node new into the database structure whose root is root.
{
if(*root==NULL) //If there is no database yet.
{
*root = new;
(*root)->prev = NULL;
(*root)->next = NULL;
}
else
{
if(strcmp(new->name, (*root)->name)<=0) // if the new node comes before root alphabetically
{
new->next = *root;
new->prev = (*root)->prev;
if((*root)->prev != NULL)
{
(*root)->prev->next = new;
}
(*root)->prev = new;
*root = new;
return;
}
else if((*root)->next == NULL) // If the next node is NULL (we've reached the end of the database so new has to go here.
{
new->prev = *root;
new->next = NULL;
(*root)->next = new;
return;
}
else if(strcmp(new->name, (*root)->name)>0) // If the new node comes after root alphabetically
{
place_alpha(new, &(*root)->next);
return;
}
}
}
Sadly, the program is unsuccessful, as showcased by the output:
a->prev is correct
a->next is correct
b->prev is INCORRECT
b->next is correct
c->prev is INCORRECT
c->next is correct
Program ended with exit code: 0
I can't figure out why, as I've clearly set b->next to c and c->prev to b.
This was tricky: there is a subtile bug in your place_alpha() function: you update *root even if it is not the root node of the list. This causes the pointer b to be updated erroneously. place_alpha() should only be called with a pointer to the actual root node.
I modified your code to make it more readable and reliable:
I wrote a function to create a new node
I protected the string copies from overflow using calloc() and strncat(). Read about these functions in the manual.
I use place_alpha() to insert all 3 nodes into the list in the same order you do.
I use newp instead of new to avoid C++ keywords in C code.
Note that place_alpha() must be called with a pointer to the head pointer of the list, if you pass a pointer to an intermediary node, chaining back along the prev links would locate the first node, but if the new employee should be inserted at the head of the list, you would not have the address of the root node to update in the caller's scope. This is the reason many programmers prefer to use a specific structure for the list head.
Here is the updated code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_NAME_LENGTH 100
#define MAX_JOB_LENGTH 100
struct Employee {
/* Employee details */
char name[MAX_NAME_LENGTH + 1]; /* name string */
char sex; /* sex identifier, either 'M' or 'F' */
int age; /* age */
char job[MAX_JOB_LENGTH + 1]; /* job string */
/* pointers to previous and next employee structures in the linked list
(for if you use a linked list instead of an array) */
struct Employee *prev, *next;
};
void place_alpha(struct Employee *new, struct Employee **root);
struct Employee *new_employee(const char *name, char sex, int age, const char *job) {
struct Employee *newp = calloc(1, sizeof(*newp));
if (!newp) {
fprintf(stderr, "cannot allocate employee\n");
exit(1);
}
strncat(newp->name, name, MAX_NAME_LENGTH);
newp->sex = sex;
newp->age = age;
strncat(newp->job, job, MAX_JOB_LENGTH);
newp->next = newp->prev = NULL;
return newp;
}
int main(void) {
struct Employee *list = NULL;
struct Employee *a = new_employee("A", 'F', 42, "Optician");
struct Employee *b = new_employee("B", 'M', 34, "Rockstar");
struct Employee *c = new_employee("C", 'F', 22, "Nurse");
place_alpha(a, &list);
place_alpha(c, &list);
place_alpha(b, &list);
if (a->prev == NULL) {
printf("a->prev is correct\n");
} else {
printf("a->prev is INCORRECT\n");
}
if (a->next == b) {
printf("a->next is correct\n");
} else {
printf("a->next is INCORRECT");
}
if (b->prev == a) {
printf("b->prev is correct\n");
} else {
printf("b->prev is INCORRECT\n");
}
if (b->next == c) {
printf("b->next is correct\n");
} else {
printf("b->next is INCORRECT\n");
}
if (c->prev == b) {
printf("c->prev is correct\n");
} else {
printf("c->prev is INCORRECT\n");
}
if (c->next == NULL) {
printf("c->next is correct\n");
} else {
printf("c->next is INCORRECT\n");
}
return 0;
}
void place_alpha(struct Employee *newp, struct Employee **root) {
// Insert a new node newp into the database structure whose root is root.
struct Employee *ep;
if (*root == NULL) { // if there is no database yet.
newp->next = newp->prev = NULL;
*root = newp;
return;
}
if ((*root)->prev) {
// invalid call, should only pass the root node address
fprintf(stderr, "invalid call: place_alpha must take a pointer to the root node\n");
return;
}
if (strcmp(newp->name, (*root)->name) <= 0) {
// if the new node comes before root alphabetically
newp->next = *root;
newp->prev = NULL;
newp->next->prev = newp;
*root = newp;
return;
}
for (ep = *root;; ep = ep->next) {
if (ep->next == NULL) {
// If the next node is NULL, we've reached the end of the list
// so newp has to go here.
newp->prev = ep;
newp->next = NULL;
newp->prev->next = newp;
return;
}
if (strcmp(newp->name, ep->next->name) <= 0) {
// The new node comes between ep and ep->next alphabetically
newp->prev = ep;
newp->next = ep->next;
newp->prev->next = newp->next->prev = newp;
return;
}
}
}
EDIT: place_alpha was a bit redundant, so I cleaned it and got a much simpler version:
void place_alpha(struct Employee *newp, struct Employee **root) {
//Places a new node newp into the database structure whose root is root.
struct Employee **link = root;
struct Employee *last = NULL;
while (*link && strcmp(newp->name, (*link)->name) > 0) {
last = *link;
link = &last->next;
}
newp->prev = last;
newp->next = *link;
if (newp->next) {
newp->next->prev = newp;
}
*link = newp;
}

Linked list program in C

I am coding for a simple linked list , but facing a little problem. The program is like it is accepting name, age and DOB through user, and memory for it is dynamically allocated. After taking data from the user, it is searching a name, asked by user, if the name exists, it should print all the details related to it.
Here is my code-
//function declarations
struct node *initnode(char *, char *, char *);
void add(struct node *);
struct node *printnode(struct node *);
struct node *searchname(struct node *, char *);
struct node {
char name[25];
char age[10];
char dob[10];
struct node *next;
};
struct node *head = (struct node *) NULL;
struct node *initnode(char *name, char *age, char *dob1)
{
struct node *ptr;
ptr = (struct node *) malloc(sizeof(struct node));
if (ptr == NULL)
return (struct node *) NULL;
else {
strcpy(ptr->name, name);
strcpy(ptr->age, age);
strcpy(ptr->dob, dob1);
ptr->next = NULL;
return ptr;
}
}
struct node *printnode(struct node *ptr)
{
printf("Name -> %s\n", ptr->name);
printf("age -> %s \n", ptr->age);
printf("dob ->%s\n", ptr->dob);
return ptr;
}
void add(struct node *newp)
{
struct node *temp = (struct node *) malloc(sizeof(struct node));
if (head == NULL)
head = newp;
else {
for (temp = head; temp->next != NULL; temp = temp->next);
temp->next = newp;
temp = newp;
}
free(temp);
}
struct node *searchname(struct node *ptr, char *name1)
{
if (strcmp(name1, ptr->name) == 0) {
printf("\n name found \n");
printf("\n details are -\n");
printnode(ptr);
return ptr;
} else {
printf("\n name not found in the database \n");
}
}
int main()
{
char name[25];
char name1[25];
char rep;
char age[10];
char dob[10];
int i;
int flag = 1;
struct node *ptr;
do {
fflush(stdin);
while (flag != 0) {
printf("Enter name -- ");
gets(name);
for (i = 0; name[i] != '\0'; i++)
if (isdigit(name[i])) {
printf("Error in user input, name should be in alphabets\n");
flag = 1;
break;
}
else
flag = 0;
}
flag = 1;
while (flag != 0) {
printf("Enter age -- ");
scanf("%s", &age);
fflush(stdin);
for (i = 0; age[i] != '\0'; i++)
if (isalpha(age[i])) {
printf("Error in user input, age should be in numbers\n");
flag = 1;
break;
} else {
flag = 0;
}
}
flag = 1;
while (flag != 0) {
printf("Enter dob in DD/MM/YY format-- ");
scanf("%s", &dob);
fflush(stdin);
for (i = 0; dob[i] != '\0'; i++) {
if (isalpha(dob[i])) {
printf("Error in user input, dob should be in numbers\n");
flag = 1;
break;
} else
flag = 0;
}
}
flag = 1;
ptr = initnode(name, age, dob);
add(ptr);
printf("\n Do you want to continue?<Y/N>:\n ");
scanf("%s", &rep);
//rep = getchar();
}
while (rep == 'Y' || rep == 'y');
printf("\n do u want to search for a name in the database? <Y/N>:\n");
scanf("%s", &rep);
if (rep == 'Y' || rep == 'y') {
printf("Enter name you want to search-- ");
scanf("%s", &name1);
ptr = searchname(head, name1);
} else {
printf("\n goodbye \n");
}
do {
printf("\n do u want to search again? <Y/N>:\n");
scanf("%s", &rep);
if (rep == 'Y' || rep == 'y') {
printf("Enter name you want to search-- ");
scanf("%s", &name1);
ptr = searchname(head, name1);
} else {
printf("\n goodbye \n");
}
}
while (rep == 'Y' || rep == 'y');
return 0;
}
The issue is that it is searching for the first entry only and not others, can anyone help me to sort out this? I am compiling through "gcc".
At a first glance, your search function is only comparing one element, the head of the list.
After comparing one element you must go to the next element. This can either be done recursively or with a while:
Recursive use:
struct node *searchname(struct node *ptr, char *name1)
{
if (ptr==NULL) //Reached end of the list
{
printf("\n name not found in the database \n");
return NULL;
}
if (strcmp(name1, ptr->name) == 0) { //found the element
printf("\n name found \n");
printf("\n details are -\n");
printnode(ptr);
return ptr;
} else { //search next element
return searchname(ptr->next,name1); //this will call your function again for the next element on the list
}
}
While use:
struct node *searchname(struct node *ptr, char *name1)
{
struct node *aux; // usually i use an auxiliary pointer in order to avoid unwanted overwrite at my pointer.
aux = ptr;
while (aux!=NULL)
{
if (strcmp(name1, aux->name) == 0) { //found the element
printf("\n name found \n");
printf("\n details are -\n");
printnode(aux);
return aux;
}
else { //move pointer to next element
aux=aux->next;
}
}
//if it reaches this point, the element was not found
printf("\n name not found in the database \n");
return NULL;
}
Check your add function, it is wrong. Step mentally through it, and see what happens
to your pointer, and to the memory it points to.
What are the malloc and free used for in the add function?

Resources