[英]Segmentation fault when using qsort
I am working on a c program to read from a txt
file and sort the strings. 我正在研究一个c程序来读取一个
txt
文件并对字符串进行排序。
data.txt: data.txt中:
jk ef ab cd bc gh fg ij hi de
Here is my code: 这是我的代码:
#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;
}
I ran the code on Ubuntu and it breaks on a segfault. 我在Ubuntu上运行代码,它在段错误上打破了。 Believe this segfault happened in
qsort
and I could not figure out why. 相信这个段错误发生在
qsort
,我无法弄清楚为什么。
Anyone can give me some suggestions? 有人可以给我一些建议吗?
The comparison function is incorrect, as you are sorting an array of arrays of char
, you can pass the pointers to the elements to strcmp
directly: 比较函数是不正确的,因为您正在排序
char
数组的数组,您可以直接将指向元素的指针传递给strcmp
:
int cmp(const void *p1, const void *p2) {
return strcmp(p1, p2);
}
Note however that your parsing loop is also incorrect: feof()
is not the correct way to check for end of file. 但请注意,您的解析循环也不正确:
feof()
不是检查文件结尾的正确方法。 Use this instead: 请改用:
n = 0;
while (n < 255 && fscanf(f, "%254s", s[n]) == 1) {
n++;
}
The qsort
invokation should specify the size of the array element: qsort
invokation应该指定数组元素的大小:
qsort(s, n, sizeof(*s), cmp);
Here is a corrected version: 这是一个更正版本:
#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;
}
Many people gave a good answer. 很多人给出了一个很好的答案。
Here is how you could have found it by yourself, step by step , with standard GNU tools: 以下是使用标准GNU工具逐步找到它的方法:
We suppose the source file is named qc
. 我们假设源文件名为
qc
。
Compile with debugging symbols (note that no need to have a Makefile here): 用调试符号编译(请注意,这里不需要Makefile):
% make CFLAGS=-g q
cc -g q.c -o q
Now, run the program with a debugger (gdb): 现在,使用调试器(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
Now look at the stack frame: 现在看看堆栈框架:
(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
So your problem is in a call to your function cmp
by the qsort library, that calls strcmp with bad pointers. 所以你的问题在于qsort库调用你的函数
cmp
,它用坏指针调用strcmp。
So we go up from one stack frame , to be at your cmp function level: 所以我们从一个堆栈框架上升到你的cmp函数级别:
(gdb) up
#1 0x00000000004009b3 in cmp (p1=0x7ffffffeeb60, p2=0x7ffffffeeb88) at q.c:8
8 return strcmp( *(const char **) p1, *(const char **) p2);
We look at the type of p1: 我们来看看p1的类型:
(gdb) ptype p1
type = void *
Since p1 is a pointer, we examine its content displaying 10 first bytes: 由于p1是一个指针,我们检查它显示10个第一个字节的内容:
(gdb) print (*(char *) p1)@10
$43 = "jk\000\000\000\000\000\000\000"
So we discover it is a null terminated string containing jk
. 所以我们发现它是一个包含
jk
的空终止字符串。
So your cast is invalid: *(const char **) p1
. 所以你的演员阵容无效:
*(const char **) p1
。
This should have been (const char*) p1
. 这应该是
(const char*) p1
。
We change the cast and then it works. 我们改变了演员阵容,然后就可以了。
qsort()
passes to the compare function two pointers to the array's elements. qsort()
将两个指向数组元素的指针传递给compare函数。
The array's elements are of type char[255]
. 数组的元素是
char[255]
类型。 So qsort()
's compare function gets passed in two char(*)[255]
. 所以
qsort()
的compare函数在两个char(*)[255]
传递。
So it should look like 所以看起来应该是这样的
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];
This smells very bad. 这味道非常糟糕。 Use C dynamic memory allocation .
使用C动态内存分配 。
Consider instead a heap-allocated pointer to an array of heap-allocated strings. 请考虑使用堆分配的指针指向堆分配的字符串数组。
qsort(s, n , sizeof(char *), cmp);
Read carefully the documentation of qsort(3) . 仔细阅读qsort(3)的文档。 With a
char s[255][255]
your call to qsort
is very wrong. 使用
char s[255][255]
你对qsort
的调用是非常错误的。
Anyone can give me some suggestions?
有人可以给我一些建议吗?
Read more carefully a good C programming book and the documentation of every function you are using (even strcmp(3) ). 仔细阅读一本好的C编程书和你正在使用的每个函数的文档(甚至是strcmp(3) )。 Look also at some C reference and glance into the C11 specification n1570 .
另请参阅一些C参考并浏览C11规范n1570 。
Compile with all warnings and debug info, ie gcc -Wall -Wextra -g
with GCC (read more about Invoking GCC ). 使用GCC编译所有警告和调试信息,即
gcc -Wall -Wextra -g
(了解更多关于调用GCC的信息 )。 Use the debugger gdb
(read about Debugging with GDB ) 使用调试器
gdb
(阅读有关使用GDB调试 )
PS. PS。 We won't do your homework.
我们不会做你的功课。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.