使用qsort时出现分段错误

时间:2017-09-07 07:13:02

标签: c segmentation-fault qsort

我正在开发程序,以便从txt文件中读取并对字符串进行排序。

data.txt中:

jk ef ab cd bc gh fg ij hi de 

这是我的代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <ctype.h>

int cmp(const void *p1, const void *p2) {
    return strcmp(*(const char **)p1,  *(const char **)p2);
}

int main() {
    FILE *f = fopen("data.txt", "r");
    char s[255][255];
    char tmp[255];
    int n = 0;

    while (!feof(f)) {
        fscanf(f, "%s", tmp);
        strcpy(s[n], tmp);
        n++;
    }

    fclose(f);

    qsort(s, n, sizeof(char *), cmp);

    int i = 0;
    for (; i < n; i++) {
        printf("%s ", s[i]);
    }

    return EXIT_SUCCESS;
} 

我在Ubuntu上运行代码,它在段错误上打破了。相信这段错误发生在qsort,我无法弄清楚原因。

任何人都可以给我一些建议吗?

4 个答案:

答案 0 :(得分:5)

比较函数不正确,因为您正在排序char数组的数组,您可以直接将指针传递给strcmp

int cmp(const void *p1, const void *p2) {
    return strcmp(p1, p2);
}

但请注意,您的解析循环也不正确:feof()不是检查文件结尾的正确方法。请改用:

  n = 0;
  while (n < 255 && fscanf(f, "%254s", s[n]) == 1) {
      n++;
  }

qsort invokation应指定数组元素的大小:

  qsort(s, n, sizeof(*s), cmp);

以下是更正后的版本:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int cmp(const void *p1, const void *p2) {
    return strcmp(p1, p2);
}

int main(void) {
    FILE *f = fopen("data.txt", "r");
    char s[255][255];
    char tmp[255];
    int n = 0;

    if (f == NULL)
        return EXIT_FAILURE;

    while (n < 255 && fscanf(f, "%254s", s[n]) == 1) {
        n++;
    }
    fclose(f);

    qsort(s, n, sizeof(*s), cmp);

    for (int i = 0; i < n; i++) {
        printf("%s ", s[i]);
    }
    printf("\n");

    return EXIT_SUCCESS;
}

答案 1 :(得分:4)

很多人给出了一个很好的答案。

以下是您可以通过标准GNU工具自行找到一步一步的方法:

我们假设源文件名为q.c

编译调试符号(注意这里不需要Makefile):

% make CFLAGS=-g q
cc -g  q.c  -o q

现在,使用调试器(gdb)运行程序:

% gdb q
(gdb) run
Starting program: /usr/home/fenyo/tmp/qs/q
Program received signal SIGSEGV, Segmentation fault.
0x00000008009607a6 in strcmp () from /lib/libc.so.7

现在看一下堆栈框架:

(gdb) where
#0  0x00000008009607a6 in strcmp () from /lib/libc.so.7
#1  0x00000000004009b5 in cmp (p1=0x7ffffffeeb60, p2=0x7ffffffeeb88) at q.c:8
#2  0x000000080093b834 in qsort () from /lib/libc.so.7
#3  0x0000000000400af5 in main () at q.c:26

所以你的问题是qsort库调用你的函数cmp,调用带坏指针的strcmp。

所以我们从一个堆栈框架上升到你的cmp功能级别:

(gdb) up
#1  0x00000000004009b3 in cmp (p1=0x7ffffffeeb60, p2=0x7ffffffeeb88) at q.c:8
8           return strcmp( *(const char **) p1,  *(const char **) p2);

我们看一下p1的类型:

(gdb) ptype p1
type = void *

由于p1是指针,我们检查其显示10个第一个字节的内容:

(gdb) print (*(char *) p1)@10
$43 = "jk\000\000\000\000\000\000\000"

因此我们发现它是一个包含jk的空终止字符串。

所以你的演员表无效:*(const char **) p1

这应该是(const char*) p1

我们改变了演员表,然后就可以了。

答案 2 :(得分:2)

qsort()向比较函数传递两个指向数组元素的指针。

数组的元素属于char[255]类型。因此,qsort()的比较函数会在两个char(*)[255]中传递。

所以看起来应该是

int cmp(const void *p1, const void *p2)
{
  const char (*ps1)[255] = p1;
  const char (*ps2)[255] = p2;

  return strcmp(*ps1, *ps2);
}

答案 3 :(得分:0)

char s[255][255];

这闻起来很糟糕。使用C dynamic memory allocation

请考虑使用堆分配的指针来指向堆分配的字符串数组。

qsort(s, n , sizeof(char *), cmp);

仔细阅读qsort(3)的文档。如果char s[255][255] qsort,则{em} 错误。

  

任何人都可以给我一些建议吗?

仔细阅读一本优秀的C编程书以及您正在使用的每个函数的文档(甚至strcmp(3))。还要看一些C reference并浏览C11规范n1570

使用GCC编译所有警告和调试信息,即gcc -Wall -Wextra -g(了解有关Invoking GCC的更多信息)。 使用调试器 gdb(阅读Debugging with GDB

PS。我们不会做你的功课。