Использование stdlib's qsort () для сортировки массива строк - PullRequest
8 голосов
/ 20 марта 2011

Немного предисловия: я учусь на инженера-компьютерщика, беру первого класса по Си после 3 семестров Java (вплоть до структур данных) Этот вопрос относится к домашнему заданию, но несколько шагов от его решения для меня исключены.

У меня есть входной файл, который я читаю в память, так что он сохраняется в char [9] [500]. Я прочитал не более 500 строк максимальной длины 8. Я пытаюсь отсортировать этот массив, используя встроенную в stdlib функцию qsort (), и у меня возникают некоторые ошибки памяти.

Важные фрагменты кода:

char data[4][500][60];
char debug[500][9];
size_t count = 0;

/* initialize file, open for reading */
FILE* pUserlog;
pUserlog = fopen("userlog","r");

while(!feof(pUserlog))
{
    fscanf(pUserlog, "%9s %8s %16s",debug[count], data[1][count], data[2][count]);
    fgets(data[3][count], 60, pUserlog);
    count++;
}

В этом разделе данные считываются в массивы. Массив интереса в этой части - «отладка». Это массив, указанный выше. Вот моя функция сравнения для qsort:

int compare(const void* a, const void* b)
{
    const char **ia = (const char **)a;
    const char **ib = (const char **)b;
    puts("I'm in compare!");
    return strncmp(*ia, *ib,8);
}

Это моя попытка вызвать qsort:

size_t debug_len = sizeof(debug)/sizeof(char*);
printf("debug len: %d, count: %d, sizeof(char*): %d\n",debug_len,count,sizeof(char*));
qsort(debug,count, sizeof(char *), compare);

Я попытался заменить debug_len в моем вызове, где count, но я все еще segfaulting. Вот вывод:

$ ./test
debug len: 1125, count: 453, sizeof(char*): 4
I'm in compare!
Segmentation fault (core dumped)

Спасибо!

Ответы [ 2 ]

9 голосов
/ 20 марта 2011

Функция сравнения будет получать указатели на сравниваемые элементы. Вы фактически пытаетесь сравнить символы, используя strncmp(). Поскольку у вас есть указатели на каждую из строк, приведите ее к char * и сравните.

int compare(const void* a, const void* b)
{
    const char *ia = (const char *)a;
    const char *ib = (const char *)b;
    puts("I'm in compare!");
    return strncmp(ia, ib, 9);
}

Помните также, что это массив массивов, а не массив указателей. Таким образом, размер элемента должен быть размером массива 9, а не указателя 4. На этом этапе было бы проще использовать sizeof debug[0], поскольку это двумерный массив. Если вы не сделаете это с правильными размерами, qsort() просто уничтожит ваш массив.

size_t elemsize = sizeof debug[0];      /*   9 - size of each element */
size_t count = sizeof(debug)/elemsize;  /* 500 - number of elements in array */
qsort(debug, count, elemsize, compare);
4 голосов
/ 20 марта 2011

Что здесь происходит: у вас есть 500 строк. Теперь вы передаете все 500 в qsort, и он, в свою очередь, передает каждый из них в качестве первого и второго аргумента вашей функции сравнения. Это немного похоже на написание этого:

compare(debug[0], debug[1])

Компилятор C передает адреса, а не фактические значения, конечно. Но теперь вы интерпретируете указатель на пустоту как указатель на указатель на символ. Ваш код теперь выполняет разыменование при вызове strncmp, но это делает значение (первые 4 байта) обработанным как указатель в strncmp. Но strncmp теперь, в свою очередь, попытается разыменовать мусорный «указатель» (который состоит из части одной из ваших строк), и это сделает bang .

Чтобы это исправить, используйте char * вместо char **:

int compare(const void* a, const void* b)
{
    puts("I'm in compare!");
    return strncmp((const char *)a, (const char *)b, 8);
}
...