用C段错误的qsort [英] qsort segfault in C

查看:150
本文介绍了用C段错误的qsort的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图按照手册页使用的qsort,但不管我怎么努力我不断收到一个段错误

下面是code的,重要

一节

  INT compare_dirent(常量无效*一,常量无效* B)
{
    常量结构的dirent *第一=(常量结构的dirent *)一个;
    常量结构的dirent *秒=(常量结构的dirent *)B:    回到一线>的d_ino - 二线>的d_ino;
}
INT过程(FILE *输出,为const char *目录名,INT标志)
{
    结构的dirent *条目= NULL;
    结构的dirent *表[256];
    INT entry_num = 0;
    DIR *目录= NULL;
    焦炭CWD [1024];    GETCWD(CWD,1024);
    bzero(表,256);    目录=执行opendir(目录名);
    而((项= READDIR(目录))!= NULL)
    {
        如果(entries-> d_type == DT_REG)
        {
            fprintf中(输出%s \\ t \\ n,entries-> d_name);
            表[entry_num] =条目;
            entry_num ++;
        }
    }
    fprintf中(标准错误,最后一项:%S \\ n,表[entry_num-1] - > d_name);    /* 就在这儿 */
    的qsort(表,entry_num,sizeof的(结构的dirent),放大器; compare_dirent);    返回entry_num;
}

在运行GDB我看到文件列表在while循环每目录fprintf中,我看到的最后一项。我把一个断点在比较哪个执行N次,其中N是文件的数量,然后我立刻得到_qsort段错误。

在第N个电话的qsort从崩溃到compare_dirent。

下面是GDB输出

 启动程序:/用户/卢克/文档/开发/ code / cs647 / PROG2 /斌/ PROG2 ./
阅读符号共享库+ ........................完成
.main.c.swp
get_pdf.sh
main.c中
main.o中
Makefile文件
program2.pdf
的test.txt
最后一个条目:test.txt的断点1,在compare_dirent main.c中(A = 0x7fff5fbff018,B = 0x7fff5fbfec00):88
88常量结构的dirent *第一=(常量结构的dirent *)一个;
(GDB)N
89常量结构的dirent *秒=(常量结构的dirent *)B:
(GDB)N
91回归一线>的d_ino - 二线>的d_ino;
(GDB)C
继续。断点1,在compare_dirent main.c中(A = 0x7fff5fbff430,B = 0x7fff5fbfec00):88
88常量结构的dirent *第一=(常量结构的dirent *)一个;
(GDB)C
继续。断点1,在compare_dirent main.c中(A = 0x7fff5fbff848,B = 0x7fff5fbfec00):88
88常量结构的dirent *第一=(常量结构的dirent *)一个;
(GDB)C
继续。断点1,在compare_dirent main.c中(A = 0x7fff5fbffc60,B = 0x7fff5fbfec00):88
88常量结构的dirent *第一=(常量结构的dirent *)一个;
(GDB)C
继续。断点1,在compare_dirent main.c中(A = 0x7fff5fc00078,B = 0x7fff5fbfec00):88
88常量结构的dirent *第一=(常量结构的dirent *)一个;
(GDB)C
继续。断点1,在compare_dirent main.c中(A = 0x7fff5fc00490,B = 0x7fff5fbfec00):88
88常量结构的dirent *第一=(常量结构的dirent *)一个;
(GDB)C
继续。节目接收信号EXC_BAD_ACCESS,无法访问内存。
原因:KERN_PROTECTION_FAILURE地址:0x00007fff5fc00490
0x00007fff8e238540在_qsort()

解决方案(完全)是一个小两个答案

  INT compare_dirent(常量无效*一,常量无效* B)
{
    常量结构的dirent *第一=(常量结构的dirent *)一个;
    常量结构的dirent *秒=(常量结构的dirent *)B:    回到一线>的d_ino - 二线>的d_ino;
}
INT过程(FILE *输出,为const char *目录名,INT标志)
{
    结构的dirent *条目= NULL;
    结构的dirent表[256];
    INT entry_num = 0;
    DIR *目录= NULL;
    焦炭CWD [1024];    GETCWD(CWD,1024);
    bzero(表,256);    目录=执行opendir(目录名);
    而((项= READDIR(目录))!= NULL)
    {
        如果(entries-> d_type == DT_REG)
        {
            fprintf中(输出%s \\ t \\ n,entries-> d_name);
            的memcpy(表+ entry_num,条目的sizeof(结构的dirent));
            entry_num ++;
        }
    }
    fprintf中(标准错误,大小:%吕\\ N的sizeof(结构的dirent));
    的qsort(表,entry_num,sizeof的(结构的dirent),compare_dirent);    fprintf中(输出\\ n \\ n);
    的for(int i = 0; I< entry_num;我++)
    {
        fprintf中(输出%s \\ n,表[I] .d_name);
    }    返回entry_num;
}


解决方案

你的一个问题是:

 的qsort(表,entry_num,sizeof的(结构的dirent),放大器; compare_dirent);

应该是:

 的qsort(表,entry_num,sizeof的(结构的dirent *)&安培; compare_dirent);

第三个元素是宽度,每个对象的大小。由于结构的dirent * 的数组,这是你想要什么样的规模。

你还滥用由readdir的返回值。从的文档


  

由readdir的()返回的指针指向其可以是数据
  再次调用覆盖到READDIR()在同一个目录流。


这意味着它很可能都在你的表中的值是相同的指针,用相同的值。您可以使用 readdir_r ,或者只分配结构的dirent (每个READDIR调用),和memcpy到位的价值

另一种方法是更改​​为结构的dirent 的数组,在这种情况下,你可以使用你原来的的qsort 调用。

I'm trying to use qsort in accordance with the man page but regardless of what I try I keep getting a segfault

Here's the section of code that matters

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;
}

When running gdb I see the list of files in the directory per the fprintf in the while loop and I see the last entry. I placed a breakpoint in compare which is executed N times where N is the number of files and then I immediately get a SEGFAULT from _qsort.

On the Nth call to compare_dirent from qsort it crashes.

Here is the gdb output

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 ()

The solution (complete) was a little of both answers

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;
}

解决方案

One of your problems is:

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

should be:

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

The third element is width, the size of each object. Since table is an array of struct dirent *, that is what you want the size of.

You're also misusing the value returned by readdir. From the docs:

The pointer returned by readdir() points to data which may be overwritten by another call to readdir() on the same directory stream.

That means it's quite possibly all of the values in your table are the same pointer, with the same value. You can use readdir_r, or just allocate struct dirent (one for each readdir call), and memcpy the value in place.

An alternative is to change it to be an array of struct dirent, in which case you would use your original qsort call.

这篇关于用C段错误的qsort的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆