我正在开发c程序,以便从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
,我无法弄清楚原因。
任何人都可以给我一些建议吗?
答案 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。我们不会做你的功课。