我正在编写Burrows-Wheeler变换的实现,它需要对(大)数组进行排序。由于我想并行化递归排序函数的部分代码,我决定在堆中分配一些局部变量(使用malloc()
)以防止堆栈溢出或 - 至少 - 使程序正常死亡。这引发了一大堆新问题。我将代码剥离到了必要部分(即导致问题的原因)。
以下代码编译时没有错误。生成的程序在使用icc编译时工作正常,但在使用gcc或tcc编译时会崩溃(随机)。
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
unsigned char *block;
int *indexes, *indexes_copy;
void radixsort(int from, int to, int step)
{
int *occurrences, *first_index_of, i;
if((occurrences = malloc(1024)) == 0)
exit(1);
if((first_index_of = malloc(1024)) == 0)
exit(1);
memset(occurrences, 0, 1024);
for(i = from; i < to; i++)
occurrences[block[indexes[i] + step]]++;
first_index_of[0] = from;
for(i = 0; i < 256; i++)
first_index_of[i + 1] = first_index_of[i] + occurrences[i];
memset(occurrences, 0, 1024);
memcpy(&indexes_copy[from], &indexes[from], 4 * (to - from));
for(i = from; i < to; i++)
indexes[first_index_of[block[indexes_copy[i] + step]] + occurrences[block[indexes_copy[i] + step]]++] = indexes_copy[i];
for(i = 0; i < 256; i++)
if(occurrences[i] > 1)
radixsort(first_index_of[i], first_index_of[i] + occurrences[i], step + 1);
free(occurrences);
free(first_index_of);
}
int main(int argument_count, char *arguments[])
{
int block_length, i;
FILE *input_file = fopen(arguments[1], "rb");
fseek(input_file, 0, SEEK_END);
block_length = ftell(input_file);
rewind(input_file);
block = malloc(block_length);
indexes = malloc(4 * block_length);
indexes_copy = malloc(4 * block_length);
fread(block, 1, block_length, input_file);
for(i = 0; i < block_length; i++)
indexes[i] = i;
radixsort(0, block_length, 0);
exit(0);
}
即使输入是一个非常小的文本文件(大约50个字节),使用后两个编译器,程序非常不稳定。它的概率约为50%。在其他情况下,当调用malloc()
时,它会在radixsort的第二次或第三次迭代中崩溃。当输入文件较大(大约1 MiB)时,始终崩溃。也是在第二次或第三次迭代......
手动增加堆没有任何好处。无论哪种方式,它都不应该。如果malloc()
无法分配内存,则应返回NULL
指针(并且不会崩溃)。
从堆切换回堆栈使得程序可以使用任一编译器(只要输入文件足够小)。
那么,我错过了什么/做错了什么?
答案 0 :(得分:1)
if((occurrences = malloc(1024)) == 0)
make that:
if((occurrences = malloc(1024 * sizeof *occurences)) == 0)
但还有更多问题......
UPDATE(1024 = 4 * 256似乎只是风格......)
for(i = 0; i < 256; i++)
first_index_of[i + 1] = first_index_of[i] + occurrences[i];
[i + 1]索引将解决超出其大小的数组;