使用qsort时出现分段错误

Bo *_*uan 2 c qsort segmentation-fault

我正在研究一个程序来读取txt文件并对字符串进行排序.

data.txt中:

jk ef ab cd bc gh fg ij hi de 
Run Code Online (Sandbox Code Playgroud)

这是我的代码:

#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;
} 
Run Code Online (Sandbox Code Playgroud)

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

有人可以给我一些建议吗?

chq*_*lie 6

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

int cmp(const void *p1, const void *p2) {
    return strcmp(p1, p2);
}
Run Code Online (Sandbox Code Playgroud)

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

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

所述qsortinvokation应该指定的数组元素的大小:

  qsort(s, n, sizeof(*s), cmp);
Run Code Online (Sandbox Code Playgroud)

这是一个更正版本:

#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;
}
Run Code Online (Sandbox Code Playgroud)


Ale*_*nyo 5

很多人都给出了很好的答案。

以下是您如何使用标准 GNU 工具自己一步一步找到它:

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

使用调试符号进行编译(注意这里不需要有 Makefile):

% make CFLAGS=-g q
cc -g  q.c  -o q
Run Code Online (Sandbox Code Playgroud)

现在,使用调试器 (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
Run Code Online (Sandbox Code Playgroud)

现在看一下堆栈帧:

(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
Run Code Online (Sandbox Code Playgroud)

所以你的问题在于qsort 库对你的函数的调用,它使用错误的指针调用 strcmp 。cmp

因此,我们从一个堆栈帧上升到您的 cmp 函数级别:

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

我们看p1的类型:

(gdb) ptype p1
type = void *
Run Code Online (Sandbox Code Playgroud)

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

(gdb) print (*(char *) p1)@10
$43 = "jk\000\000\000\000\000\000\000"
Run Code Online (Sandbox Code Playgroud)

所以我们发现它是一个以 null 结尾的字符串,其中包含 jk.

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

这本来应该是(const char*) p1

我们改变演员阵容然后它就起作用了。