main.c

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

#include "sort_strings.h"

int main(int argc, char** argv) {
    sort_strings(argv+1, argc-1);
    for (int i = 1; i < argc; i++) {
        printf("%s ", argv[i]);
    }
    printf("\n");
}

sort_strings.h

#ifndef SORT_STRINGS_H
#define SORT_STRINGS_H

// Sorts strings in place
// Pre: arr is a valid pointer to an array of strings
//      arr is len long
// Post: arr is an array of strings sorted in strcmp order
void sort_strings(char** arr, int len);

#endif

selsort_strings.c

#include <string.h>

#include "sort_strings.h"

void swap(char** a, char** b) {
    char* tmp = *a;
    *a = *b;
    *b = tmp;
}

void sort_strings(char** arr, int len) {
    for (int i = 0; i < len; i++) {
        int minIndex = i;
        for (int j = i+1; j < len; j++) {
            if (strcmp(arr[minIndex], arr[j]) > 0) {
                minIndex = j;
            }
        }
        swap(&arr[i], &arr[minIndex]);
    }
}

qsort_strings.c

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

#include "sort_strings.h"


/* The actual arguments to this function are "pointers to
   pointers to char", but strcmp(3) arguments are "pointers
   to char", hence the following cast plus dereference */
int cmpstringp(const void *p1, const void *p2) {
   return strcmp(*(char* const*) p1, *(char* const*) p2);
}

void sort_strings(char** arr, int len) {
    qsort(arr, len, sizeof(char*), cmpstringp);
}

Makefile

all: qsort_strings selsort_strings

qsort_strings: qsort_strings.o main.o
    gcc $(COPTS) -o $@ $^

selsort_strings: selsort_strings.o main.o
    gcc $(COPTS) -o $@ $^

qsort_strings.o: qsort_strings.c sort_strings.h
    gcc $(COPTS) -c $<

selsort_strings.o: selsort_strings.c sort_strings.h
    gcc $(COPTS) -c $<

main.o: main.c
    gcc $(COPTS) -c $<

clean:
    rm -f qsort_strings selsort_strings *.o *~