如何修复导致分段错误的Qsort比较器

时间:2019-02-09 02:50:15

标签: c

我为qsort编写的比较器函数每次运行时都会引发分段错误。具体来说,qsort()命令本身会导致错误,将其注释掉会使代码运行正常。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <assert.h>
#include <ctype.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "sort.h"
#include <sys/stat.h>

int compare(const void *r1, const void *r2) {
  return (strcmp(r1, r2));
}

//Function to compare strings in an array of strings for qsort
int main(int argc, char *argv[]) {
  FILE *file;
  file = fopen(argv[1], "r");
  struct stat fs;
  //exists only to get file size
  stat(argv[1], &fs);
  int file_size = fs.st_size;
  int number_of_records = file_size / 100;
  char AllRecords[file_size][100];
  fread(AllRecords, 100, file_size, file);
  fclose(file);
  int i = sizeof(AllRecords);
  //  int l = compare(AllRecords[0],AllRecords[1]);
  //  Test, current bug, calling qsort causes errors
  qsort(AllRecords, i, 100, compare);
  FILE *file2 = fopen(argv[2], "w");
  fwrite(AllRecords, 100, i, file2);
  fclose(file2);
  return (0);
}

3 个答案:

答案 0 :(得分:1)

您需要非常小心使用的尺寸。该代码有效,解决了数组大小的各种问题。请注意,在堆栈上可以创建多大数组有一个限制。在Unix系统上,1 MiB具有足够的错误余量(限制通常为8 MiB);在Windows上,该限制通常为1 MiB,因此此处施加的限制可能有点大-也许(1000 * 1000)是安全的;也许较小的值会更好,例如(1024 * 1024 * 15 / 16)

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>

#define MAX_FILE_SIZE (1024 * 1024)

static int compare(const void  *r1, const void *r2)
{
    return(strcmp(r1, r2));
}

int main(int argc, char *argv[])
{
    assert(argc == 3);
    FILE *file = fopen(argv[1], "r");
    struct stat fs;
    stat(argv[1], &fs);
    int file_size = fs.st_size;
    if (file_size > MAX_FILE_SIZE)
    {
        fprintf(stderr, "file %s is too big to be sorted by this program\n", argv[1]);
        exit(EXIT_FAILURE);
    }
    int number_of_records = file_size / 100;
    char AllRecords[number_of_records][100];
    fread(AllRecords, 100, file_size, file);
    fclose(file);
    qsort(AllRecords, number_of_records, 100, compare);
    FILE *file2 = fopen(argv[2], "w");
    fwrite(AllRecords, 100, number_of_records, file2);
    fclose(file2);
    return(0);
}

问题之一就是生成样本数据。我使用随机数据生成器生成以空字节结尾的99个字符“行”(这样,字符串比较将具有以空结尾的字符串。

输入:

LLWNMGWMIQECKYLWFFIHWSZVYBQLLYTDAXNQNCQRBJZMZNFMMNCBAFYIIXUKXEBGSQHIYVCDVWCUHLXLOCOETLRPZRSGWDERQAZ
YNWEULRIMNODDAKABCKVAXTWLMPFOFIGRIJLKPVTWCFJGXAZEWKZFWCIZVQZYPADMBQOOHITVPEVWOIUSZISJOQTHQHCXEADIHW
YSHUYAQTPVTBKKHXQQXZMJIQVJRFJSNZSXKMHNJRAPNYWVSJRIHVHUBJJJAMRVBJZWWEACTUXLDXEFIDALHJBOKXJBAQJFABKLR
UWXIJELISTPAFXSKEGQHHJYPKWGLBXJSQWFHCAPRJTLQHRZEEEJAELOMKDAQIDIBZKZMCYNCMVLTXDUKLYGEIBVXTXNKPOUGMQE
NFUVXYBDQYMIEVWEQUYPTEASNSOQHZRLLLKXSBSQJFJBNRLSPUELCYTWDLLMTQKKHWFVFCQXNEBBMAPASRZSIOELSZGGFDDWJSK
OXQGGDODECBRVSXUAMZSLIHUJRAUFGMMORRBBGHECQLRWSVZGZWTSSBJVPTTRUIDJVGKTFGJFMSOHHTBIAEFIMUSYXMJAIRIZTU
XRRQOOBLDYLQQMKVFSOIZNTXAARKUZRBFCAEJDGCZGXHUTWHHOHERWPKOLDBCEHCUXPHVJMEUEJVTUDCQFXWAEWMPZPROKSOKAE
LURFJLTYKIIWTMWJLXZGOGCPMMRWZEOCSODVRSQDFTMJJILCIZNQWITWFJSCSAZTTJBYEGAWXBAYGQVQOMQTKTEHGUTOOMOCFAZ
NGBPRHOEICRLXPVTMHULNYJNNRJYVZDDGHDFHJFKELHUGGYWHSMBPCRTAAVHOKAITDPTPGWOOMSHHGLRNVQBMTHCFCPQGDRTCAV
ZJRHMYEPSWTRPGNFZMGPHOSFAFADGTDMISIWGSOCLSYGBURDJEKYYYLZXHHXIYYUVTYNXYBKJLSPNVXIKDZNSIZDITIOWGODJNL

使用tr '\0' '\n'进行了转换(反之亦然,将换行符转换为空字节)。

输出:

LLWNMGWMIQECKYLWFFIHWSZVYBQLLYTDAXNQNCQRBJZMZNFMMNCBAFYIIXUKXEBGSQHIYVCDVWCUHLXLOCOETLRPZRSGWDERQAZ
LURFJLTYKIIWTMWJLXZGOGCPMMRWZEOCSODVRSQDFTMJJILCIZNQWITWFJSCSAZTTJBYEGAWXBAYGQVQOMQTKTEHGUTOOMOCFAZ
NFUVXYBDQYMIEVWEQUYPTEASNSOQHZRLLLKXSBSQJFJBNRLSPUELCYTWDLLMTQKKHWFVFCQXNEBBMAPASRZSIOELSZGGFDDWJSK
NGBPRHOEICRLXPVTMHULNYJNNRJYVZDDGHDFHJFKELHUGGYWHSMBPCRTAAVHOKAITDPTPGWOOMSHHGLRNVQBMTHCFCPQGDRTCAV
OXQGGDODECBRVSXUAMZSLIHUJRAUFGMMORRBBGHECQLRWSVZGZWTSSBJVPTTRUIDJVGKTFGJFMSOHHTBIAEFIMUSYXMJAIRIZTU
UWXIJELISTPAFXSKEGQHHJYPKWGLBXJSQWFHCAPRJTLQHRZEEEJAELOMKDAQIDIBZKZMCYNCMVLTXDUKLYGEIBVXTXNKPOUGMQE
XRRQOOBLDYLQQMKVFSOIZNTXAARKUZRBFCAEJDGCZGXHUTWHHOHERWPKOLDBCEHCUXPHVJMEUEJVTUDCQFXWAEWMPZPROKSOKAE
YNWEULRIMNODDAKABCKVAXTWLMPFOFIGRIJLKPVTWCFJGXAZEWKZFWCIZVQZYPADMBQOOHITVPEVWOIUSZISJOQTHQHCXEADIHW
YSHUYAQTPVTBKKHXQQXZMJIQVJRFJSNZSXKMHNJRAPNYWVSJRIHVHUBJJJAMRVBJZWWEACTUXLDXEFIDALHJBOKXJBAQJFABKLR
ZJRHMYEPSWTRPGNFZMGPHOSFAFADGTDMISIWGSOCLSYGBURDJEKYYYLZXHHXIYYUVTYNXYBKJLSPNVXIKDZNSIZDITIOWGODJNL

当然,有了这些数据,字符串比较将不需要查找空字节,但是如果文件中有重复的行,那将是至关重要的。

答案 1 :(得分:0)

qsort函数需要两个数字参数:nitemssize。第一个是项目数。我认为您已将此存储在number_of_records中。第二个是单个记录的大小,您正在使用文字100

与其传递i(整个数组的总字节数),不如传递number_of_records

qsort(AllRecords, number_of_records, 100, compare);

答案 2 :(得分:0)

立即解决各种问题。

<?php $a = isset( $_GET['A'] ) ? $_GET['A'] : ''; echo $a; $point = isset( $_GET['POIN'] ) ? $_GET['POIN'] : ''; echo $point; ?> <form enctype="multipart/form-data" method="post" style="width:auto;"> <div class="box"> <span class='odometer' id="timespan" name="timespan">232</span> </div> <input class="process" name="submit" type="submit" id="submit" value="winners" onclick="window.location='reward-pollingx.php?A=1&POIN='+document.getElementById('timespan').innerHTML;return false;" > </form> 不是file_size中期望的记录数,file是期​​望的记录数。

number_of_records不应是i的字节大小,也不应该是AllRecords中的元素数,而不能是从AllRecords[]成功读取的项数。

fread()

希望//char AllRecords[file_size][100]; //fread(AllRecords, 100, file_size, file); //int i = sizeof(AllRecords); char AllRecords[number_of_records][100]; int i = fread(AllRecords, 100, number_of_records, file);` qsort(AllRecords, i, 100, compare); // This is OK ,但是在读取文件时会发生废话。 number_of_records == i的返回值是最好的指示。