【问题标题】:Bus Error 10 in Merge Sort Implementation on OS XOS X 上合并排序实现中的总线错误 10
【发布时间】:2014-10-21 20:41:14
【问题描述】:

我正在尝试在 C 中实现合并排序。我编写的代码适用于 100,000 个数字的列表,但是当我在 1,000,000 个数字的列表上运行它时,我得到“总线错误:10”。

错误发生在我评论“这里的总线错误”的地方。报错时,tmp_list_i == 65920 and pws->merge_cursor == 32776。函数merge合并任意数量的子数组,因为我也是用它来合并不同线程排序的子数组。但是即使我只使用一个线程(即一次只需要合并两个子数组时)也会发生总线错误。

有什么想法吗?

// Represents a sub-array in the list.
typedef struct
{
    int begin_i; // inclusive
    int end_i; // exclusive
    int already_sorted; // if the partition was sorted before runtime
    pthread_t tid; // thread associated with this partition, if any
    int merge_cursor; // index used for merging
} Partition;

// O(n log(n)) 
// n = number of comparisons in a merge
// log(n) = number of merges
void* merge_sort(void* partition)
{
    Partition* part = (Partition*) partition;

    // Base case. One item, so partition is sorted
    int len = part->end_i - part->begin_i;
    if (len < 2)
    {
        part->already_sorted = TRUE;
        return 0;
    }

    // Recursion
    Partition left_part;
    left_part.begin_i = part->begin_i;
    left_part.end_i = part->begin_i + (len / 2);
    left_part.merge_cursor = left_part.begin_i;

    Partition right_part;
    right_part.begin_i = part->begin_i + (len / 2);
    right_part.end_i = part->end_i;
    right_part.merge_cursor = right_part.begin_i;

    merge_sort(&left_part); 
    merge_sort(&right_part); 

    if (left_part.already_sorted && right_part.already_sorted)
        part->already_sorted = TRUE;

    // Create parts array to pass to merge
    Partition* parts[] = {&left_part, &right_part};

    if (merge(parts, 2, len) == FALSE)
        part->already_sorted = FALSE;

    return 0;
}

// O(n) but more specifically O(n * p + n) where p is num_parts
int merge(Partition* parts[], int num_parts, int total_num) 
{
    int already_sorted = TRUE; // whether the partitions were already sorted

    int tmp_list[total_num];
    int tmp_list_i;
    for (tmp_list_i = 0; tmp_list_i < total_num; tmp_list_i++) 
    {
        // find (P)artition (W)ith (S)mallest number under its merge cursor
        Partition* pws = NULL; 

        int parts_i;
        for (parts_i = 0; parts_i < num_parts; parts_i++)
        {
            Partition* this_part = parts[parts_i];

            if (this_part->merge_cursor == MERGE_CURSOR_DONE)
                continue;

            if (pws == NULL)
                pws = this_part; 

            int this_part_num = list[this_part->merge_cursor];
            int smallest_part_num = list[pws->merge_cursor];

            if (this_part_num < smallest_part_num)
            {
                pws = this_part;
                already_sorted = FALSE;
            }
        }

        // add the smallest of the numbers to current spot in tmp array
        tmp_list[tmp_list_i] = list[pws->merge_cursor]; // BUS ERROR HERE

        // increment the merge cursor for pws and set to NULL if done
        (pws->merge_cursor)++;
        if (pws->merge_cursor == pws->end_i)
            pws->merge_cursor = MERGE_CURSOR_DONE;
    }

    // Copy back to list from tmp_list. Costs an extra n.
    int list_i = parts[0]->begin_i; // start where we should in list
    for (tmp_list_i = 0; tmp_list_i < total_num; tmp_list_i++)
    {
        list[list_i] = tmp_list[tmp_list_i];
        list_i++;
    }

    return already_sorted;
}

编辑: 在堆而不是堆栈上分配所有内容时,我遇到了不同的问题。分配int this_part_num = list[this_part-&gt;merge_cursor]; 似乎没有正确评估,最终我得到一个信号错误:

141             int this_part_num = list[this_part->merge_cursor];
(gdb) s
142             int smallest_part_num = list[pws->merge_cursor];
(gdb) print this_part_num
$5 = 1
(gdb) print list[this_part->merge_cursor]
$6 = 6

【问题讨论】:

  • 报错时total_num的值是多少? list 数组的大小是多少?顺便说一句,我没有看到 list 的声明,它在某处吗?
  • 经过进一步审查,将tmp_list 声明为局部变量可能是问题所在。作为局部变量,tmp_list 将分配在堆栈上,堆栈上的 100 万个 int 的数组可能会导致堆栈溢出(而 100K 个 int 可能实际上适合堆栈)。我建议你 malloc tmp_list 数组和 free 它在函数的末尾。
  • 我尝试在堆上创建所有内容。但现在事情变得更奇怪了。我最终得到一个段错误,但在此之前分配 int this_part_num = list[list_part-&gt;merge_cursor]; 没有正确评估。请参阅上面的编辑。
  • 哦,list 被全局声明为 int* list; 并指向一个 malloc-ed 数组。

标签: c mergesort bus-error


【解决方案1】:

想通了。 List 在单独的文件中声明为int* list,但在文件中使用merge_sort 函数声明为extern int list[]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-10
    • 1970-01-01
    • 1970-01-01
    • 2020-05-25
    • 1970-01-01
    • 2016-03-07
    相关资源
    最近更新 更多