C 使用qsort时出现分段错误

C 使用qsort时出现分段错误,c,segmentation-fault,qsort,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) {

我正在编写一个程序,从
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;
} 
#包括
#包括
#包括
#包括
#包括
int cmp(常数无效*p1,常数无效*p2){
返回strcmp(*(常量字符**)p1,*(常量字符**)p2);
}
int main(){
文件*f=fopen(“data.txt”,“r”);
字符s[255][255];
char-tmp[255];
int n=0;
而(!feof(f)){
fscanf(f,“%s”,tmp);
strcpy(s[n],tmp);
n++;
}
fclose(f);
qsort(s,n,sizeof(char*),cmp);
int i=0;
对于(;i
我在Ubuntu上运行了这段代码,但它在一个错误上中断了。相信这个错误发生在
qsort
中,我不知道为什么

谁能给我一些建议

char s[255][255];
这闻起来很难闻。使用

相反,请考虑一个指向堆分配字符串数组的堆分配指针

qsort(s, n , sizeof(char *), cmp);
仔细阅读的文件。使用
chars[255][255]
调用
qsort
是非常错误的

谁能给我一些建议

char s[255][255];
更仔细地阅读一本好的C编程书和您正在使用的每个函数的文档(甚至)。还可以查看一些,并浏览C11规范


使用所有警告和调试信息编译,即使用(阅读更多信息)使用调试器
gdb
(阅读)

另外,我们不会做您的家庭作业。

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

比较函数不正确,因为您正在对
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++;
  }
以下是更正的版本:

#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;
}
#包括
#包括
#包括
int cmp(常数无效*p1,常数无效*p2){
返回strcmp(p1,p2);
}
内部主(空){
文件*f=fopen(“data.txt”,“r”);
字符s[255][255];
char-tmp[255];
int n=0;
如果(f==NULL)
返回退出失败;
而(n<255&&fscanf(f,“%254s”,s[n])==1){
n++;
}
fclose(f);
qsort(s,n,sizeof(*s),cmp);
对于(int i=0;i
许多人给出了一个很好的答案

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

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

使用调试符号编译(请注意,此处不需要Makefile):

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

现在查看堆栈帧:

(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"
因此我们发现它是一个以null结尾的字符串,包含
jk

因此,您的强制转换无效:
*(const char**)p1

这应该是
(const char*)p1


我们更改了强制转换,然后它就工作了。

1)
sizeof(char*)
-->
sizeof(*s)2)
返回strcmp(*(const char**)p1,*(const char**)p2)-->
返回strcmp((常量字符*)p1,(常量字符*)p2)3)使用所有警告和调试信息进行编译(例如,
gcc-Wall-Wextra-g
with…),然后使用调试器(例如,
gdb
)。仔细阅读的文件。Use@BLUEPIXY:Re 2.:你确定吗?如果OP想要更改数组大小,这将是一个令人讨厌的函数,对吗?警告:初始化从指针tar get type[-Wdiscarded限定符]
const char(*ps1)[255]=p1
生成.BTW,
&s[X][0]
作为比较函数的参数传递。它没有类型信息,因为它是作为空指针传递的。您试图复制该类型,但最终该信息未被使用。您试图复制该类型,但最终该信息未被使用。(作为
const char*
传递给strcmp
),因此它只是一个表单。当使用
strncmp
strncmp(*ps1,*ps2,sizeof(*ps1))
时,它可能很有用。然而,因为这意味着它是有用的,因为它是C字符串,这将不同于OP的愿望。Valgrind在这方面非常有效,也是-并且很好的非交互式。在开始使用GDB进行调试之前,你能推荐一个好的简短指南来先学习GDB的基础知识吗?不,那有一个介绍性的章节。读一下。此外,在别处还提供了大量关于GDB的教程。吉伊夫。
(gdb) ptype p1
type = void *
(gdb) print (*(char *) p1)@10
$43 = "jk\000\000\000\000\000\000\000"