C - 函数调用本身会导致递归调用中的段错误



我正在与我无法理解的段错误作斗争:我有一个递归函数,它扩展了表示像素的数组:从索引开始,它通过左右调用相同的函数(又名索引 -1,索引 +1...)围绕索引创建像素组。出于调试目的,我在函数的第一行有一个 printf 调用,在 4 个递归调用中的每一个之前都有一个。我没有得到的是,在递归期间,我最终会在 recrusive 调用本身的递归期间出现段错误(我得到的是调用前的打印,但没有在函数启动时得到的打印)。

void explore(Pixel * array, int j, Tache * cur_pound, int * it, Pixel previous){
printf("%dn", j); // I DONT GET THIS PRINT AT LAST RECURSIVE CALL
// out of bounds
if(j > sizeX * sizeY)
return;
// allready explored index
if(array[j].explored == 1){
return;
}
// to big of a color difference between this pixel and the reference one
if(abs((int)array[j].r - previous.r) > SEUIL || abs((int)array[j].g - previous.g) > SEUIL || abs((int)array[j].b - previous.b) > SEUIL){
return;
}
array[j].explored = 1;
cur_pound->limits[* it] = j;
(* it)++;
// recursion
if(j +1 < sizeX * sizeY && array[j+1].explored != 1){
printf("before SFn); // I GET THIS PRINTF
explore(array, j + 1, cur_pound, it, previous);
}
// 3 other recursive calls removed for simplicity here
}

关于我的数据结构:Tache *是包含 3 GLub 和limitsstruct,一个代表属于该组的每个像素索引的int *。一个Pixel包含 3 个 GLubytes 和一个char,表示函数是否已访问过此像素。作为第一个参数提供给函数的array是表示我的图像的Pixel数组。it是一个表示组中索引的int,以便我的函数知道它应该在数组的哪个位置添加新索引。Limits在此函数之外的-1初始化,并分配malloc(size * sizeof(int))其中size是图像的宽度乘以其高度。

这是初始调用的完成方式:

void taches_de_couleur(Image *i){
int j, k, y, size, it;
GLubyte * im;
Pixel * array;
sizeX = i->sizeX;
sizeY = i->sizeY;  
k = 0;
size = sizeX * sizeY;
array = malloc(size * sizeof(Pixel));
im = i->data;
/* build the array from image data */
for(j = 0; j < 3 * size; j+= 3){
array[k].explored = 0;
array[k].r = i->data[j];
array[k].g = i->data[j + 1];
array[k].b = i->data[j + 2];
k++;
}
Tache * new_pound;
new_pound = malloc(sizeof(Tache));
new_pound->limits = malloc(size * sizeof(int));
int x= 0;
while(x < size){
new_pound->limits[x] = -1;
x++;
}
it = 0;
explore(array, 0, new_pound, &it, array[0]);
}

请注意,该程序在处理小图像时不会产生任何SF(我能做的最大图像是512x384px)。 这件事已经让我头疼了一个星期了,无法弄清楚是什么导致了这种段错误,这就是为什么我问你们是否可以在这里看到任何明显的东西。如果需要,我可以添加调用 Explore 的第二个函数,但这部分似乎很好。

编辑:这是我使用太大的图像运行时 gdb 给我的输出:

Thread 1 "palette" received signal SIGSEGV, Segmentation fault.
0x00007ffff7b730be in __GI___libc_write (fd=1, buf=0x555555592770, 
nbytes=7)
at ../sysdeps/unix/sysv/linux/write.c:26
26  ../sysdeps/unix/sysv/linux/write.c: No such file or directory.

编辑:由于im无法提供足够的资源,请参阅 https://github.com/BruhP8/TachesDeCouleur 以获取完整项目 提前致谢

我没有得到的是,在递归期间,我最终在 recrusive 调用本身的递归期间出现段错误(我得到的是调用前的打印,但不是函数启动时的打印)。

这几乎是堆栈耗尽的迹象。

在调试器下运行程序,并检查导致段错误的指令。很有可能,它将是堆栈操作指令之一(CALLPUSH),或者是堆栈递减之后的堆栈取消引用指令。您还可以查看寄存器的值$SP并将其与堆栈段的边界进行比较(如果您使用的是 Linux,则从/proc/$pid/maps开始)。

您显示的代码似乎没有分配任何堆栈,因此问题可能出在您省略的代码中。

请注意,程序在处理小图像时不会产生任何SF

这是另一个迹象:您可能正在堆栈上分配一个新图像,并且图像越大,您可以实现的递归级别就越少。

附言在 Linux 上,默认堆栈大小通常为 8MiB。尝试ulimit -s unlimited- 如果这允许程序更深入地重复,那将是一个确定的迹象,表明我的猜测是正确的。但不要使用ulimit -s unlimited作为修复(事实并非如此)。

更新:

有了完整的源代码,我就能够构建palette程序。对explore的每个递归调用只需要 48 字节的堆栈(这并不多)。

但是对于默认的 8MiB 堆栈,这会将总递归限制在(8 << 20) / 48 == 174762级深度。

TL;DR:如果您的递归过程需要每个像素一个递归级别,那么您将无法处理大图像。必须重写过程以改为迭代过程。

代码中的第一个边界检查似乎是:

if( j >= sizeX * sizeY )

而不是

if( j > sizeX * sizeY )

(因为数组的最后一个元素是数组[大小 - 1] 而不是数组[大小])

相关内容

  • 没有找到相关文章

最新更新