1

I'm trying to do a project... The project needs to read from a csv file that have contacts. The contacts have several fields that I read to an array of structs of type contact. Ex: array.contactFirstName, array contactLastName, etc. Here is some part of the code:

void string_InsertionSort(contact *array, int size, char *sortField){
    waitForKey();
    int i,j;
    contact key;
    if (strcmp(sortField, "First name") == 0){

        for (i = 1; i < size; i++){
            key=array[i];   
            j = i-1;                
            while ( (j >= 0) && strcmp(array[j].contactFirstName, array[j].contactFirstName) > 0){

                    array[j + 1] = array[j];
                    j--;    
                }
                array[j + 1] = key; 
            }

    }else if (strcmp(sortField, "Last name") == 0){

        for (i = 1; i < size; i++){
            key=array[i];
            j= i-1;
            while ( (j >= 0) && strcmp(array[j].contactLastName, array[j].contactLastName) > 0){
                array[j + 1] = array[j];
                j--;
            }
            array[j + 1] = key; 
        }

    }else{

        printf(" debuggggg");
    }
}

I'm implementing several sorting algoritms to sort the contacts in several diferent functions.

The problem that I have is, in the string_InsertionSort function, I pass an array of contacts, the size of the array, and the sort field that I want to order. Inside the function, I compare the sorting field to the fields that I have, and if is the correct one, I make the sorting.

The problem is that I have 15 different fields, so I have to repeat all the code to the diferent fiels. There is another way? If so, can anyone, make me an exemple? (kind accessing the struct member from outside)

Cœur
  • 37,241
  • 25
  • 195
  • 267
  • 1
    The aswer is probably: use a pointer to function to pass the compare function as an argument to a generic sort function. – wildplasser May 13 '17 at 17:51

1 Answers1

0

This is generally solved by passing in a function pointer to do the comparison, just like in qsort.

 void
 qsort(void *base, size_t nel, size_t width,
     int (*compar)(const void *, const void *));

The int (*compar)(const void *, const void *) means to pass in a function pointer that takes two void pointers and returns an integer. This allows generic sorting functions that can sort anything any way you like, but you have to write the comparison.

In your code, a function to sort by name might look something like:

int cmp_contact_names( const void *_a, const void *_b ) {
    // Copy the void pointers to their correct types.
    // Easier to work with than casting multiple times.
    const contact *a = _a;
    const contact *b = _b;

    // Sort by last name, then by first name.
    return strcmp( a->contactLastName, b->contactLastName ) ||
           strcmp( a->contactFirstName, b->contactFirstName );
}

Then that gets passed into qsort. The list to be sorted, the number of elements in the list, the size of each element, and the comparison function to use for sorting.

qsort(contacts, num_contacts, sizeof(contact*), cmp_contact_names);

Pattern your insertion sort after this, or better yet after qsort_r.

Unless this is an exercise, there's no point in writing your own insertion sort, use an existing one from a library. Or use a better sort, insertion sort isn't terribly efficient. Regardless, a hand written sort probably won't beat one from a good library, it just adds more code to maintain.

Schwern
  • 153,029
  • 25
  • 195
  • 336