런타임에러 질문입니다.

  • oanoelsis
    oanoelsis
    #include <stdio.h>
    #include <iostream>
    #include <stdlib.h>
    using namespace std;
    #define MAX_MAN_NUM 100001 /* max human number + 1 */
    
    typedef struct Tree* TreePointer;
    struct Tree{
            int name;
            int level;
            TreePointer parent;
            TreePointer child;
    };
    
    /* allocation memory for array to 0~N-1 node treePointer */
    TreePointer* NodeAdd =(TreePointer*)malloc(MAX_MAN_NUM * sizeof(TreePointer));
    /* Initializing node address array list */
    void Init_NodeAdd(){
            int i=0;
            while(NodeAdd[i]!=0){
                    NodeAdd[i] = 0;
                    i++;
            }
    }
    
    void FirstTree(){
            TreePointer temp = (Tree*)malloc(sizeof(Tree));
            temp->name = 0;
            temp->parent = 0;
            temp->level = 0;
            NodeAdd[0] = temp;
    }
    
    void Add(int n,int parent){
            TreePointer temp = (Tree*)malloc(sizeof(Tree));
            temp->name = n;
            temp->parent = NodeAdd[parent];
            temp->level =(*(NodeAdd[parent])).level + 1;
            NodeAdd[n] = temp;
    }
    
    void Free_Tree(){
            int i=0;
            while(NodeAdd[i] != 0){
                    free(NodeAdd[i]);
                    i++;
            }
    }
    
    int Find(int l, int r){
            int dist = 0;
            TreePointer left = NodeAdd[l];
            TreePointer right= NodeAdd[r];
            if(l==r){
                    return 0;
            }
            int leftdist=0, rightdist=0;
            while(left->name != right->name){
                    int diff = left->level - right->level;
                    if(diff > 0){/* left->level > right->level */
                            leftdist++;
                            left = left->parent;
                    }
                    else if(diff < 0){/* left->level < right->level */
                            rightdist++;
                            right = right->parent;
                    }
                    else if(diff == 0){/* left->level == right->level */
                            leftdist++;
                            rightdist++;
                            left = left->parent;
                            right = right->parent;
                    }
            }
            dist = leftdist + rightdist;
            return dist;
    }
    int main(){
            int cases;
            scanf("%d", &cases);
            while(cases--){
                    Init_NodeAdd();
                    int N, testN;
                    scanf("%d", &N);
                    //cout << N << endl;
                    scanf("%d", &testN);
                    //cout << testN << endl;
                    NodeAdd[N] = 0;
                    FirstTree(); N--;
                    int parent = 0;
                    int n = 1;
                    while(N--){
                            scanf("%d",&parent);
                            //cout << parent << endl;
                            Add(n,parent);
                            n++;
                    }
                    int left, right;
                    while(testN--){
                            scanf("%d",&left);
                            //cout << left << endl;
                            scanf("%d",&right);
                            //cout << right << endl;
                            printf("%d\n",Find(left,right));
                    }
    
                    Free_Tree();
            }
    
            free(NodeAdd);
    }
    

    familytree 문제를 풀다 생긴 런타임오류에 대한 질문입니다. 간단하게 들어오는 입력값들을 자기자신의 번호(name)와 조상의주소(parent), 노드의 레벨 을 데이터로 가지고 있는 노드들의 트리로 구성한 뒤, 같은 조상을 가질떄까지의 거리를 합산하여 촌수를 계산해내는 알고리즘 입니다.

    답안 제출을 하면 런타임오류가 나며 잘못된 메모리 엑세스라고 뜨는데요. 궁금한 점은 우분투 g++ 환경인 제 컴퓨터에서는 잘 컴파일되고 돌아간다는 점입니다.(한가지 짐작가는 점은 엄청나게 개수가 많은 데이터에 대해서는 테스트 해보지 않았다는 점인데, 손으로 입력해야 하니 테스트를 해볼수가 없었습니다....) 그래서 이러한 경우에 어떤 문제로 런타임 에러가 난 것인지 알고 싶습니다. ㅠ

    한달 전부터 혼자 전산공부를 시작해서 알고스팟 문제들이 좋은 연습문제들이 되어주고 있습니다. 정말 감사합니다. ㅠㅠ


    9년 전
7개의 댓글이 있습니다.
  • Being
    Being

    많은 데이터에 대해 테스트하시려면 입력을 파일로 만든 뒤 표준 입력에 리디렉션해 보세요. ./a.out < input.txt 와 같이 하시면 됩니다.


    9년 전 link
  • oanoelsis
    oanoelsis

    제 컴퓨터에서는 꽤큰입력까지 해도 에러가 나지 않는데요 . ㅠ 혹시 저 코드에서 메모리 런타임 에러가 날 여지가 어디에 있는지 알려주세요 ㅠㅠㅠㅠㅠㅠ 왜 제가 돌릴떈 나지 않고 온라인 저지에서는 메모리엑세스 에러가 나는거죠


    9년 전 link
  • Being
    Being

    실행해본 것은 아닙니다만 확실히 잘못된 지점을 하나 짚자면, NodeAdd가 가리키는 영역이 할당되었을 때 내용이 연속해서 0이라는 보장이 없습니다. 맨 처음 초기화시에 0이 아닌 연속된 영역을 초기화하고 그 위에 새로운 내용을 덮어씌우지만, 마지막에 리소스 반환시 실제 할당이 이루어지지 않은 곳에 대해 free 할 수 있습니다.


    9년 전 link
  • oanoelsis
    oanoelsis

    음.. NodeAdd가 가지고 있는 값들이 0이 아니더라도 그 메모리가 할당이 안된 것은 아니지 않나요? 마지막에 리소스 반환시 실제할당이 이루어지지 않은 곳에 대해 free할 수 있다는게 무슨 말인지 잘 이해가 안되요 ㅠ


    9년 전 link
  • Being
    Being

    최초에 해당 메모리 영역에 0xDEADBEEF 0x00000000 0xDEADBEEF 와 같이 세 값이 들어 있었으며 입력이 두 개였다 가정해 봅시다. 최초 초기화시 첫 값이 0으로 덮어씌워진 후에 각 영역에 malloc()으로 할당된 주소가 저장되겠죠. 이 때 계산을 모두 마친 후에 Free_Tree()는 어떻게 동작할까요?


    9년 전 link
  • oanoelsis
    oanoelsis

    먼저 계속 질문 드려서 정말 죄송합니다. ㅠ. 제가 이해하기로는 말씀하신 예는 Free_Tree()함수가 null이 나올떄까지 free를 작동시키는데 null이 존재하지 않을 수 잇어서 할당하지 않은 메모리를 free할수 있다. 라는 말씀으로 이해했는데요. 제 코드에서 전체 들어올 입력 개수를 받은뒤 NodeAdd[N]=0; 를 통해서 항상 N개의 입력을 받은 후에 그 다음 값은 null이 되도록 작동하니, Free_Tree()함수는 항상 NodeAdd[0]~NodeAddN-1 까지만 free를 실행해서 메모리를 할당받지 않은 곳에는 free를 하지 않을것 같은데요.


    9년 전 link
  • Being
    Being

    아 그렇군요. 제가 그 부분을 확인하지 못했습니다.

    문제를 검토해 보니 문제에는 부모의 번호가 자식보다 작다는 말이 어디에도 없는데, 그러한 가정을 하신 것이 문제로 보입니다.


    9년 전 link
  • 정회원 권한이 있어야 커멘트를 다실 수 있습니다. 정회원이 되시려면 온라인 저지에서 5문제 이상을 푸시고, 가입 후 7일 이상이 지나셔야 합니다. 현재 문제를 푸셨습니다.