재귀 함수 호출을 쓰는데 에러가 발생합니다.

조회수 885회
#include <iostream>
#include <string>

std::string reverseParentheses(std::string s) {
    int strLen = (int)(s.size());
    int parStart = 0;
    int parEnd = 0;
    int parInnerLen = 0;
    int isParExist = 0;

    char temp;

    //괄호 탐색
    for (int i = 0; i < strLen; i++) {
        if (s[i] == '(') {
            parStart = i;
            isParExist++;
        } else if (s[i] == ')') {
            parEnd = i;
            isParExist++;
            break;
        }
    }

    //괄호 존재 여부와 괄호 안 문자의 개수 결정
    if (isParExist == 0) {
        return s;
    } else {
        parInnerLen = parEnd - parStart - 1;
    }

    //바괄호 내 모든 문자 뒤집기
    for (int i = parStart + 1, j = parEnd - 1; i < (parInnerLen / 2) + (parStart + 1); i++, j--) {
        temp = s[i];
        s[i] = s[j];
        s[j] = temp;
    }

    //괄호 삭제
    s.erase(s.begin() + parStart);
    s.erase(s.begin() + parEnd - 1);

    reverseParentheses(s);
}

int main() {
    std::string str = "co(de(fight)s)";
    //예상 결과: cosfighted

    std::string revStr = reverseParentheses(str);

    for (const char& cIdx : revStr) {
        std::cout << cIdx;
    }
    std::cout << "\n";

    return 0;
}

괄호 안에 있는 글자만 역으로 뒤집는 알고리즘을 짜고 있는데요. 괄호가 중첩되는 경우를 고려하면 함수를 재귀적으로 호출하는 것이 나을 것 같아서 그렇게 짰는데

Control may reach end of non-void function

이런 경고가 뜨고 컴파일을 강제 수행하면 SIGSEGV 에러가 납니다.

어디가 문제인 건가요?

  • (•́ ✖ •̀)
    알 수 없는 사용자

1 답변

  • 원인은 간단합니다.

    반환 값을 갖는 함수가 반환을 하지 않아서 Control may reach end of non-void function와 같은 경고를 컴파일러가 발생시킨 것이고, 실행 중 std::string이 반환 될것으로 동작하나 실제로 반환되지 않았기에 잘못된 메모리에 접근하게 되어 SIGSEGV와 같은 예외가 발생한 것 입니다.

    std::string reverseParentheses(std::string s) {
        int strLen = (int)(s.size());
        int parStart = 0;
        int parEnd = 0;
        int parInnerLen = 0;
        int isParExist = 0;
    
        char temp;
    
        //괄호 탐색
        for (int i = 0; i < strLen; i++) {
            if (s[i] == '(') {
                parStart = i;
                isParExist++;
            } else if (s[i] == ')') {
                parEnd = i;
                isParExist++;
                break;
            }
        }
    
        //괄호 존재 여부와 괄호 안 문자의 개수 결정
        if (isParExist == 0) {
            return s;
        } else {
            parInnerLen = parEnd - parStart - 1;
        }
    
        //바괄호 내 모든 문자 뒤집기
        for (int i = parStart + 1, j = parEnd - 1; i < (parInnerLen / 2) + (parStart + 1); i++, j--) {
            temp = s[i];
            s[i] = s[j];
            s[j] = temp;
        }
    
        //괄호 삭제
        s.erase(s.begin() + parStart);
        s.erase(s.begin() + parEnd - 1);
    
        return reverseParentheses(s);
    }
    
    • 그런데 코드 상에서는 괄호를 계속 삭제하고 있고, 괄호가 없으면 s를 리턴하며 종료되게 되어 있는데 그러면 값을 반환하는 것 아닌가요? 이 코드를 goto문으로 바꾸면 잘 동작합니다. 그런데 goto문은 되도록 쓰지 말라는 이야기가 많아서... 알 수 없는 사용자 2018.9.22 10:39
    • 작성하신 함수에서 isParExist 가 0일 때만 정상적인 반환이 이루어집니다. 그렇다면 isParExist 가 0 이 아닐 경우는 어떻게 될까요? 제귀 함수란 꼬리에 꼬리를 무는 함수호출인데 isParExist가 0이되는 경우는 가장 마지막 호출이 될것 입니다. 최초의 호출은 reverseParentheses()의 반환 값을 얻길 원하지만 return을 사용한 곳은 reverseParentheses() -> reverseParentheses() -> ... -> reverseParentheses() 상황에서 가장 마지막 호출에서만 하게 되는데 그렇다면 최초 호출은 return 을 통해 값을 받지 못하는 경우가 되는 것이지요. 유동욱 2018.9.22 21:11
    • 아...이해했습니다. 어이없는 실수를 했네요;; 답변 감사합니다. 알 수 없는 사용자 2018.9.22 22:11

답변을 하려면 로그인이 필요합니다.

프로그래머스 커뮤니티는 개발자들을 위한 Q&A 서비스입니다. 로그인해야 답변을 작성하실 수 있습니다.

(ಠ_ಠ)
(ಠ‿ಠ)