Возможно, вы сможете что-то сделать с помощью хитрых приемов препроцессора, но ваш код будет трудным для чтения.Я думаю, что я бы выбрал действительно низкотехнологичное решение и просто добавил массив имен функций, совпадающих с массивом указателей функций:
#define ARRAY_SIZE(A) (sizeof(A)/sizeof(A[0]))
// Pointer to functions
char *(*srtFunc[])(int *, int) = {selection, bubble, recursiveBubble, insertion, recursiveInsertion};
const char *srtFuncNames[] = {"selection", "bubble", "recursiveBubble", "insertion", "recursiveInsertion"};
_Static_assert(ARRAY_SIZE(srtFuncNames)==ARRAY_SIZE(srtFunc), "Function table and names out of synch!");
Наличие двух определений сразу после друг друга облегчаетсинхронизируйте их, и код легко читается._Static_assert
(доступно из C11) поможет запомнить новые имена при добавлении новых функций.
В качестве альтернативы можно определить структуру, содержащую указатель функции и соответствующее имя.Это можно инициализировать с помощью макроса следующим образом:
typedef struct
{
char *(*srtFunc)(int *, int);
const char *srtName;
} sortMethod;
#define SORT_METHOD(S) {(S), #S}
sortMethod methods[] = {
SORT_METHOD(selection),
SORT_METHOD(bubble),
SORT_METHOD(recursiveBubble),
SORT_METHOD(insertion),
SORT_METHOD(recursiveInsertion)
};