1

manページに従ってqsortを使用しようとしていますが、何を試してもsegfaultが発生し続けます

重要なコードのセクションは次のとおりです

int compare_dirent(const void *a, const void *b)
{
    const struct dirent *first = (const struct dirent *) a;
    const struct dirent *second = (const struct dirent *) b;

    return first->d_ino - second->d_ino;
}


int process(FILE* output,const char *dirname, int flags)
{
    struct dirent *entries = NULL;
    struct dirent *table[256];
    int entry_num = 0;
    DIR *directory = NULL;
    char cwd[1024];

    getcwd(cwd,1024);
    bzero(table,256);

    directory = opendir(dirname);
    while((entries = readdir(directory))!=NULL)
    {
        if(entries->d_type == DT_REG)
        {
            fprintf(output,"%s\t\n",entries->d_name);
            table[entry_num] = entries;
            entry_num++;
        }
    }
    fprintf(stderr,"last entry: %s\n", table[entry_num-1]->d_name);

    /* RIGHT HERE */
    qsort(table, entry_num, sizeof(struct dirent), &compare_dirent);

    return entry_num;
}

gdb を実行するfprintfと、while ループごとにディレクトリ内のファイルのリストが表示され、最後のエントリが表示されます。N回実行される比較にブレークポイントを配置しました。Nはファイルの数であり、すぐに_qsortからSEGFAULTを取得します。

qsort からの compare_dirent への N 回目の呼び出しで、クラッシュします。

ここにgdb出力があります

Starting program: /Users/luke/Documents/Dev/code/cs647/prog2/bin/prog2 ./
Reading symbols for shared libraries +........................ done
.main.c.swp 
get_pdf.sh  
main.c  
main.o  
Makefile    
program2.pdf    
test.txt    
last entry: test.txt

Breakpoint 1, compare_dirent (a=0x7fff5fbff018, b=0x7fff5fbfec00) at main.c:88
88      const struct dirent *first = (const struct dirent *) a;
(gdb) n
89      const struct dirent *second = (const struct dirent *) b;
(gdb) n
91      return first->d_ino - second->d_ino;
(gdb) c
Continuing.

Breakpoint 1, compare_dirent (a=0x7fff5fbff430, b=0x7fff5fbfec00) at main.c:88
88      const struct dirent *first = (const struct dirent *) a;
(gdb) c
Continuing.

Breakpoint 1, compare_dirent (a=0x7fff5fbff848, b=0x7fff5fbfec00) at main.c:88
88      const struct dirent *first = (const struct dirent *) a;
(gdb) c
Continuing.

Breakpoint 1, compare_dirent (a=0x7fff5fbffc60, b=0x7fff5fbfec00) at main.c:88
88      const struct dirent *first = (const struct dirent *) a;
(gdb) c
Continuing.

Breakpoint 1, compare_dirent (a=0x7fff5fc00078, b=0x7fff5fbfec00) at main.c:88
88      const struct dirent *first = (const struct dirent *) a;
(gdb) c
Continuing.

Breakpoint 1, compare_dirent (a=0x7fff5fc00490, b=0x7fff5fbfec00) at main.c:88
88      const struct dirent *first = (const struct dirent *) a;
(gdb) c
Continuing.

Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_PROTECTION_FAILURE at address: 0x00007fff5fc00490
0x00007fff8e238540 in _qsort ()

解決策(完全)は両方の答えの少しでした

int compare_dirent(const void *a, const void *b)
{
    const struct dirent *first = (const struct dirent *) a;
    const struct dirent *second = (const struct dirent *) b;

    return first->d_ino - second->d_ino;
}


int process(FILE* output,const char *dirname, int flags)
{
    struct dirent *entries = NULL;
    struct dirent table[256];
    int entry_num = 0;
    DIR *directory = NULL;
    char cwd[1024];

    getcwd(cwd,1024);
    bzero(table,256);

    directory = opendir(dirname);
    while((entries = readdir(directory))!=NULL)
    {
        if(entries->d_type == DT_REG)
        {
            fprintf(output,"%s\t\n",entries->d_name);
            memcpy(table+entry_num, entries, sizeof(struct dirent));
            entry_num++;
        }
    }
    fprintf(stderr,"size: %lu\n", sizeof(struct dirent));
    qsort(table, entry_num, sizeof(struct dirent) , compare_dirent);

    fprintf(output,"\n\n");
    for(int i=0;i<entry_num;i++)
    {
        fprintf(output,"%s\n", table[i].d_name);
    }

    return entry_num;
}
4

2 に答える 2

5

あなたの問題の1つは次のとおりです。

qsort(table, entry_num, sizeof(struct dirent), &compare_dirent);

次のようにする必要があります。

qsort(table, entry_num, sizeof(struct dirent *), &compare_dirent);

3 番目の要素はwidth、各オブジェクトのサイズです。tableは の配列であるためstruct dirent *、それが必要なサイズです。

また、readdir によって返される値を誤用しています。ドキュメントから:

readdir() によって返されるポインタは、同じディレクトリ ストリームでの readdir() への別の呼び出しによって上書きされる可能性があるデータを指します。

つまり、テーブル内のすべての値が同じ値を持つ同じポインターである可能性が非常に高いということです。を使用するreaddir_rか、単に割り当てstruct dirent(readdir 呼び出しごとに 1 つ) して、値をその場で memcpy することができます。

別の方法として、配列に変更することもできます。struct direntこの場合、元のqsort呼び出しを使用します。

于 2012-04-10T00:03:55.077 に答える
3

あなたのコードは s を保存しませんdirent! それらへのポインタを保持するためにメモリを割り当てますが、実際のエントリを保持するためにメモリを割り当てることはありません。したがって、並べ替えると、ポインターは存在しなくなったオブジェクトを指します。

このコード行は壊れています:

table[entry_num] = entries;

dirent これにより、 nowを指すポインタが保存されます。しかし、そのポインターは、後でdirent. 後で使用するためにポインターを保存することはできません。実際のエントリを保存する必要があります。

readdir() によって返されたデータは、同じディレクトリ ストリームに対する readdir() への後続の呼び出しによって上書きされる場合があります。

したがって、次のようなものが必要です。

table[entry_name] = malloc(sizeof(struct dirent));
memcpy(table[entry_name], entries, sizeof(struct dirent));

完了したら、それらを解放することを忘れないでください。

マシュー・フラッシェンの答えも正しいです。に間違ったサイズを渡しましたqsort

于 2012-04-10T00:04:17.873 に答える