在 C 中使用 qsort 和简单的 strcmp 函数获取分段错误?
Getting segmentation fault using qsort and simple strcmp function in C?
GDB 打印命令提示我的数组及其内容的格式正确('asdf'
,'[=16=]000'
),但我在 qsort
调用中遇到了段错误,该错误可追溯到比较功能我通过了。我所能推测的是,我以某种方式传递了 qsort
一个空指针,或者我的字符串格式不正确,但对我来说似乎并非如此。
/** 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 ];
编辑:在问题中添加了 Word 的定义^^
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 函数接受一个 .txt 文件,其格式为:
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] = '[=13=]';
}
}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.
您的代码执行无效转换:qsort
向您传回指向 Word
的指针,但您的 cmp
函数将其视为指向 char
的 const 指针指针。
由于Word
是char
的固定大小数组的typedef
,它与指向指针的指针不同。您应该在 cmp
中执行指向指向 Word
的指针的强制转换,而不是指向指针的指针:
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);
}
GDB 打印命令提示我的数组及其内容的格式正确('asdf'
,'[=16=]000'
),但我在 qsort
调用中遇到了段错误,该错误可追溯到比较功能我通过了。我所能推测的是,我以某种方式传递了 qsort
一个空指针,或者我的字符串格式不正确,但对我来说似乎并非如此。
/** 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 ];
编辑:在问题中添加了 Word 的定义^^
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 函数接受一个 .txt 文件,其格式为:
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] = '[=13=]';
}
}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.
您的代码执行无效转换:qsort
向您传回指向 Word
的指针,但您的 cmp
函数将其视为指向 char
的 const 指针指针。
由于Word
是char
的固定大小数组的typedef
,它与指向指针的指针不同。您应该在 cmp
中执行指向指向 Word
的指针的强制转换,而不是指向指针的指针:
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);
}