0

I have this csv file:

NAME, NUMBER, ADDRESS, EMAIL
Kevin, +62 812-xxx-xxx, Jln.Anggrek Merah 3, [email protected]
Adwi, +62 821-xxxx-xxxx, Jln.Ruhui Rahayu, [email protected]
Wasis, +62 813-xxxx-xxxx, Jln.Pramuka 6 25, [email protected]
Alief, +62 811-xxxx-xxx, Jln.Padat Karya, [email protected]

This is my code:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX 50

typedef struct Contact
{
    char name[MAX];
    char number[MAX];
    char address[MAX];
    char email[MAX];
    struct Contact *next;
} 
Contact;

void create_linkedList(Contact **start, Contact p)
{
    Contact *new = malloc(sizeof(Contact));
    strcpy(new->name, p.name);
    strcpy(new->number, p.number);
    strcpy(new->address, p.address);
    strcpy(new->email, p.email);

    new->next = *start;
    *start = new;
}

void printList(Contact *start)
{
    Contact *cursor = start;
    while (cursor != NULL)
    {
        printf("%s\n", cursor->name);
        cursor = cursor->next;
    }
}

void sorting(Contact *start)
{
    Contact *cursor = start, *traverse = NULL;
    Contact *tmp, *tmp_next;
        
    while (cursor != NULL)
    {
        traverse = cursor;

        while (traverse->next != NULL)
        {
            if (strcasecmp(traverse->name, traverse->next->name) > 0)
            {
                tmp = traverse;
                tmp_next = traverse->next->next;
    
                traverse->next = tmp;

                traverse->next->next = tmp_next;
            }
            traverse = traverse->next;
        }
        printf("Prepare!\n");
        cursor = cursor->next;
    }
}

int main(void)
{
    FILE *file = fopen("contacts.csv", "r");
    if (file == NULL)
        return 1;

    Contact person;
    Contact *start = NULL;

    // Loop inside csv file til' the end of file
    while(fscanf(file, "%[^,], %[^,], %[^,], %[^\n] ", person.name, person.number, person.address, person.email) == 4)
    {   
        # Skip header file from csv
        if (strcmp("NAME", person.name) == 0) 
            continue;
        
        create_linkedList(&start, person);
    }    

    printList(start);

    // Swapped
    sorting(start);

    printList(start);

    return 0;
}

So, after i successfully created a linked list that connect each person data in my csv file, i want to sort it by their name and then print it. But if you compile my code, it causes segmentation fault.

In my sort() function i try to change the node (next) of each person. Because i think if i only swap the value of each element, the node (next) will still point same person as before. So i was thinking maybe i can only swap the node (next).

I can do it if it's only sorting value in an array. But linked list it's difficult for me as beginner.

Can you help me, please? Maybe write me some new code and explain the solution, if you guys have it. Thanks!

2 Answers 2

1

When you want to create a linked list, you should use a struct Cell that contains two types of date: the first is your data itself (Contact in your case) the other is a pointer to the next cell in the list (next). Using this type of implementation you make your code more readable, modular and reusable.

typedef struct Contact
{
   char name[MAX];
   char number[MAX];
   char address[MAX];
   char email[MAX];
   struct Contact *next;
}
Contact;

typedef struct ContactCell {
   Contact info;
   struct ContactCell* next;
}
ContactCell;
typedef ContactCell* ContactList;

Using the implementation above your functions would be:

void addContactToList(ContactList start, Contact p)
{
   ContactCell* aux = malloc(sizeof(ContactCell));
   aux->info = p;

   aux->next = start;
   start = aux;
}

void printList(ContactList start)
{
   ContactList cursor = start;
   while (cursor != NULL)
   {
    printf("%s\n", cursor->info.name);
    cursor = cursor->next;
   }
}

For the sorting I would have swapped the info between the cell (using the implementation above), because this method makes the swapped easier to understand especially for a type of data like Contact (not weighty to be swapped using a third variable). The following version uses selection sort algorithm (not super efficient, but easier).

void sorting(ContactList start)
{

  for (ContactList i= start; i!=NULL; i = i->next)
  {
     ContactList current_min = i;

     for (ContactList j=i->next ;j!=NULL; j = j->next)
        if (strcasecmp(current_min->info.name,j->info.name) > 0)
           current_min = j;

     //swap using a Contact aux variable
     Contact tmp = i->info;
     i->info = current_min->info;
     current_min->info = tmp;
  }

}
Sign up to request clarification or add additional context in comments.

3 Comments

So i don't need to add struct Contact *next; inside my Contact, instead i can only use struct Cell to linked them just like your code? Which means my create_linkedList isn't necessary?
Exactly in this way you separate your data structure (list rapresented by cell pointers) and the type of data your working on (Contact). If you want to be more precise you can add a function create_linkedlist that creates a Contact list initialized to NULL (only to improve information hiding in your code)
Thank you very much! I really like when u said better use separate struct to create a linked list. Didn't know it before!
1

Rather than pass around double star pointers (e.g. Contact **start), I prefer a separate List struct. This can be [easily] be expanded for a doubly linked list.

Also, I always pass a struct to a function with a pointer. Passing by value [as you're doing when creating the list] is slower. And, in the general case would cause a stack overflow if the struct was large (e.g. it had an element: int data[10000000];)

I had some difficulty understanding your sorting logic. And, using traverse->next->next seems problematic to me. I couldn't tell exactly what your sorting algorithm was based on. I'm guessing it was trying to do an insertion sort [but I could easily be wrong].

I'm more familiar with mergesort for linked lists that pull from source lists and append to a destination list during the merge phase. That would be fast(er), and it adapts well to linked lists.

But, rather than get that far afield from your code, I adapted some of the logic from that to create a selection sort [I think].

Anyway, here's the refactored code:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX 50

typedef struct Contact {
    char name[MAX];
    char number[MAX];
    char address[MAX];
    char email[MAX];
    struct Contact *next;
} Contact;

typedef struct {
    Contact *head;
} List;

void
create_linkedList(List *list, Contact *p)
{
    Contact *new = malloc(sizeof(Contact));

    strcpy(new->name, p->name);
    strcpy(new->number, p->number);
    strcpy(new->address, p->address);
    strcpy(new->email, p->email);

    new->next = list->head;
    list->head = new;
}

void
printList(List *list)
{
    Contact *cursor = list->head;

    printf("List:\n");
    while (cursor != NULL) {
        printf("  %s\n", cursor->name);
        cursor = cursor->next;
    }
}

void
sorting(List *list)
{
    Contact *oldhead = list->head;
    Contact *newhead = NULL;
    Contact *newprev = NULL;

    while (oldhead != NULL) {
        // lowest element to be selected
        Contact *bestcur = oldhead;
        Contact *bestprev = NULL;

        // find the lowest element in remaining list
        Contact *travprev = NULL;
        Contact *travcur = oldhead;
        for (;  travcur != NULL;  travcur = travcur->next) {
            if (strcasecmp(bestcur->name,travcur->name) > 0) {
                bestcur = travcur;
                bestprev = travprev;
            }
            travprev = travcur;
        }

        // remove selected element from old list
        if (bestprev != NULL)
            bestprev->next = bestcur->next;
        else
            oldhead = bestcur->next;

        bestcur->next = NULL;

        // append to new list
        if (newprev != NULL)
            newprev->next = bestcur;
        else
            newhead = bestcur;
        newprev = bestcur;
    }

    list->head = newhead;
}

int
main(void)
{
    FILE *file = fopen("contacts.csv", "r");

    if (file == NULL)
        return 1;

    Contact person;
    List *list = calloc(1,sizeof(*list));

    // Loop inside csv file til' the end of file
    while (fscanf(file, "%[^,], %[^,], %[^,], %[^\n] ",
        person.name, person.number, person.address, person.email) == 4) {
        // Skip header file from csv
        if (strcmp("NAME", person.name) == 0)
            continue;

        create_linkedList(list, &person);
    }

    printList(list);

    // Swapped
    sorting(list);

    printList(list);

    return 0;
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.