使用qsort导致分段错误

时间:2011-09-18 00:32:14

标签: c++ c segmentation-fault cstring

好吧,作为学习C ++的一部分,我的项目有一个限制。我不允许使用除<cstring>等基本库以外的任何库以及其他一些必需品。

项目应该从一个“n”个字符串列的文件中获取输入,并且能够根据任何选定列的词典排序对输出进行排序。例如,给定输入

Cartwright   Wendy    93
Williamson   Mark     81
Thompson     Mark     100
Anderson     John     76
Turner       Dennis   56

它应该按列排序。我在StackOverflow周围的搜索返回了几年前不得不做同样项目的其他人的结果哈哈哈Qsort based on a column in a c-string?

但在我的情况下,我只是为列使用全局变量并继续生活。当我为qsort

实现比较功能时,我遇到了问题

在我的主要方法中,我打电话给

qsort (data, i, sizeof(char*), compare);

其中数据为char * data[]i是要比较的行数。 (在这种情况下为5)

以下是我的比较方法代码

int compare (const void * a, const void * b){
    char* line1 = new char[1000]; char* line2 = new char[1000];
    strcpy(line1, *((const char**) a));
    strcpy(line2, *((const char**) b));
    char* left = &(strtok(line1, " \t"))[column-1];
    char* right = &(strtok(line2, " \t"))[column-1];
    return strcmp(left, right);
}

1000s是因为我只是概括(并且故意编写错误的代码)来过度概括,没有行将超过1000个字符。

让我感到困惑的是,当我在Eclipse中使用调试器时,我可以看到它第一次成功比较它,然后在第二轮,当它试图比较它时它有一个分段错误。

我还尝试更改左侧和右侧分配的代码,但这样做没有任何帮助

char* left = new char[100];
strcpy(left, &(strtok(line1, " \t"))[column-1]);
char* right = new char[100];
strcpy(right, &(strtok(line2, " \t"))[column-1]);

请帮助我了解导致此细分错误的原因。它第一次比较两个,左=“威廉姆森”和右=“汤普森”。第二次比较(和崩溃尝试)left =“Cartwright”和right =“Thompson”

1 个答案:

答案 0 :(得分:4)

char* line1 = new char[1000]; char* line2 = new char[1000];

这根本不好。你永远不会释放它,所以每次调用比较函数时都会泄漏2000个字节。最终这会导致内存不足,new会抛出。 (或者在Linux上你的进程可能被OOM杀手杀死)。当你可以说char line1[1000]时,这也是非常有效的,因为它只是从堆栈指针中减去而不是潜在地遍历空闲列表或者要求内核获得更多内存。

但实际上你可以在不修改或复制字符串的情况下进行比较。例如:

static int
is_end_of_token(char ch)
{
    // If the string has the terminating NUL character we consider it the end.
    // If it has the ' ' or '\t' character we also consider it the end.  This
    // accomplishes the same thing as your strtok call, but WITHOUT modifying
    // the source buffer.
    return (!ch || ch == ' ' || ch == '\t');
}

int
compare(const void *a, const void *b)
{
   const char *strA = *(const char**)a;
   const char *strB = *(const char**)b;

   // Loop while there is data left to compare...
   while (!is_end_of_token(*strA) && !is_end_of_token(*strB))
   {
      if (*strA < *strB)
         return -1;      // String on left is smaller
      else if (*strA > *strB)
         return 1;       // String on right is smaller
      ++strA;
      ++strB;
   }

   if (is_end_of_token(*strA) && is_end_of_token(*strB))
      return 0;    // both strings are finished, so they are equal.
   else if (is_end_of_token(*strA))
      return -1;   // left string has ended, but right string still has chars
   else
      return 1;    // right string has ended, but left string still has chars
}

但最后......你说的是std::string吗?好吧,如果是这种情况,那么假设传递给qsort的内存与“const char **兼容”有点奇怪,我希望它会崩溃。从这个意义上讲,你应该做些什么:

int compare(const void *a, const void *b)
{
    const char *strA = ((const std::string*)a)->c_str();
    const char *strB = ((const std::string*)b)->c_str();

    // ...
}

但实际上,如果您使用的是C ++而不是C,则应使用std::sort