簡體   English   中英

使用qsort時出現分段錯誤

[英]Segmentation fault when using 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) {
    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 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;
}

很多人給出了一個很好的答案。

以下是使用標准GNU工具逐步找到它的方法:

我們假設源文件名為qc

用調試符號編譯(請注意,這里不需要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

我們改變了演員陣容,然后就可以了。

qsort()將兩個指向數組元素的指針傳遞給compare函數。

數組的元素是char[255]類型。 所以qsort()的compare函數在兩個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編譯所有警告和調試信息,即gcc -Wall -Wextra -g (了解更多關於調用GCC的信息 )。 使用調試器 gdb (閱讀有關使用GDB調試

PS。 我們不會做你的功課。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM