使用QSORT引起分割故障

发布于 2024-12-05 07:03:00 字数 1581 浏览 3 评论 0原文

嗯,作为学习 C++ 的一部分,我的项目对此有一个限制。除了 等基本库和一些其他必需品之外,我不允许使用任何库。

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

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

它应该按列对它们进行排序。我在 StackOverflow 上的搜索返回了其他人的结果,几年前他也必须做完全相同的项目哈哈哈 基于 C 字符串中的列进行 Qsort?

但就我而言,我只是为该列使用全局变量并继续生活。当我实现 qsort 的比较函数时,我的问题出现了。

在我的主要方法中,我调用

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

其中 data 是 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);
}

1000 是因为我只是概括(并故意进行了错误的编码)以过度概括,没有行会超过 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]);

请帮助我了解导致此分段错误的原因。第一次比较两者时,左=“Williamson”,右=“Thompson”。第二次比较(并尝试崩溃)左=“Cartwright”和右=“Thompson”

Well, as part of learning C++, my project has a restriction on it. I'm not allowed to use any libraries except the basic ones such as <cstring> and a few other necessities.

The project should take in input from a file that is an "n" number of columns of strings and be able to sort the output according to lexicographical ordering of any selected column. So for example, given the input

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

It should sort them by column. And my search around StackOverflow returned a result from someone else who had to do the exact same project a few years ago too Hahaha Qsort based on a column in a c-string?

But in my case I just use a global variable for the column and get on with life. My problem came in when I am implementing the compare function for qsort

In my main method I call

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

where data is a char * data[] and i is the number of lines to compare. (5 in this case)

Below is my code for the compare method

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);
}

the 1000s are because I just generalized (and did bad coding on purpose) to overgeneralize that no lines will be longer than 1000 characters.

What confuses me is that when I use the debugger in Eclipse, I can see that it it compares it successfully the first time, then on the second round, it has a segmentation fault when it tries to compare them.

I also tried to change the code for assigning left and right to what is below but that didn't help either

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

Please help me understand what is causing this segmentation fault. The first time it compares the two, left = "Williamson" and right = "Thompson". The second time it compares (and crashes trying) left = "Cartwright" and right = "Thompson"

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

前事休说 2024-12-12 07:03:00
char* line1 = new char[1000]; char* line2 = new char[1000];

这一点都不好。您永远不会释放此功能,因此每次调用比较功能时,您都会泄漏2000个字节。最终,这将导致较低的内存条件,将投掷。 (或在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

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

This is not good at all. You're never freeing this, so you leak 2000 bytes every time your comparison function is called. Eventually this will lead to low-memory conditions and new will throw. (Or on Linux your process might get killed by the OOM-killer). It's also not very efficient when you could just have said char line1[1000], which is super-quick because it simply subtracts from the stack pointer rather than potentially traversing a free list or asking the kernel for more memory.

But really you could be doing the compare without modifying or copying the strings. For example:

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
}

But lastly... You're using std::string you say? Well, if that's the case, then assuming the memory passed to qsort is compatible with "const char **" is a little weird, and I would expect it to crash. In that sense maybe what you should do something like:

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();

    // ...
}

But really, if you are using C++ and not C, you should use std::sort.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文