C structs and linked lists struggle - c

So, we just started learning linked lists and data structures in my online class, but I have been really struggling with this topic. I have a general understanding of pointers but when you combine everything, I get completely lost.
So for this program, I am supposed to process employee data and access it through the use of structs and pointers. However, I think I am not passing the correct values into the functions because the data is not being saved and I can't access it. Any help would be appreciated.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct address {
char street[49];
char city[29];
char state[2];
char zip[5];
};
struct data{
char name[39];
struct address addy;
float salary;
struct data *next;
} emp;
void LIST(struct data* head);
void INSERT(struct data* head, char* name, struct address addr, float salary);
void DELETE(char* name, struct data* head);
void EDIT(struct data* head, char* name, struct address addr, float salary);
void CALCPAYROLL(struct data* head);
void HELP();
int main()
{
char input[15];
int quitter = 1;
struct data *head = NULL;
head = malloc(sizeof(emp));
if (head == NULL){
return 1;
}
while(quitter == 1)
{
printf(" enter command: \n");
fgets(input,15, stdin);
input[strlen(input) -1] = '\0';
if((strcmp(input, "List") == 0) || (strcmp(input, "list") == 0))
{
LIST(head);
}
if((strcmp(input, "Insert") == 0) || (strcmp(input, "insert") == 0))
{
scanf("%s-%s-%s-%s-%s-%f", head->name, head->addy.street, head->addy.city, head->addy.state, head->addy.zip, &head->salary);
INSERT(head, head->name, head->addy, head->salary);
}
if ((strcmp(input, "Delete") == 0) || (strcmp(input, "delete") == 0))
{
DELETE(head->name, head);
}
if ((strcmp(input, "Edit") == 0) || (strcmp(input, "edit") == 0))
{
EDIT(head, head->name, head->addy, head->salary);
}
if ((strcmp(input, "Payroll") == 0) || (strcmp(input, "payroll") == 0))
{
CALCPAYROLL(head);
}
if ((strcmp(input, "Help") == 0) || (strcmp(input, "help") == 0))
{
HELP();
}
if ((strcmp(input, "Quit") == 0) || (strcmp(input, "quit") == 0))
{
printf("============\nGood bye!\n");
quitter = 0;
}
}
return 0;
}
void LIST(struct data* head)
{
struct data* temp = head;
while (temp) {
printf("%s\n%s\n%s, %2s %5s\n%9.2f\n-----\n", temp->name, temp->addy.street, temp->addy.city, temp->addy.state, temp->addy.zip, temp->salary);
temp = temp->next;
printf("%s\n%s\n%s, %2s %5s\n%9.2f\n-----\n", temp->name, temp->addy.street, temp->addy.city, temp->addy.state, temp->addy.zip, temp->salary);
temp = temp->next;
}
}
void INSERT(struct data* head, char* name, struct address addr, float salary)
{
struct data* newEmployee = NULL;
newEmployee = (struct data*)malloc(sizeof(emp));
strcpy(newEmployee->name, head->name);
newEmployee->salary = head->salary;
strcpy(newEmployee->addy.street, head->addy.street);
strcpy(newEmployee->addy.city, head->addy.city);
strcpy(newEmployee->addy.state, head->addy.state);
strcpy(newEmployee->addy.zip, head->addy.zip);
struct data* temp = head;
while(temp->next && temp->next->name > newEmployee->name)
{
temp = temp->next;
}
newEmployee->next = temp->next;
temp->next = newEmployee;
}
void DELETE(char* name, struct data* head)
{
char del[39];
scanf("%39s", del);
struct data * toBeDeleted = NULL;
struct data * temp = head;
while (strcmp(del, temp->name) == 0)
{
strcpy(temp->next->name, temp->name);
temp->addy = temp->next->addy;
temp->salary = temp->next->salary;
toBeDeleted = temp->next;
temp->next = temp->next->next;
free(toBeDeleted);
printf("RECORD DELETED\n");
}
temp = temp->next;
printf("RECORD NOT FOUND\n");
}
void EDIT(struct data* head, char* name, struct address addr, float salary)
{
char edit[39];
scanf("%39s", edit);
struct data* temp = head;
while (strcmp(edit, temp->name) == 0)
{
temp->addy = addr;
temp->salary = salary;
printf("RECORD EDITED\n");
return;
}
temp = temp->next;
printf("RECORD NOT FOUND\n");
}
void CALCPAYROLL(struct data* head)
{
struct data* temp = head;
float total;
while (temp)
{
total += temp->salary;
temp = temp->next;
}
printf("total payroll: %f", total);
}
void HELP()
{
printf("commands:\n");
printf("List - shows the list of employees\n");
printf("Insert - Creates a new employee record\n");
printf("Delete - Deletes an existing employee record\n");
printf("Edit - Modifies the contents of an employee record\n");
printf("Payroll - Calculates and displays the total payroll\n");
printf("Help - Displays the set of available commands\n");
printf("Quit - Prints the message ""good bye!"" and exits the program" );
}

First of all, I have to commend you for a very neat presentation. The code is readable and easy to follow. The only fault I find with it is that all uppercase names are usually reserved for macros and constants declared with #define.
Here:
struct data{
char name[39];
struct address addy;
float salary;
struct data *next;
} emp; // declaring a variable at the same time as the structure? Not very nice.
I see an issue that happens when you create your first list item, the head. Insert must have a way to modify the head parameter. This needs an extra level of indirection. INSERT should also return an error code, in case malloc fails, a common way to do this is to return a negative value (-1) on error.
void INSERT(struct data* head, char* name, struct address addr, float salary)
// should be
int INSERT(struct data** head, char* name, struct address addr, float salary)
You'll have to change the logic a little bit to set head with the newly allocated buffer when head is NULL on entry. Calling INSERT then becomes.
if (INSERT(&head, name, &addr, salary) < 0)
{
// error !
}
I see a problem in data allocation in INSERT.
struct data* newEmployee = NULL;
//newEmployee = (struct data*)malloc(sizeof(emp)); // ?? you allocate a struct data, what's emp?
// should read
newEmployee = (struct data*)malloc(sizeof(struct data));
DELETE and EDIT do not work. They cannot find the employee as written. You should consider using a find() function, something like this:
data* FindEmployeeData(data* head, const char* name)
{
while (head)
{
if (strcmp(head->name, name) == 0)
break;
head = head->next;
}
return head;
}
This could be a time saver when writing new operations on employees.
In INSERT:
while(temp->next && temp->next->name > newEmployee->name)
I thought strings were supposed to be compared with strcmp()...
In DELETE: same as for INSERT, the function could change the head of the list
int DELETE(data** head, const char* name); // returns -1 on error.
Here:
scanf("%s-%s-%s-%s-%s-%f", head->name, head->addy.street, head->addy.city, head->addy.state, head->addy.zip, &head->salary);
Terrible things will happen when the user enters a name, address, state, street, city or zip that are too long for the space you have allocated.

You can't access to the data because in INSERT function head must be a double pointer, because when you want to insert something in the head of a linked list you have to change the address stored in head. In your code you're modifying a copy of head. remember that in C everything is passed for value. This mean that for modify the address content in a pointer you have to pass the address of the pointer at your function.

Related

printf segmentation fault and wrong sorted linked list

This is my algorithm for adding nodes to a linked list which is in a sorted way for surnames of persons.
Here is the code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct Node {
char Name[1024];
char Surname[1024];
char Telno[1024];
struct Node* next;
};
void Add(struct Node** firstnode, struct Node* NewNode)
{
struct Node* tempo;
//printf("%d",strcmp((*firstnode)->Surname,NewNode->Surname));
if (*firstnode == NULL || (strcmp((*firstnode)->Surname,NewNode->Surname) > 0)) {
NewNode->next = *firstnode;
*firstnode = NewNode;
}
else {
tempo = *firstnode;
while (tempo->next != NULL && strcmp(tempo->Surname,NewNode->Surname) < 0) {
tempo = tempo->next;
}
NewNode->next = tempo->next;
tempo->next = NewNode;
}
}
struct Node* CreateNode(char name[1024], char surname[1024], char telno[1024])
{
struct Node* NewNode = (struct Node*)malloc(sizeof(struct Node));
strcpy(NewNode->Name,name);
strcpy(NewNode->Surname,surname);
strcpy(NewNode->Telno,telno);
NewNode->next = NULL;
return NewNode;
}
void Printlinkedlist(struct Node* head)
{
struct Node* temp = head;
while (temp != NULL) {
printf("%s %s %s\n", temp->Name,temp->Surname,temp->Telno);
temp = temp->next;
}
}
struct Node* head = NULL;
struct Node* temp;
int main()
{
int personcount;
char name[1024],surname[1024],telno[1024];
printf("Please give the count of person:");
scanf("%d", &personcount);
for (int i = 0; i < personcount; i++) {
printf("Please give the name of %d. person:", i + 1);
scanf(" %s", &name);
printf("Please give the surname of %d. person:", i + 1);
scanf(" %s", &surname);
printf("Please give the phone number of %d. person:", i + 1);
scanf(" %s", &telno);
temp = CreateNode(name,surname,telno);
Add(&head, temp);
}
printf("\n -------------- Linkedlist --------------\n");
Printlinkedlist(head);
return 0;
}
The first problem is this: For example, if I enter people's surnames as G, A, L, E, K (So first person's last name will be "G", second person's last name will be "A" etc..), it gives an incorrectly ordered output.
And the second one is: If I delete the comment line characters behind the printf inside the add function, I get a segmentation fault that I don't understand why
Thanks for the answer.
It should first be said that you could, and should, have figured it out yourself by either:
Debugging the program:
On Linux: How Can I debug a C program on Linux?
On Windows: How do you debug a C program on Windows?
Enabling core dumps and analyzing the core file you get when your program crashes; see this explanation.
But, more to the point, let's have a look at (some of) your code:
if (*firstnode == NULL || /* another condition */) {
// do stuff
}
else {
// so *firstnode may be NULL here
tempo = *firstnode;
while (tempo->next != /* some value */ && /* another condition*/ ) {
// do stuff
}
// do stuff
}
See the problem? tempo could get assigned a NULL point, and then de-referenced to get to the next field. That would likely cause a segmentation fault.

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

Segmentation fault while using malloc

As an exercise I am trying to work on a Binary search tree!
I have created the code and it seems to run, but when I try to add a customer it crashes. After debugging the code I get a segmentation fault in line 82, where I try to allocate memory to root... Researching for a while I see that it is something related to memory, but can't figure what is going on with my code... Any suggestions about what is causing this failure when trying to allocate memory?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_STRING 50
void flush();
struct customer {
char *name;
char *address;
char *email;
};
struct double_linked_list {
struct customer *data;
struct double_linked_list *previous;
struct double_linked_list *next;
};
struct double_linked_list *customers_head = 0;
struct BST_node {
struct double_linked_list *data;
struct BST_node *left;
struct BST_node *right;
};
struct BST_node *BST_email_root = 0;
struct BST_node *BST_find_customer(struct BST_node *root, char *email) {
if (root == NULL)
return NULL;
if (strcmp(email, root->data->data->email) == 0)
return root;
else {
if (strcmp(email, root->data->data->email) == -1)
return BST_find_customer(root->left, email);
else
return BST_find_customer(root->right, email);
}
}
void find_customer() {
char email[MAX_STRING];
struct double_linked_list *l;
struct BST_node *b;
printf("Give the email of the customer (up to %d characters) : ", MAX_STRING - 1);
gets(email);
b = BST_find_customer(BST_email_root, email);
if (b == 0)
printf("There is no customer with this email.\n");
else {
l = b->data;
printf("Customer found! \n");
printf("Name : %s\n", l->data->name);
printf("Address : %s\n", l->data->address);
printf("Email : %s\n", l->data->email);
}
}
struct BST_node *new_BST_node(struct BST_node *root, struct double_linked_list *l) {
if (root == NULL);
{
root = (struct BST_node *)malloc(sizeof(struct BST_node));
if (root == NULL) {
printf("Out of Memory!");
exit(1);
}
root->data = l;
root->left = NULL;
root->right = NULL;
}
if (strcmp(l->data->email, root->data->data->email) == -1)
root->left = new_BST_node(root->left, l);
else
root->right = new_BST_node(root->right, l);
return root;
};
struct double_linked_list *new_customer() {
char name[MAX_STRING], address[MAX_STRING], email[MAX_STRING];
struct BST_node *b;
struct double_linked_list *l;
struct customer *c;
printf("\nADDING NEW CUSTOMER\n=\n\n");
printf("Give name (up to %d characters): ", MAX_STRING - 1);
gets(name);
printf("Give address (up to %d characters): ", MAX_STRING - 1);
gets(address);
printf("Give email (up to %d characters): ", MAX_STRING - 1);
gets(email);
b = BST_find_customer(BST_email_root, email);
if (b) {
printf("Duplicate email. Customer aborted.\n");
return 0;
}
c = (struct customer *)malloc(sizeof(struct customer));
if (c == 0) {
printf("Not enough memory.\n");
return 0;
}
c->name = strdup(name); // check for memory allocation problem
if (c->name == 0)
return 0;
c->address = strdup(address); // check for memory allocation problem
if (c->address == 0)
return 0;
c->email = strdup(email); // check for memory allocation problem
if (c->email == 0)
return 0;
l = (struct double_linked_list*)malloc(sizeof(struct double_linked_list));
if (l == 0) {
printf("Not enough memory.\n");
free(c->name);
free(c->address);
free(c->email);
free(c);
return 0;
}
l->data = c;
l->previous = 0;
l->next = customers_head;
if (customers_head)
customers_head->previous = l;
customers_head = l;
BST_email_root = new_BST_node(BST_email_root, l);
return l;
}
void displaymenu() {
printf("\n\n");
printf("1. New customer\n");
printf("2. Find customer using email\n");
printf("0. Exit\n\n");
printf("Give a choice (0-6) : ");
}
void flush() {
char ch;
while ((ch = getchar()) != '\n' && ch != EOF);
}
int main() {
int choice;
do {
displaymenu();
scanf("%d", &choice);
flush();
switch (choice) {
case 1:
new_customer();
break;
case 2:
find_customer();
break;
}
} while (choice != 0);
return 0;
}
Codeblocks debugger gives the following information
Active debugger config: GDB/CDB debugger:Default
Building to ensure sources are up-to-date
Selecting target:
Debug
Adding source dir: C:\debug\
Adding source dir: C:\debug\
Adding file: C:\debug\bin\Debug\debug.exe
Changing directory to: C:/debug/.
Set variable: PATH=.;C:\Program Files\CodeBlocks\MinGW\bin;C:\Program Files\CodeBlocks\MinGW;C:\Windows\System32;C:\Windows;C:\Windows\System32\wbem;C:\Windows\System32\WindowsPowerShell\v1.0;C:\Program Files\ATI Technologies\ATI.ACE\Core-Static;C:\Users\baskon\AppData\Local\Microsoft\WindowsApps
Starting debugger: C:\Program Files\CodeBlocks\MINGW\bin\gdb.exe -nx -fullname -quiet -args C:/debug/bin/Debug/debug.exe
done
Registered new type: wxString
Registered new type: STL String
Registered new type: STL Vector
Setting breakpoints
Debugger name and version: GNU gdb (GDB) 7.6.1
Child process PID: 5908
Program received signal SIGSEGV, Segmentation fault.
In ?? () ()
9 0x00401480 in new_BST_node (root=0x0, l=0xbe0ec8) at C:\debug\main.c:82
C:\debug\main.c:82:1907:beg:0x401480
At C:\debug\main.c:82
9 0x00401480 in new_BST_node (root=0x0, l=0xbe0ec8) at C:\debug\main.c:82
C:\debug\main.c:82:1907:beg:0x401480
The call stack is the following
There are multiple problems in your code:
You have a classic bug here:
struct BST_node *new_BST_node(struct BST_node *root, struct double_linked_list *l) {
if (root == NULL);
{
root = (struct BST_node *)malloc(sizeof(struct BST_node));
The ; at the end of the if statement line is parsed as an empty statement. The subsequent block, introduced by the { will always be executed.
You can avoid this kind of silly bug by always using braces for your compound statements and placing them on the same line as the beginning of the statement, not on the next line. This is close to the original K&R style used by the creators of the C language more than 40 years ago.
The type for variable ch in function flush should be int to allow proper distinction of all values returned by getc(): all values of unsigned char plus the special value EOF:
void flush(void) {
int ch;
while ((ch = getchar()) != EOF && ch != '\n') {
continue;
}
}
Note that you should make the empty statement more explicit as I did above, to avoid confusion and bugs such as the previous one.
You should not use the obsolete unsafe function gets(): Use fgets() and strip the trailing newline with strcspn().
When comparing strings with strcmp(), you should only rely on the sign of the return value. In functions BST_find_customer() and new_BST_node(), you compare with -1: this is unreliable. Use if (strcmp(email, root->data->data->email) < 0) instead.
In function new_BST_node(), You do not return root when you create a new node in the tree. Here is a corrected version:
struct BST_node *new_BST_node(struct BST_node *root, struct double_linked_list *l) {
if (root == NULL) {
root = malloc(sizeof(*root));
if (root == NULL) {
printf("Out of Memory!");
exit(1);
}
root->data = l;
root->left = NULL;
root->right = NULL;
return root;
}
if (strcmp(l->data->email, root->data->data->email) < 0) {
root->left = new_BST_node(root->left, l);
} else {
root->right = new_BST_node(root->right, l);
}
return root;
}
Note that this is causing your bug as you probably have an infinite recursion here.
Finally a couple pieces of advice:
use NULL instead of 0 when comparing pointers to the null pointer. It is more readable.
avoid naming a variable l as this name is graphically too close to 1 with the fixed pitch fonts used in programming environments. Sometimes it is almost indistinguishable.
Ok, so after testing everything i found out what is wrong however i can't figure out why.. Any Suggestions??
I think that strcmp returns values of either 0 or -1 or 1.
But there was the problem, if i didn't define exactly if strcmp ==1 or if strcmp ==-1 ...i had an infinite loop as it seems (i used a printf command to see what is going on, and i discovered the bug..)
By changing
struct BST_node *new_BST_node(struct BST_node *root, struct double_linked_list *l)
{
if (root==NULL)
{
root = (struct BST_node *) malloc (sizeof(struct BST_node ));
if (root==NULL)
{
printf("Out of Memory!");
exit(1);
}
root->data=l;
root->left=NULL;
root->right=NULL;
}
if (strcmp(l->data->email, root->data->data->email) == -1)
root->left =new_BST_node(root->left,l);
else
root->right =new_BST_node(root->right,l);
return root;
};
to
struct BST_node *new_BST_node(struct BST_node *root, struct double_linked_list *l)
{
if (root==NULL)
{
root= (struct BST_node *)malloc(sizeof(struct BST_node ));
if (root==NULL)
{
printf("Out of Memory!");
exit(1);
}
root->data=l;
root->left=NULL;
root->right=NULL;
}
if ((strcmp(l->data->email, root->data->data->email))==-1)
root->left =new_BST_node(root->left,l);
else if ((strcmp(l->data->email, root->data->data->email)) ==1)
root->right =new_BST_node(root->right,l);
return root;
};
everything works fine..
But why didnt the other code work? I am pretty sure it is the same...

Makes integer from pointer without a cast

I'm writing a code to manipulate a linked list. But It won't compile because on line 36 i'm making an integer from a pointer without a cast. I'm not sure why this is happening. But it's affecting my function "Ins" which puts new characters into my list. Let me know what you think.
Please ignore functions del, fde, pst, prl, pcr, ppr, and psu. I haven't gotten to those yet, they shouldn't get in the way. Thanks
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MIN_LENGTH 4
#define MAX_LENGTH 11
struct node{
char list;
int count;
struct node *next;
};
typedef struct node Node;
typedef Node *ListNode;
void ins(ListNode *ptr, char value);
int main(void){
ListNode startPtr = NULL;
char com[MIN_LENGTH];
char cho[MAX_LENGTH];
while(strcmp(com, "end") != 0){
printf("Command? ");
scanf("%s", &com);
if(strcmp(com, "ins") == 0){
scanf("%s", &cho);
ins(&startPtr, cho);
printf("%s", cho);
}
else if(strcmp(com, "del") == 0){
// del();
scanf("%s", &cho);
printf("%s\n", cho);
}
else if(strcmp(com, "fde") == 0){
// fde();
scanf("%s", &cho);
printf("%s\n", cho);
}
else if(strcmp(com, "pst") == 0){
// pst();
scanf("%s", &cho);
printf("%s\n", cho);
}
else if(strcmp(com, "prl") == 0){
// prl();
scanf("%s", &cho);
printf("%s\n", cho);
}
else if(strcmp(com, "pcr") == 0){
// pcr();
scanf("%s", &cho);
printf("%s\n", cho);
}
else if(strcmp(com, "ppr") == 0){
// ppr();
scanf("%s", &cho);
printf("%s\n", cho);
}
else if(strcmp(com, "psu") == 0){
// psu();
scanf("%s", &cho);
printf("%s\n", cho);
}
else if(strlen(com) >= 4 || strlen(com) < 3){
printf("You have entered an incorrect command.\n");
}
}
}
void ins(ListNode *ptr, char value){
ListNode newPtr;
ListNode prevPtr;
ListNode currPtr;
newPtr = (struct node*) malloc(sizeof(Node));
if(newPtr != NULL){
newPtr->list = value;
newPtr->next = NULL;
prevPtr = NULL;
currPtr = *ptr;
while(currPtr != NULL && value > currPtr-> list){
prevPtr = currPtr;
currPtr = currPtr->next;
}
if(prevPtr == NULL){
newPtr->next = *ptr;
*ptr = newPtr;
}
else{
prevPtr->next = newPtr;
newPtr->next = currPtr;
}
}
else{
printf("No memory available\n");
}
}
void del(){
}
void fde(){
}
void pst(){
}
void prl(){
}
void pcr(){
}
void ppr(){
}
void psu(){
}
You have cho as a char array, you have function ins accepting two parameters, the second being a char.
Then you try to call function ins with the second parameter being cho. As cho is a char array, its name is considered to be equivalent to a pointer. So you are calling ins with the second parameter being a pointer, whereas that function expects a char, which is an integer type. You cannot reasonably expect the compiler to convert that pointer to that char.
if you need to store strings, you can read here:
you need to change your structure to:
struct node{
char *list;
then change method:
void ins(ListNode *ptr, char *value);
then change insert logic:
newPtr->list = (char*)malloc(strlen(value)+1); // NOTE: dont forget to free this memory
memcpy(newPtr->list, value, strlen(value)+1);
then, you have problem:
while(currPtr != NULL && value > currPtr-> list)
I don't understand what you're trying to compare here, if you need to compare strings - use strcmp here instead of >
if you need to store individual chars, read here:
change you insertion logic to:
char *tcho = cho;
while (!*tcho) {
ins(&startPtr, *tcho);
tcho++;
}
Declare your struct node to contain a char*,
struct node{
char* list;
int count;
struct node *next;
};
Change your ins() function declaration,
void ins(ListNode *ptr, char* value);
Call ins() with correct parameters,
main(void) {
//...
ins(&startPtr, cho);
//...
}
define your ins() function to allocate space for the data string passed,
void ins(ListNode *ptr, char* value){
//...
newPtr->list = strdup(value);
//...
}
You have three pointers declared in ins(), but typical single linked list inserts only need two, one to hold the new node, and one to hold the iterator to scan for the end of the list,
ListNode newPtr;
ListNode prevPtr; //we will omit this
ListNode currPtr;
After looking a little closer, the newPtr is your newly allocated list Node which you malloc, and check for successful malloc (good). And you seem to be using prevPtr and currPtr as a way to walk the list looking for the end of the list (often called the tail, while the front of the list is often called the head). This is a workable solution, but you can simplify it.
Here is a function to construct a new Node,
ListNode NodeNew(char* value)
{
ListNode newPtr;
if( (newPtr = (struct node*) malloc(sizeof(Node))) == NULL )
{
printf("ENOMEM memory available\n");
return newPtr=NULL;
}
newPtr->list = strdup(value);
newPtr->next = NULL;
newPtr->count = 0;
return newPtr;
}
And here is a simpler list insert,
void ins(ListNode *head, char* value)
{
ListNode newPtr;
ListNode prevPtr;
ListNode currPtr;
if( !(newPtr = NodeNew(value)) )
{
return;
}
if(*head == NULL)
{
*head = newPtr;
}
else
{
for( currPtr=*ptr; currPtr->next != NULL; )
{
currPtr = currPtr->next;
}
currPtr->next = newPtr;
}
}
And you want to implement the list print (prl),
void prl(ListNode head){
ListNode currPtr;
for( currPtr=head; currPtr != NULL; )
{
printf("n:%s\n",currPtr->list);
currPtr = currPtr->next;
}
}

Resources