2015-11-12 1 views
3

Команды печати GDB предполагают, что мой массив и его содержимое отформатированы правильно ('asdf', '\00000'), но я получаю segfault в моем вызове qsort, который возвращается к функции сравнения, которую я передаю. Все, что я могу догадаться, это то, что я каким-то образом передаю qsort нулевой указатель или что мои строки отформатированы неправильно, что, похоже, не так.Получение ошибки сегментации с использованием qsort и простой функции strcmp в C?

/** Word type, used to store elements of the word list, 
    with room for a word of up to 20 characters. */ 
typedef char Word[ WORD_MAX + 1 ]; 

редактировать: добавлено Definiton Слова на вопрос ^^

typedef struct { 
/** Number of words in the wordlist. */ 
int len; 
    /** Capacity of the WordList, so we can know when we need to resize. */ 
    int capacity; 
    /** List of words. Should be sorted lexicographically once the word list 
     has been read in. */ 
    Word *words; 
} WordList; 

Функция readWordList принимает в текстовый файл, который отформатирован:

3 the 
5 hello 
3 foo 
... 

Целое число представляет число символы в строке, которая следует за ним. validChar - это просто логическая проверка, чтобы увидеть, находится ли входящий символ в определенном диапазоне. Я удалил код, который не относится непосредственно к проблеме, такой как fopen и несколько инициализаций.

/** 
* comparison function for qsort in readWordList 
*/ 
static int cmp(const void *p1, const void *p2){ 
    return strcmp(* (char * const *) p1, * (char * const *) p2); 
} 

WordList *readWordList(char const *fname){ 
    //malloc space for newList 
    WordList *newList = (WordList *) malloc(sizeof(WordList)); 
    //set capacity to 10 
    newList->capacity = START_CAPACITY; 
... 
    newList->words = (Word *) calloc(newList->capacity, sizeof(Word)); 
... 
    while(fscanf(toRead, "%d ", &numChars) == 1) 
    { 
    //realloc space for Word *words if necessary 
    if(newList->len >= newList->capacity) 
    { 
     newList->capacity *= 2; 
     //check dereferencing 
     newList->words = (Word *)realloc(newList->words, newList->capacity * sizeof(Word)); 
    } 
    //if word is longer than 20 chars skip it 
    if(numChars > WORD_MAX) 
     continue; 
    else 
    { 
     for(int i = 0; i < numChars; i++) 
     { 
     ch = fgetc(toRead); 
      if(validChar(ch)){ 
      newList->words[newList->len][i] = ch; 
      if(i == numChars-1){ 
       newList->words[(newList->len)][numChars] = '\0'; 
      } 
      }else{ 
      continue; 
      } 
     } 
     //debug 
     printf("%s\n",newList->words[newList->len]); 
     //increase length of wordlist 
     newList->len += 1; 
    } 
    } 
    qsort(newList->words, newList->len, sizeof(Word), cmp); 
    return newList; 
} 

Вот моя ошибка Valgrind: (wordlist.c: 76) относится к qsort вызова;

==59199== Invalid read of size 1 
==59199== at 0x10000AAC9: _platform_strcmp (in /usr/local/Cellar/valgrind/3.11.0/lib/valgrind/vgpreload_memcheck-amd64-darwin.so) 
==59199== by 0x100000C92: cmp (wordlist.c:23) 
==59199== by 0x1001F2BDE: _qsort (in /usr/lib/system/libsystem_c.dylib) 
==59199== by 0x100000C5E: readWordList (wordlist.c:76) 
==59199== by 0x1000007A8: main (pack.c:52) 
==59199== Address 0x656874 is not stack'd, malloc'd or (recently) free'd 
==59199== 
==59199== 
==59199== Process terminating with default action of signal 11 (SIGSEGV) 
==59199== Access not within mapped region at address 0x656874 
==59199== at 0x10000AAC9: _platform_strcmp (in /usr/local/Cellar/valgrind/3.11.0/lib/valgrind/vgpreload_memcheck-amd64-darwin.so) 
==59199== by 0x100000C92: cmp (wordlist.c:23) 
==59199== by 0x1001F2BDE: _qsort (in /usr/lib/system/libsystem_c.dylib) 
==59199== by 0x100000C5E: readWordList (wordlist.c:76) 
==59199== by 0x1000007A8: main (pack.c:52) 
==59199== If you believe this happened as a result of a stack 
==59199== overflow in your program's main thread (unlikely but 
==59199== possible), you can try to increase the size of the 
==59199== main thread stack using the --main-stacksize= flag. 
==59199== The main thread stack size used in this run was 8388608. 
+3

Где определение 'слово'? –

+0

«Адрес 0x656874» Он читает строку '' \ x74 \ x68 \ x65 "' ('' ''), включая окончательный '' \ 0'', в качестве адреса. Другими словами, он разыменовывает 'char *' дважды. Вы уверены, что эти '' 'в вызове' strcmp' должны быть там? –

+1

В C вы не должны указывать результат 'malloc' (http://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc) или любую другую функцию, возвращающую' void * '(например,' realloc'). –

ответ

3

Ваш код выполняет недопустимый бросок: qsort передает вам обратно указатель на Word, но ваша cmp функции рассматривает его как константный указатель на указатель char.

Поскольку Word является typedef для массива фиксированного размера из char, это не то же самое, как указатель на указатель. Вы должны выполнить приведение к указателю Word в вашем cmp, а не указатель на указатель:

static int cmp(const void *p1, const void *p2){ 
    const Word *lhs = p1; 
    const Word *rhs = p2; 
    return strcmp((const char*)*lhs, (const char*)*rhs); 
} 
+0

Не передает ли 'qsort' указатели на элементы функции сравнения? Если 'Word' является указателем на' char', тогда 'cmp' должен получить указатель на указатель на' char' – Kevin

+0

@Kevin. Вы правы. Теперь, когда ОП предоставил определение «Word», мне нужно было отредактировать исправление. – dasblinkenlight

+0

Это была проблема, однако, я не настолько уверен в вашем использовании lhs и rhs, вы имели в виду использовать их в вызове strcmp? Независимо ... спасибо! – Harrison

Смежные вопросы