I am working on a c program to read from a txt file and sort the strings.
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. Believe this segfault happened in qsort and I could not figure out why.
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:
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. 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(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:
We suppose the source file is named q.c.
Compile with debugging symbols (note that no need to have a Makefile here):
% make CFLAGS=-g q
cc -g q.c -o q
Now, run the program with a debugger (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.
So we go up from one stack frame, to be at your cmp function level:
(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:
(gdb) ptype p1
type = void *
Since p1 is a pointer, we examine its content displaying 10 first bytes:
(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.
So your cast is invalid: *(const char **) p1.
This should have been (const char*) p1.
We change the cast and then it works.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With