2014-04-01 2 views
1

재귀 함수가있는 클래스가 있습니다. 나는 100 건을 테스트했고 코드는 잘 작동한다. 그러나 다른 테스트를 실행하고 몇 번의 재귀 호출 후에 스택 오버플로를 보여주는 First-Inception 예외를 받았다.이를 무시하고 메모리 읽기 위반에 대한 처리되지 않은 예외를 표시했다.재귀 함수를 사용하는 동안 C++ 스택 오버플로

내가 (종료 조건을 가지고하지 실제 코드) 다음 코드가 있다고 가정 : 나는 디버거를 사용할 때

class Foo { 
    void Bar() { 
     Bar(); 
    }; 
}; 

, 나는 시간에 Bar라는 것을 알게을의 this 포인터가받는 잘못된 주소 번호로 인해 Foo 개체가 잘못 읽혀졌고 그 이유를 모르겠습니다.

누구에 대해 알고 있나요?

또는 시도해야합니까?

class Foo { 
    static void Bar (Foo* obj) { 
     Foo::Bar(obj); 
    }; 
}; 

편집 여기

게임 보석을 시뮬레이션하는 데 사용되는 실제 코드입니다. 나는 scanTile 방법

enum MOVE {MOVE_T, MOVE_L, MOVE_R, MOVE_B}; // Move Direction 
enum SCORE {SCORE_3 = 1, SCORE_4 = 2, SCORE_5 = 4}; // Score Types 
enum ERROR {ERR_DROP = 1, ERR_COUNT, ERR_MOVE}; // User-defined Error Code 

class Jewel { 
private: 
    UINT32 m, n, score, x, y; 
    char** map; 
    bool** scanned; 
    char move; 

    void init() { 
     map = new char*[n]; 
     scanned = new bool*[n]; 
     for (UINT32 i = 0; i < n; i++) { 
      map[i] = new char[m]; 
      scanned[i] = new bool[n]; 
     }; 
    }; 

    void reinit() { 
     for (UINT32 i = 0; i < n; i++) 
      for (UINT32 j = 0; j < n; j++) 
       scanned[i][j] = false; 
    }; 

    void uninit() { 
     for (UINT32 i = 0; i < n; i++) { 
      delete[m] map[i]; 
      delete[n] scanned[i]; 
     }; 

     delete[n] map; 
     delete[n] scanned; 
    }; 

    void fileInput() { 
     std::ifstream fInput("input.txt"); 
     fInput >> n >> m; 

     init(); 

     for (UINT32 j = 0; j < m; j++) 
      for (UINT32 i = 0; i < n; i++) 
       fInput >> map[i][j]; 

     fInput.close(); 
    }; 

    void fileOutput() { 
     std::ofstream fOutput("output.txt"); 
     fOutput << score << '\n'; 

     for (UINT32 j = 0; j < n; j++) { 
      for (UINT32 i = 0; i < n; i++) 
       fOutput << map[i][n - 1 - j] << ' '; 
      fOutput << '\n'; 
     }; 

     fOutput.close(); 

     uninit(); 
    }; 

    bool inputMove() { 
     std::cin >> x >> y >> move; 
     if ((x == -1) && (y == -1) && (move == 'A')) 
      return false; 
     else 
      return true; 
    }; 

    void outputMove() { 
     std::cout << '\n' << score << '\n'; 

     for (UINT32 j = 0; j < n; j++) { 
      for (UINT32 i = 0; i < n; i++) { 
       std::cout << map[i][n - 1 - j] << ' '; 
      }; 

      std::cout << '\n'; 
     }; 
    }; 

    void swap(char &a, char &b) { 
     char temp = a; 
     a = b; 
     b = temp; 
    }; 

    bool beginMove() { 
     switch (move) { 
     case 'T': 
      if (x < n - 1) { 
       swap(map[y][x], map[y][x + 1]); 
       return true; 
      }; 
      break; 
     case 'B': 
      if (0 < x) { 
       swap(map[y][x], map[y][x - 1]); 
       return true; 
      }; 
      break; 
     case 'L': 
      if (0 < y) { 
       swap(map[y][x], map[y - 1][x]); 
       return true; 
      }; 
      break; 
     case 'R': 
      if (y < n - 1) { 
       swap(map[y][x], map[y + 1][x]); 
       return true; 
      }; 
      break; 
     }; 

     return false; 
    }; 

    void revertMove() { 
     switch (move) { 
     case 'T': 
      swap(map[y][x], map[y][x + 1]); 
      break; 
     case 'B': 
      swap(map[y][x], map[y][x - 1]); 
      break; 
     case 'L': 
      swap(map[y][x], map[y - 1][x]); 
      break; 
     case 'R': 
      swap(map[y][x], map[y + 1][x]); 
      break; 
     }; 
    }; 

    void drop() { 
     for (UINT32 i = 0; i < n; i++) { 
      UINT32 j = 0; 

      while (j < n && map[i][j]) 
       j++; 

      if (j < n) { 
       UINT32 k = j + 1; 

       while (j < n) 
        if (!map[i][j]) { 
         while ((k < m) && !map[i][k]) 
          k++; 

         if (!map[i][k]) 
          exit(ERR_DROP); 

         map[i][j] = map[i][k]; 
         map[i][k] = 0; 

         j++; 
         k++; 
        }; 
      }; 
     }; 
    }; 

    bool scanMap() { 
     reinit(); 
     UINT32 sessionScore = 0; 

     for (UINT32 j = 0; j < n; j++) 
      for (UINT32 i = 0; i < n; i++) 
       if (!scanned[i][j]) 
        sessionScore += startScan(i, j); 

     if (sessionScore) { 
      score += sessionScore; 
      return true; 
     } else 
      return false; 
    }; 

    UINT32 startScan(const UINT32 &col, const UINT32 &row) { 
     UINT32 count = 1; 
     scanned[col][row] = true; 

     if ((row < n - 1) && !scanned[col][row + 1] && (map[col][row] == map[col][row + 1])) 
      count += scanTile(col, row + 1, MOVE_T, (0 < row) && (map[col][row] == map[col][row - 1])); 

     if ((0 < row) && !scanned[col][row - 1] && (map[col][row] == map[col][row - 1])) 
      count += scanTile(col, row - 1, MOVE_B, (row < n - 1) && (map[col][row] == map[col][row + 1])); 

     if ((col < n - 1) && !scanned[col + 1][row] && (map[col][row] == map[col + 1][row])) 
      count += scanTile(col + 1, row, MOVE_R, (0 < col) && (map[col][row] == map[col - 1][row])); 

     if ((0 < col) && !scanned[col - 1][row] && (map[col][row] == map[col - 1][row])) 
      count += scanTile(col - 1, row, MOVE_L, (col < n - 1) && (map[col][row] == map[col + 1][row])); 

     if ((count < 3) && (count != 1)) 
      exit(ERR_COUNT); 

     if (count >= 3) 
      map[col][row] = 0; 

     if (count == 1) 
      return 0; 
     else if (count == 3) 
      return count*SCORE_3; 
     else if (count == 4) 
      return count*SCORE_4; 
     else if (count >= 5) 
      return count*SCORE_5; 
    }; 

    UINT32 scanTile(const UINT32 &col, const UINT32 &row, const MOVE &direction, const bool &opposite = false) { 
     UINT32 count = 1; 
     UINT32 temp = 0; 
     bool counted = false; 

     switch (direction) { 
     case MOVE_T: 
      if ((row < n - 1) && (map[col][row] == map[col][row + 1])) 
       if (scanned[col][row + 1]) 
        counted = true; 
       else 
        count += scanTile(col, row + 1, MOVE_T, (0 < row) && (map[col][row] == map[col][row - 1])); 
      break; 
     case MOVE_B: 
      if ((0 < row) && (map[col][row] == map[col][row - 1])) 
       if (scanned[col][row - 1]) 
        counted = true; 
       else 
        count += scanTile(col, row - 1, MOVE_B, (row < n - 1) && (map[col][row] == map[col][row + 1])); 
      break; 
     case MOVE_R: 
      if ((col < n - 1) && (map[col][row] == map[col + 1][row])) 
       if (scanned[col + 1][row]) 
        counted = true; 
       else 
        count += scanTile(col + 1, row, MOVE_R, (0 < col) && (map[col][row] == map[col - 1][row])); 
      break; 
     case MOVE_L: 
      if ((0 < col) && (map[col][row] == map[col - 1][row])) 
       if (scanned[col - 1][row]) 
        counted = true; 
       else 
        count += scanTile(col - 1, row, MOVE_L, (col < n - 1) && (map[col][row] == map[col + 1][row])); 
      break; 
     default: 
      exit(ERR_MOVE); 
     }; 

     if ((opposite ? 1 : 0) + 1 + count + (counted ? 1 : 0) >= 3) { 
      switch (direction) { 
      case MOVE_T: 
      case MOVE_B: 
       temp = 0; 
       if ((col < n - 1) && !scanned[col + 1][row] && (map[col][row] == map[col + 1][row])) 
        count += temp = scanTile(col + 1, row, MOVE_R, (0 < col) && (map[col][row] == map[col - 1][row])); 
       if ((0 < col) && !scanned[col - 1][row] && (map[col][row] == map[col - 1][row])) 
        count += scanTile(col - 1, row, MOVE_L, temp ? true : false); 
       break; 
      case MOVE_L: 
      case MOVE_R: 
       temp = 0; 
       if ((row < n - 1) && !scanned[col][row + 1] && (map[col][row] == map[col][row + 1])) 
        count += temp = scanTile(col, row + 1, MOVE_T, (0 < row) && (map[col][row] == map[col][row - 1])); 
       if ((0 < row) && !scanned[col][row - 1] && (map[col][row] == map[col][row - 1])) 
        count += scanTile(col, row - 1, MOVE_B, temp ? true : false); 
       break; 
      default: 
       exit(ERR_MOVE); 
      }; 

      scanned[col][row] = true; 
      map[col][row] = 0; 
      return count; 
     } else { 
      return 0; 
     }; 
    }; 

public: 
    Jewel() : score(0) { 
     fileInput(); 
    }; 

    void process() { 
     outputMove(); 

     while (inputMove()) { 
      if (beginMove()) { 
       bool first = true; 

       while (scanMap()) { 
        outputMove(); 
        drop(); 
        outputMove(); 
        first = false; 
       }; 

       if (first) 
        revertMove(); 
      }; 

      outputMove(); 
     }; 

     fileOutput(); 
    }; 
}; 
+2

음, 이것은 밑바닥이 아닌 재귀입니까? 아니면 실제 코드가 아닐까요? –

+0

실제 코드는 매우 복잡합니다 –

+0

4 월 바보는 결코 복잡하지 않습니다 – sehe

답변

1

스택은 다른 많은 것들과 마찬가지로 유한 크기의 무언가이며 재귀를 사용하면 프로그램이 만료되고 프로그램이 오버플로가 될 때까지 점점 더 많은 공간을 사용하게됩니다.

* nix 기반 OS에서 일반적으로 GNU/리눅스 배포판에서 일반적으로 약 7/8Mb 인 스택 크기를 얻으려면 ulimit -a 또는 ulimit -s (더 짧은 출력) 명령을 사용할 수 있습니다.

+0

맞습니다. 문제를 파악했습니다. :) –

1

당신이 재귀 작업 할 때, 당신은 항상 종료 조건이 있어야에서 문제를 발견했다.

스택 오버플로는 일반적으로 스택 오버 플로우가 없거나 재귀가 너무 깊음을 의미 할 때 발생합니다.

+0

내 실제 코드에 종료 조건이 있으며 걱정하지 않아도됩니다. –

관련 문제