递归期间代码执行中断

Posted

技术标签:

【中文标题】递归期间代码执行中断【英文标题】:Code execution breaking during recursion 【发布时间】:2017-10-23 17:44:20 【问题描述】:

在图像中的单个字母模式中,我编写了一个小函数,该函数将从任何像素开始并遍历所有连续像素。简而言之,在矩阵中,它会将所有连续像素打开为真,其余像素为零。

此函数已正确完成。然而,输入模式几乎没有变化,它的行为异常。我发现这条线以后://process left-up diagonally 没有被调用。

可能是什么原因?

valgrind 也没有显示内存损坏。输入的 jpg 文件大小最大为 170x30 像素

系统 Ubuntu-16

生成文件

CFLAGS= -O2 -c  -I$(INC_DIR) -fpermissive  -std=c++11
CC=g++-5


%.o: %.cpp
        $(CC) $(CFLAGS) -c $< -o $@


readpattern: readpattern.o
        g++ -IPNG/include  -o readpattern readpattern.o libcorona.a -lpng -ljpeg

代码

void do_start_extract_char(char **output, int x, int y, int width, int height) 

    //if pixel location croses boundary then return
    if (x < 0 || y < 0 || x > width - 1 || y > height - 1) 
        return;
    

    //if the same pixel has already been visited then just return
    if (output[y][x]) 
        return;
    

    if (isUsefulPixel(x, y)) 
        //store it

        output[y][x] = 1;

     else 

        return;
    


    //process left
    do_start_extract_char(output, x - 1, y, width, height);


    //process down
    do_start_extract_char(output, x, y + 1, width, height);


    //process right
    do_start_extract_char(output, x + 1, y, width, height);

//process up
    do_start_extract_char(output, x, y - 1, width, height);

    //process left-down diagonally
    //          /
    //         /
    do_start_extract_char(output, x - 1, y + 1, width, height);

    //process left-up diagonally
    //        \
    //         \
    do_start_extract_char(output, x - 1, y - 1, width, height);


    //process right-down diagonally
    //          \
    //           \
    do_start_extract_char(output, x + 1, y + 1, width, height);

    //process right-up diagonally
    //            /
    //           /
    do_start_extract_char(output, x + 1, y - 1, width, height);


    return;


【问题讨论】:

@user5858 在使用调试器单步执行代码时,您观察到了什么?关于您的代码,我没有发现任何错误,这很明显 是时候创建一个minimal reproducible example了。如果创建 MCVE 并不能完全暴露问题并让您修复它,请编辑您的问题并添加 MCVE。 唾手可得的果实:确保您没有用完自动存储。 @user4581301 我怎么知道这个?不过我从来没有遇到过这种自动存储问题 仔细阅读 Yakk 的回答。它涵盖了这个问题。每个函数调用最多可以假设 64 位是您可用的最好的)40 字节的存储空间。对于 1 百万像素的图像,40 MB 的存储空间可能会在你结束时被吃掉,而且大多数系统都是基于堆栈的,具有 2 到 10 MB 的存储空间 【参考方案1】:

从大部分像素开始,向左、向下、向右、向上递归,足以覆盖整个图像中的每一个像素。

当一个像素无法通过左、下、右和上到达时,左下像素只能是到达像素的方式。

请注意,天真的递归在这里是一个糟糕的计划。如果您的图像有几十亿像素,这意味着第一次调用可能会以几十亿次递归调用结束。这可能会毁掉你的筹码。

相反,维护您自己的像素堆栈以访问,并通过在其中排队更多任务来递归。

struct location 
  int x,y;
;
bool visited_already(bool const*const* visit_flag, location l) 
  return visit_flag[l.y][l.x];

struct size 
  int x,y;
;
struct rectangle 
  location l;
  size s;
;
bool in_bounds( location l, rectangle b ) 
  if (l.x < b.l.x || l.y < b.l.y) return false;
  if (l.x >= b.l.x+b.s.x || l.y >= b.l.y+b.s.y) return false;
  return true;


bool do_visit(char*const* output, location l) 
  if (isUsefulPixel(l.x, l.y)) 
    output[l.y][l.x] = 1;
    return true;
   else 
    return false;
  


using todo_list = std::vector<location>;

bool extract_char( char*const* output, bool*const*visited, location where, rectangle bounds) 
  if (!in_bounds(where, bounds)) return false;
  if (visited_already(visited, where)) return false;
  visited[where.y][where.x] = 1;
  return do_visit(output, where);


void extract_chars(char*const* output, bool*const*visited, todo_list& list, rectangle bounds)

  while (!list.empty()) 
    auto next = list.back();
    list.pop_back();
    if (extract_char(output, visited, next, bounds))
    
      list.push_back( l.x+1, l.y-1 );
      list.push_back( l.x+1, l.y+0 );
      list.push_back( l.x+1, l.y+1 );
      list.push_back( l.x+0, l.y-1 );
      list.push_back( l.x+0, l.y+0 );
      list.push_back( l.x+0, l.y+1 );
      list.push_back( l.x-1, l.y-1 );
      list.push_back( l.x-1, l.y+0 );
      list.push_back( l.x-1, l.y+1 );
    
  

void do_start_extract_char(char *const*output, bool*const*visited, location where, rectangle bounds) 
  extract_chars( output, visited, where, bounds );

【讨论】:

以上是关于递归期间代码执行中断的主要内容,如果未能解决你的问题,请参考以下文章

Windows 窗体 - 如何中断当前正在执行的代码的执行

VBA:运行时自动化错误 - “代码执行已被中断”

代码执行已被保存预防宏中断[重复]

JNI - 在执行本机代码期间与目标 VM 断开连接

您的应用已进入中断状态,但没有代码可显示,因为所有线程都在执行外部代码(通常是系统或框架代码)

你的应用进入了中断状态,但无任何代码显示,因为所有线程之前都在执行外部代码(通常为系统或框架代码)