c语言 - 使用 qsort 时的分段错误



我正在开发一个 c 程序来读取txt文件并对字符串进行排序。

数据.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,我不知道为什么。

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

比较函数不正确,因为您正在对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调用应指定数组元素的大小:

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

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

以下是你如何用标准的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 = "jk00000000000000"

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

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

这应该是(const char*) p1.

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

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 s[255][255];

这闻起来很难闻。使用 C 动态内存分配。

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

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

仔细阅读 qsort(3) 的文档。有了char s[255][255]你对qsort的呼吁是非常错误的。

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

更仔细地阅读一本好的 C 编程书籍和你正在使用的每个函数的文档(甚至是 strcmp(3))。另请查看一些 C 参考并浏览 C11 规范 n1570。

使用所有警告和调试信息进行编译,即gcc -Wall -Wextra -g与 GCC 一起(阅读更多关于调用 GCC 的信息)。使用调试器gdb(阅读有关使用 GDB 进行调试的信息)

附言。我们不会做你的功课。

相关内容

  • 没有找到相关文章

最新更新