I have written a code to enter the name, age, department id, company name, and salary respectively, of employees from a text file into a linked list. Right now, In my code, I have created an insert function and a display function. When I ran the code on the command prompt there were no errors found. However, my list did not get printed. Can someone help me out with this if possible? thankyou.
Here are the details of the file, it is called employee.txt:
Peter 30 1001 Apple 8000
Joseph 50 1002 Oracle 4000
Mary 40 1003 Samsung 6000
Lilly 40 1203 Samsung 7000
Tony 50 1002 Oracle 3000
Jake 30 1005 Apple 3000
Sam 40 1007 Samsung 4000
Lisa 30 1300 Oracle 5000
Kate 50 1200 Apple 6000
Rick 50 1313 Apple 4000
My Code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct personTag {
char name[20];
int age;
};
struct officialTag {
int deptId;
char cmpName[20];
double salary;
};
struct employeeTag {
struct personTag personalInfo;
struct officialTag officialInfo;
struct employeeTag *next;
};
typedef struct employeeTag EmpTag;
typedef EmpTag *EmpTagPtr;
void insert(EmpTagPtr *s, char E_name[], int E_age, int E_deptid,
char E_cmpname[], double E_salary);
void displayEmployees(EmpTagPtr s);
int main() {
EmpTagPtr start = NULL;
char E_name[20];
int E_age;
int E_deptid;
char E_cmpname[20];
double E_salary;
// reading employee.txt file
FILE *fp;
fp = fopen("employee.txt", "r");
fscanf(fp, "%s,%d,%d,%s,%lf", E_name, &E_age, &E_deptid, E_cmpname,
&E_salary);
while (!feof(fp)) {
insert(&start, E_name, E_age, E_deptid, E_cmpname,
E_salary); // inserting data to the new node
fscanf(fp, "%s,%d,%d,%s,%lf", E_name, &E_age, &E_deptid, E_cmpname,
&E_salary);
}
fclose(fp);
displayEmployees(start);
return 0;
}
void insert(EmpTagPtr *s, char E_name[], int E_age, int E_deptid,
char E_cmpname[], double E_salary) {
EmpTagPtr current = *s;
EmpTagPtr prev = NULL;
// create an empty node
EmpTagPtr newNode;
newNode = (EmpTag *)malloc(sizeof(EmpTag));
// filling in the values
strcpy(newNode->personalInfo.name, E_name);
newNode->personalInfo.age = E_age;
newNode->officialInfo.deptId = E_deptid;
strcpy(newNode->officialInfo.cmpName, E_cmpname);
newNode->officialInfo.salary = E_salary;
newNode->next = NULL;
while (current != NULL &&
strcmp(current->personalInfo.name, prev->personalInfo.name) > 0) {
prev = current;
current = current->next;
}
if (prev == NULL) {
// add as the first node
newNode->next = *s;
*s = newNode;
} else {
prev->next = newNode;
newNode->next = current;
}
}
void displayEmployees(EmpTagPtr s) {
EmpTagPtr current = s;
while (current != NULL) {
// printing the data part
printf("Employee name: %s\n", current->personalInfo.name);
printf("Company name: %s\n", current->officialInfo.cmpName);
printf("Employee Age: %d\n", current->personalInfo.age);
printf("Department ID: %d\n", current->officialInfo.deptId);
printf("Employee Salary: %lf\n", current->officialInfo.salary);
printf("---------------------------------------------------------");
current = current->next; // move foward the current pointer
}
printf("NULL\n");
}
Your loop to read uses the wrong fscanf format. The loop is also a bit overcomplicated. Just fscanf and check that you successfully extracted the 5 elements. Note the limits for the strings and removed commas:
while (fscanf(fp, "%19s %d %d %19s %lf", E_name, &E_age, &E_deptid,
E_cmpname, &E_salary) == 5)
{
insert(&start, E_name, E_age, E_deptid, E_cmpname, E_salary);
}
The insert function has a buggy loop to find the insertion point. prev will be a NULL pointer here:
while(current != NULL && strcmp(current->personalInfo.name,
prev->personalInfo.name) >0 )
{
prev = current;
current = current->next;
}
Suggested fix:
void insert(EmpTagPtr *s, char E_name[], int E_age, int E_deptid,
char E_cmpname[], double E_salary)
{
// create an empty node
EmpTagPtr newNode = malloc(sizeof *newNode);
// filling in the values
strcpy(newNode->personalInfo.name, E_name);
newNode->personalInfo.age = E_age;
newNode->officialInfo.deptId = E_deptid;
strcpy(newNode->officialInfo.cmpName, E_cmpname);
newNode->officialInfo.salary = E_salary;
// use `newNode` in the comparison:
while (*s && strcmp(newNode->personalInfo.name,
(*s)->personalInfo.name) > 0)
{
s = &(*s)->next;
}
// `s` now points at the `EmpTagPtr` pointer where the new node should
// be inserted for the list to be sorted in alphabetical order.
// If it's the first node to be inserted, `s` points at `start` so
// you do not need `prev` or `current`:
newNode->next = *s;
*s = newNode;
}
Demo
As can be seen in the demo, your program leaks memory so you need to add a function to clean that up.
More about the insertion logic:
Think of start as the next member of an imaginary first dummy node and s starts out pointing at start.
If the linked list has zero elements, start will point at NULL.
*s will therefore be == NULL and the while loop will not do any laps.
You now assign newNode->next = *s (which is NULL) and assign *s = newNode (which means start will point at newNode). The first node is now completely linked.
If the linked list has more than zero elements, the while loop will compare the name of the newNode with that of the dereferenced s's name. EmpTagPtr current = *s; followed by current->personalInfo.name is the same as (*s)->personalInfo.name.
If strcmp(newNode->personalInfo.name, (*s)->personalInfo.name) > 0 we haven't found the insertion point and step s to point at the next node's next member, s = &(*s)->next - and loop to check the conditions again.
If the condition is false it means that newNode should be inserted between the node to which the next member s points at belongs and the *s node - and the loop terminates. When the loop terminates s will therefore point at a next member where the new node should be inserted.
It can be hard to "see" it without actually doing this with pen and paper so I recommend doing just that. Insert 3 nodes using only pen and paper and draw the pointers to see where everything ends up. It usually gives me an "aha!" moment.
As Allan Wind already commented on your question, the first problem was that you had commas in fscanf even though your data is seperated by spaces.
A bigger problem is that segmentation fault occurs in the following while loop in your insert() function
while(current != NULL && strcmp(current->personalInfo.name , prev->personalInfo.name) >0 )
{
prev = current;
current = current->next;
}
This happens because you are accesing personalInfo of prev when prev is set to NULL. I assume that what you wanted to do here is insert an elemente into the linked list so that the list stays sorted alphabetically by names. In that case, you must compare names of current and newNode in strcmp and NOT names of current and prev. Your condition in the while loop should look like this:
while(current != NULL && prev != NULL && strcmp(current->personalInfo.name , newNode->personalInfo.name) > 0 )
I think an important point to improve your programme is database normalization. You might end up with roughly:
Where, person.txt is (an example),
1 Peter 30
2 Joseph 50
3 Mary 40
works.txt
1 1001 8000
2 1002 4000
3 1002 6000
department.txt
1001 1
1002 1
company.txt
1 Apple
Instead of duplicating data, this reduces data redundancy. This is good for if you want to add or make changes to your database. It also mirrors the usage (somewhat) in your programme.
Related
I had a problem and I cannot seem to find a solution.I tried to do a simple program that creates a list and prints it in C, but when i tried to run it it looped printing the first value of the list.This is the program if anyone could help plz:
I tried adding parenthesis etc but didn't work.
#include <stdio.h>
#include <stdlib.h>
typedef struct nodo{
int dato;
struct nodo *next;
}nodo_t;
typedef nodo_t *Ptr_nodo;
int main(){
Ptr_nodo testa,temp;
int q;
temp=NULL;
testa=NULL;
temp=malloc(sizeof(nodo_t));
if(temp){
q=0;
while(q!=-1){
printf("Inserire valore: ");
scanf("%d",&q);
if(q!=-1){
temp->dato=q;
temp->next=testa;
testa=temp;
}
}
while(testa!=NULL){
printf("%d",testa->dato);
if(testa->next!=NULL)
printf(" -> ");
else
printf(" -|");
testa=testa->next;
}
}
else
printf("Errore allocazione memoria"),
free(temp);
return 0;
}
I tried out your code and got the repeated printing of the one node which was pointing to itself. What appeared to be missing was when more data was being entered, new nodes needed to be created with memory allocated for each node. With that in mind, following is a refactored version of your code.
#include <stdio.h>
#include <stdlib.h>
typedef struct nodo{
int dato;
struct nodo *next;
}nodo_t;
typedef nodo_t *Ptr_nodo;
int main(){
Ptr_nodo testa,temp;
int q;
temp=NULL;
testa=NULL;
temp=malloc(sizeof(nodo_t));
testa = temp;
if(temp){
q=0;
while(q!=-1){
printf("Insert Value: ");
scanf("%d",&q);
if(q!=-1){
temp->dato=q;
temp->next=malloc(sizeof(nodo_t)); /* Created new node and allocate memory */
temp=temp->next;
temp->next = NULL; /* Make sure this latest node has the NULL terminator */
}
}
while(testa!=NULL){
printf("%d",testa->dato);
if(testa->next!=NULL)
printf(" -> ");
else
printf(" -|");
testa=testa->next;
}
printf("\n"); /* Just added this for appearances on the terminal output */
}
else
printf("Memory allocation error"),
free(temp);
return 0;
}
Some bits to point out.
When another value is received from the user, a new node needs to be created with memory allocated via the "malloc" function.
Pointer references for the previous node and new node need to be updated once the new node is created.
In the new node, its "next" pointer needs to be set to NULL so as to ensure that the subsequent list printing does not get caught up in an endless loop.
With those bits added, following was a sample output at the terminal.
#Vera:~/C_Programs/Console/MultiNode/bin/Release$ ./MultiNode
Insert Value: 4
Insert Value: 1998
Insert Value: 22
Insert Value: 45
Insert Value: 88
Insert Value: -1
4 -> 1998 -> 22 -> 45 -> 88 -> 0 -|
One small side effect I saw was that the final node has a value of zero. I don't know if that is a desired outcome, but I will leave that as something to possibly be refined.
Give that a try and see if it meets the spirit of your project.
draw it out:
temp = malloc(...); // creates a node
+------------+
temp --> | data: ?? |
| next | --> ?? points nowhere right now
+------------+
testa --> NULL
You scanf your data, just call it 5
scanf("%d",&q); // user inputs 5
if(q!=-1){
// set data
temp->dato=q;
temp->next=testa;
+------------+
temp --> | data: 5 |
| next | --> testa, which is NULL right now
+------------+
testa=temp; // results in testa and temp pointing to the same node
+------------+
temp --> | data: 5 |
testa --> | next | --> NULL
+------------+
}
Now you loop back around
scanf("%d",&q); // user inputs 8
if(q!=-1){
// whoops, didn't create a new node, so it's still the same temp from before
temp->dato=q;
temp->next=testa;
testa=temp;
+------------+
temp --> | data: 8 |
testa --> | next | --> testa, which is the same as temp -----+
+------------+ |
^ |
| |
+-------------------------------------------------+
You have one node that points to itself. You need to create a new node on each user entry, I trust the other answer(s) show you how to do that.
You allocated only one node within the program
temp=malloc(sizeof(nodo_t));
if(temp){
//...
Then within the following while loop
while(q!=-1){
printf("Inserire valore: ");
scanf("%d",&q);
if(q!=-1){
temp->dato=q;
temp->next=testa;
testa=temp;
}
}
You are changing the data member dato of the same node because the pointer temp always points to the early allocated single node before the while loop and neither new nodes are being allocated
Its data member next points to the node itself except the first iteration of the loop when the data member next is set to the value of the pointer testa that initially was set to NULL.
So you are outputting the same node that stores the last entered value in its data member dato.
Also if the user at once will enter the value -1 then you will have uninitialized node that results in undefined behavior in the loop where the list is outputted.
You need to allocate new nodes using malloc that will store subsequent entered values. And at the end of the program you should free all the allocated nodes.
Your program can look for example the following way.
#include <stdio.h>
#include <stdlib.h>
typedef struct nodo{
int dato;
struct nodo *next;
}nodo_t;
typedef nodo_t * Ptr_nodo;
int main( void )
{
Ptr_nodo testa = NULL
while ( 1 )
{
Ptr_nodo temp = NULL;
int valore;
printf( "Inserire valore in lista (-1 - esci): " );
if ( scanf( "%d", &valore ) != 1 || valore == -1 || ( temp = malloc( sizeof( *temp ) ) ) == NULL )
{
break;
}
temp->dato = valore;
temp->next = testa;
testa = temp;
}
for ( Ptr_nodo temp = testa; temp != NULL; temp = temp->next )
{
printf( "%d -> ", temp->dato );
}
puts ( "null" );
while ( testa )
{
Ptr_nodo temp = testa;
testa = testa->next;
free( temp );
}
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 40
struct ticket
{
char *visitor;
struct ticket *nextPtr;
};
// insert a new value into ticket data list
void append(struct ticket **head_ref, char *visitor)
{
// allocate node
struct ticket *new_node = (struct ticket *)malloc(sizeof(struct ticket));
struct ticket *last = *head_ref;
// put in the data
new_node->visitor = visitor;
// This new node is the last node
new_node->nextPtr = NULL;
// If the Linked List is empty, then make the new node as head
if (*head_ref == NULL)
{
*head_ref = new_node;
return;
}
// Else traverse till the last node */
while (last->nextPtr != NULL)
{
last = last->nextPtr;
}
// Change the next of last node
last->nextPtr = new_node;
return;
}
// This function prints contents of linked list starting from head
void printList(struct ticket *node)
{
while (node != NULL)
{
printf("\n%s", node->visitor);
node = node->nextPtr;
}
}
char Name[31] = {'\0'};
int main(void)
{
/* Start with the empty list */
struct ticket *head = NULL;
int i = 0;
printf("Name: "); // instruction
scanf("%[^\n]%*c", Name);
append(&head, Name);
printList(head);
printf("Name: "); // instruction
scanf("%[^\n]%*c", Name);
append(&head, Name);
printList(head);
return 0;
}
I want to store some string the linked list, but when I try to input any string and add to the linked list, all the previous value of the linked list has been changed to the last string that I have enter.
What I get ->
Name: Chris
Chris
Name: Lebron
Lebron
Lebron
What I expect ->
Name: Chris
Chris
Name: Lebron
Chris
Lebron
As noted your program currently just stores a link to the character array. Following is one route you might go with storing a name in your linked list if you can afford to limit your names to a specific character length.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 40
struct ticket
{
char visitor[MAX]; /* Utilized your maximum length */
struct ticket *nextPtr;
};
// insert a new value into ticket data list
void append(struct ticket **head_ref, char *visitor)
{
// allocate node
struct ticket *new_node = (struct ticket *)malloc(sizeof(struct ticket));
struct ticket *last = *head_ref;
// put in the data
// new_node->visitor = visitor;
strcpy(new_node->visitor, visitor); /* Store the name in this fashion */
// This new node is the last node
new_node->nextPtr = NULL;
// If the Linked List is empty, then make the new node as head
if (*head_ref == NULL)
{
*head_ref = new_node;
return;
}
// Else traverse till the last node */
while (last->nextPtr != NULL)
{
last = last->nextPtr;
}
// Change the next of last node
last->nextPtr = new_node;
return;
}
// This function prints contents of linked list starting from head
void printList(struct ticket *node)
{
printf("\nNames\n-------------------\n");
while (node != NULL)
{
printf("%s\n", node->visitor);
node = node->nextPtr;
}
}
char Name[31] = {'\0'};
int main(void)
{
/* Start with the empty list */
struct ticket *head = NULL;
//int i = 0;
printf("Enter name(s) or type 'quit' to end entry\n\n");
while (1) /* Allow for variable number of vistors to be entered and stored */
{
printf("Name: "); // instruction
scanf("%[^\n]%*c", Name);
if ((strcmp(Name, "quit") == 0))
{
break;
}
append(&head, Name);
}
printList(head);
return 0;
}
Utilizing the "MAX" constant in your code, the linked list structure was revised to allocate enough storage for a character string of 39 characters plus the NULL terminator. Along with a slight tweak to the input of names in the main function, the program can be tested with the entry of one or more names.
Following is a sample output illustrating the storage and retrieval of your linked list data.
#Dev:~/C_Programs/Console/LinkedList/bin/Release$ ./LinkedList
Enter name(s) or type 'quit' to end entry
Name: Chris
Name: Lebron
Name: Milly
Name: Joe
Name: quit
Names
-------------------
Chris
Lebron
Milly
Joe
You might want to explore other approaches for allocating variable amounts of character data down the road, but you might want to utilize the simple fixed length approach for storing string data in your linked list structure if you have a feel for the maximum length of the names to be stored.
Give that a try to see if it meets the spirit of your project.
This question already has answers here:
Delete node from Linked List
(3 answers)
Closed 1 year ago.
I'm trying to delete a data from linked list loaded from drivers.txt and I haven't got any ideas to how to do it...
So to imagine this is my drivers.txt file.
***
Carl
RedBull
***
John
Mercedes
***
Jessica
Mercedes
***
Brandon
RedBull
I'm trying to remove every driver driving for RedBull. So when I print next time I want to see only John and Jessica.
My struct:
typedef struct drivers {
char *name;
char *team;
struct drivers *next;
} drivers_t;
How I load the drivers.txt.
drivers_t *drivers_load(const char *file){
int i = 0;
FILE *fp = fopen("drivers.txt", "r");
drivers_t *ptr = NULL;
drivers_t *head = NULL;
char buffer[255];
while (fgets(buffer, 255, fp) != NULL){
switch(i++){
case 0:
if( !ptr ) {
ptr = drivers_new();
head = ptr;
}
else {
ptr->next = drivers_new();
ptr = ptr->next;
}
break;
case 1:
ptr->name = strdup(buffer);
break;
case 2:
ptr->team = strdup(buffer);
break;
i = 0;
break;
}
}
return head;
}
My print function:
void drivers_print(drivers *head){
int number = 1;
for (drivers_t *drivers = head; drivers != NULL; drivers = drivers->next){
printf("%d.\n", number++);
printf("Driver: %s", drivers->presenter);
printf("Team: %s", drivers->birth_number);
}
}
Thanks in advance for any ideas.
Deleting node:
void node_delete(drivers_t *head){
char team[32];
scanf("%s", &team);
strcat(team, "\n");
for (node_t *node = head; node != NULL; node = node->next){
if(strcmp(node->team, team) == 0){
drivers_t *temp;
temp = head->next;
head->next = temp->next;
free(temp);
}
else{}
}
}
If you have a list like this:
A -> B -> C -> D -> E
and you want to delete C, all you need to do is to ensure that the next pointer of B now points to D, so you get:
A -> B -> D -> E
Basically the algorithm is:
Go down the list and find C, the node you want to remove.
While going down the list, always also remember the last node you have seen, which would be B in that case.
Once you reached C, assign the next pointer value of C to the next pointer value of B and you are done, as now going over the list directly jumps from B to D.
Finally clean up C, which means free any memory C or any of its struct fields are using.
The only tricky case is the first node, as removing A is a special case, in which case you must set the list pointer itself to the next value of A, so the list now starts with B. You can recognize that case easily, though, as in step (2) you have remembered the last node. When you start, there is no last node, so initially that value should start with NULL. If you found the node (step 3) and the last one is NULL, you will know that you just hit the first node and you can handle that case appropriately.
Yesterday after I did a stupid approach, I think I am on a good way right now. The thing I wanna program is that I am getting n values from the user and I am trying to store every value into a linked list node which has to be sorted after every input.
So it means:
Input:
5 1 9
Output:
1 5 9
Input:
2 3
Output:
1 2 3 5 9
My code so far:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
typedef struct node {
int val;
struct node* next;
} node;
void printList(node* n) {
while (n != NULL) {
printf("%d ", n->val);
n = n->next;
}
}
void push(node * head, int val) {
node * current = head;
while (current->next != NULL) {
current = current->next;
}
/* now we can add a new variable */
current->next = malloc(sizeof(node));
current->next->val = val;
current->next->next = NULL;
}
int main() {
char input[20];
char* ptr;
node* head = NULL;
head = (node*) malloc(sizeof(node));
do {
printf("Eingabe:");
fgets(input,20,stdin);
ptr = strtok(input," ");
while(ptr!=NULL){
int val = atoi(ptr);
push(head,val);
ptr = strtok(NULL, " ");
}
printList(head);
}
while(*input != '0');
return 0;
}
Edited my code, node creation is working , but when I input 5 1 9 , it outputs 0 5 1 9 where is that 0 coming from?
The 0 is the value of your head.
When you create the first node you add it as the next of the head, this means that by having as input 5 1 9 your linked list will be:
head -> 5 -> 1 -> 9
When you print you don't just print the values of the nodes you have created but also the value of the head, since the value was never initialized and in the struct it's an int your compiler intializes it to 0 automatically (this depends on the compiler implementation so it's always better to initialize it).
If you don't want that 0 in the front you have a couple of options:
assign to head->value the first number that you input
call the printList as printList(head->node)
change your linked list implementation to not have the head hold a value
change printList to:
void printList(node* n) {
n = n->next;
while (n != NULL) {
printf("%d ", n->val);
n = n->next;
}
}
The correct approach could be (pseudo-code):
[START]
Read new line from the STDIN;
While there are new values:
Read new value;
Add it on new node (easier adding on top of the list);
Sort the list;
Print the list;
Loop to [START]
In your code you are missing the "sort the list" phase.
Easier if you add a swap function and try one of sorting algorithm on your choice
I'm having an issue: in a function, program needs to compare two nodes and delete one of them if the node values are the same (example: A -> B -> B -> C >>> A -> B -> C). In a few words: it have to leave only unique nodes.
Steps that I've done: created list from data given in data file and it prints out perfectly. Now I'm struggling comparing two nodes.
Steps that I'm thinking of doing: Put two nodes values in two different variables, then comparing those two and if latest node is equal to previous, delete the latest and somehow link previous node to next node. Then the cycle goes all over again.
Question: How do I compare node with further one?
Here's the code that I have right now:
#include <stdio.h>
#include <stdlib.h>
#define LENGTH 255
struct node {
int info;
struct node *next;
} *head = NULL;
int create(FILE **data){
char read[LENGTH];
printf("Write data file name: ");
scanf("%s", read);
*data = fopen (read, "r");
if (data == NULL) {
printf("Error reading given file.");
}
return 0;
}
int put_Symbols_into_list(FILE *data) {
struct node *new_node, *current;
char c;
printf("Data given: ");
while (!feof(data)){
new_node = (struct node*)malloc(sizeof (struct node));
c = fscanf(data, "%s", &new_node -> info);
printf("%s ", &new_node -> info);
if (head == NULL){
head = new_node;
current = new_node;
} else {
current -> next = new_node;
current = new_node;
}
}
}
int delete_Same_Symbols() {
}
int main() {
FILE *data;
struct node *n;
create(&data);
put_Symbols_into_list(data);
delete_Same_Symbols();
//display_List(n);
return 0;
}
An efficient way of remove duplicates is the following:
1. Sort the list
2. Run through the list once deleting any adjacent duplicates.
Whether this solution works for you depends on whether your data can be ordered.
Traverse the list from head to end and maintain a Hash table.
For every element,check whether value is in the hash table: if yes, remove the node; else put value in the hash table.
Time Complexity: O(n) on average (assuming that hash table access time is O(1) on average).
I'll give you the function that will remove the duplicates.
Assuming that your code is working fine and that the info is an int value
Note that if info is a string you will need strcmp function instead of head->info == info.
int exist(NODE *head, int info) {
while (head && head->info != info) // strcmp(info,head->info) != 0
head = head->next;
return head->info == info; // strcmp(info,head->info)
}
void removeDuplicates(NODE **phead, int info) {
NODE *tmp = *phead;
while (tmp->info != info) // strcmp(info,head->info) != 0
tmp = tmp->next;
NODE *tmp1 = tmp->next;
tmp->info = tmp1->info; // strcpy(tmp->info,tmp1->info)
tmp->next = tmp1->next;
free(tmp1);
}