2009-09-19 8 views
0

나는 거의 완료 한 숙제가 있습니다.힙 손상, 가능한 메모리 누수, C++

내 프로그램이 끝날 때 충돌을 막을 수있는 방법을 알고 싶었던만큼 비효율적이었습니다.

quack::quack(int capacity) : backPtr(NULL), frontPtr(NULL) 
{ 
    items = new item[capacity]; 
    backPtr = new item; 
    frontPtr = new item; 
    midPtr = new item; 
    current = new item; 

    maxSize = capacity; 
    back = maxSize-1; 
    count = 0; 
    top  = -1; 
} 

quack::~quack(void) 
{ 
    delete frontPtr; 
    delete backPtr; 
    delete current; 
    delete midPtr; 
    delete [] items; //Heap Corruption Debug Error at the end of program. 

    items = NULL; 
    maxSize = 0; 
    back  = 0; 
} 

bool quack::pushFront(const int n) 
{  
    int i = 0; 

    if (count == maxSize) // Then we cant add to it n e more. 
    { 
     throw runtime_error("Stack is Full");// Full Stack 
     return false; 
    } 
     backPtr->n = items[back-1].n; 
     while (i < count) // Loop less than however many we counted. 
     { 
      if (i == top+1) 
      { 
       current->n = items[top+1].n; 
       items[top+1].n = backPtr->n; 
      } 

      midPtr->n = items[++i].n; 
      items[i].n = current->n; 

      if (i != back-1) 
      { 
       current->n = items[++i].n; 
       items[i].n = midPtr->n; 
      } 
     } 
     ++count; 
     items[top+1].n = n; 
     return true;  
} 

bool quack::pushBack(const int n) 
{ 
    items[count].n = n; 
    count++; 
    return true; 
} 

bool quack::popFront(int& n) 
{ 
    n = items[top+1].n; 
    for (int i = 0; i < count; i++) 
    { 
     items[i] = items[i+1]; 
    } 
    count--; // Remove top element. 
    return true; 
} 

bool quack::popBack(int& n) 
{ 

    n = items[--count].n; 
    return true; 
} 

void quack::rotate(int r) 
{ 
    int i = 0; 

    while (r > 0) // rotate postively. 
    { 
     frontPtr->n = items[top+1].n; 
     for (int i = 0; i < back; i++) 
     { 
      items[i] = items[i+1];     
     } 
     items[back-1].n = frontPtr->n; 
     r--; 
    } 

    while (r < 0) // rotate negatively. 
    { 
     if (i == top+1) 
     { 
      backPtr->n = items[back-1].n; 
      current->n = items[top+1].n; 
      items[top+1].n = backPtr->n; 
     } 
      midPtr->n = items[++i].n; 
      items[i].n = current->n; 

      if (i == back-1) 
      { 
       items[back-1].n = current->n; 
       i = 0; 
       r++; continue; 
      } 
     else 
     { 
      current->n = items[++i].n; 
      items[i].n = midPtr->n; 
      if (i == back-1) 
      { 
       i = 0; 
       r++; continue; 
      } 
     } 
    } 
} 

void quack::reverse(void) 
{ 
    int j = 0; // Variable declaration/initialization. 

    frontPtr->n = items[top+1].n; 
    backPtr->n = items[back-1].n; 

    for (int i = 0; i < count/2; i++) 
    { 
     items[j].n = items[i].n; 
     items[i].n = items[ count - i-1 ].n; 
     items[ count - i-1 ].n = items->n; 
    } 

    items[top+1].n = backPtr->n; 
    items[back-1].n = frontPtr->n; 
} 

int quack::itemCount(void) 
{ 
    return count; 
} 

ostream& operator<<(ostream& out, quack& q) 
{ 
    if (q.count == 0) // No elements have been counted. 
    out << endl << "quack: empty" << endl; 
    else 
    { 
     out << endl << "quack: "; 
     for (int i = 0; i < q.count; i++) 
     { 
      if (i < q.count-1) 
       out << q.items[i].n << ", "; 
      else out << q.items[i].n; 
     } 
     out << endl << endl; 
    } 
    return out; 
} 

와 헤더 파일 : 나는이 코드를 읽으면서이 몇 번을 편집 할거야

#include <ostream> 

using namespace std; 

class quack 
{ 
public: 
    quack(int capacity); 
    ~quack(void); 
    bool pushFront(const int n); // Push an item onto the front. 
    bool pushBack(const int n);  // Push an item onto the back. 
    bool popFront(int& n);   // Pop an item off the front. 
    bool popBack(int& n);   // Pop an item off the back. 
    void rotate(int r);    // "rotate" the stored items (see note below). 
    void reverse(void);    // Reverse the order of the stored items. 
    int itemCount(void);   // Return the current number of stored items. 

private: 
    int maxSize; // is for the size of the item stack 
    int back; // is for the back or "bottom" of the stack 
    int count; // to count the items added to the stack 
    int top; 

    struct item      // Definition of each item stored by the quack. 
    { 
     int  n; 
    }; 

    item  *items;    // Pointer to storage for the circular array. 
    item  *backPtr; 
    item  *frontPtr; 
    item  *midPtr; 
    item  *current; 

public: 
    friend ostream& operator<<(ostream& out, quack& q); 
}; 
+0

나는 * 5 이상의 포맷팅을 읽었으며 실제로는 이해하지 못한다. 누군가가 나에게 마침내 이해할 것이라고 말한다면 아마도. – user40120

+0

모든 코드를 들여 쓰기하여 다시 포맷 할 수 있습니까? –

+1

편집 창에서 "원하는대로"를 올바르게 편집하면 어떻게되지만 결과가 다른지는 다릅니다. – user40120

답변

5

, 용서해주십시오. 그것은 당신이 더블 엔드 큐 (dequeue)를 구현하는 것으로 보입니다.

생성자

items = new item[capacity]; 
backPtr = new item; 
frontPtr = new item; 
midPtr = new item; 
current = new item; 

이 이해가되지 않습니다. 앞/뒤/중간/현재 포인터는 실제로 아이템 중 하나를 가리 키지 않습니다. frontPtr = items+0backPtr = items + capacity-1 (또는 그 반대)을 원할 수도 있습니다. dequeue가 midPtr 또는 현재를 필요로하는지 확실하지 않습니다.

[편집 : 그것은 아이템이 struct item { int n } 인 것처럼 보이고 주변을 복사하는 것입니다. 그리고 당신은 다시 뒤로 지수와 상위 인덱스 ...]

소멸자 전면 이후

delete frontPtr; 
delete backPtr; 
delete current; 
delete midPtr; 
delete [] items; //Heap Corruption Debug Error at the end of program. 

// 등이있다. 항목 안쪽을 가리켜 야 할 경우이 항목 중 일부를 두 번 비우는 것입니다. 그것은 당신의 힙 부패 추락일지도 모릅니다. [편집 : 여부, 이상한 복사 고려]

items  = NULL; 
maxSize = 0; 
back   = 0; 

이 오히려 바보 같다을 (객체는 더 이상 되려고 없으며 관심있는 사람?) ..., 무엇

ERR 좋아, 간단한 디큐 일하는 것이 일반적인 방법은 요소의 배열하는 것입니다 :

items  -> 1 2 3 4 5 6 7 8 9 … 
front_ptr -----------/     /|\ 
back_ptr --------------------------------+ 

을 그리고 당신은 (배열의 첫 번째 사용 장소와 다른 포인터를 가리키는 포인터 (frontPtr)가 줄 backPtr) 마지막으로 사용한 지점을 가리 킵니다. 그래서하는 pop_front는 다음과 같이 할 것 : 유사하다 (4)와 pop_back를 가리 키도록 3을 반환

if (frontPtr <= backPtr) { 
    return *frontPtr++ 
} else { 
    // tried to pop from empty dequeue, handle error 
} 

및 사전 front_ptr을 (하지만 테스트로 반전하고,와 - 대신 ++의) .

또는 포인터 대신 인덱스를 저장할 수 있습니다. 하지만 하나를 선택하고 색인과 포인터를 모두 사용하지 마십시오.

+0

이 방법을 사용하면 rotate 메소드를 구현하는 것이 더 쉽습니다. 방향 (방향에 따라 뺄셈)에 따라 인덱스 (또는 포인터)를 사용하면됩니다. – Vargas

+0

@Vargas : OP는 성능을 신경 쓰지 않기 때문에, rotate는 매우 간단합니다 : push_back (pop_front()), 반복 횟수. – derobert

0

valgrind으로 실행하십시오.

+2

그는 도구가 필요 없으며, 그가 무엇을하고 있는지 이해해야합니다. – karx11erx

+0

공구의 정확한 _ 출력 _이 될 것입니다. – Zed

+0

아니요, valgrind가 포인터와 그 사용법/응용 프로그램의 종류가 무엇인지 설명하지 않기 때문입니다. – karx11erx

2

포인터는 익숙해지는 데 시간이 걸리는 것들 중 하나입니다.

당신은 할당 할 때

items = new item[capacity] 
효과적으로 '항목'의 배열의 첫 번째 요소에 대한 포인터 '항목'을 가리키는 힙에 할당 된

:

items -> {item}{item}{item}..{item} // capacity 

귀하의 다른 포인터해야 같은 배열을 가리키고 나중에 가리키는 것을 지우지 말고 '항목'을 삭제하면됩니다.

delete [] items 

배열과 포인터는 서로 바꿔 쓸 수 있습니다.

개 +1은 & 개 항목과 동일합니다. [1] * (items + 1)은 [1] 항목과 같습니다. 어레이의 두 번째 항목에

이 만들어

'현재'점 :

current = items + 1 

이 '현재'때문에 동작하지 않는 포인터 및 항목 [1] 어레이 내의 아이템 객체가 아니라이다 주소 : 이것은 그러나 작동

current = items[1] 

:

current = &items[1] 
+0

그냥 질문에 대답하기위한 +1 – Vargas

1

귀하의 주요 문제는 backptr, FR을 이해하는 것입니다 ontptr, midptr 및 current는 항목과 다른 목적을 가지고 있습니다. 엄밀히 말하자면, 그들은 모든 메모리 위치를 가리키고 있지만, 의미 론적 항목은 데이터 컨테이너 (배열)에 대한 앵커의 일종이며 다른 포인터의 목적은 그 데이터를 관리하는 것입니다 (서적 유지).

할당 할 메모리를 지정해야하는 항목은 항목뿐입니다. 다른 포인터는 배열 (항목) 항목 점을 가리켜 야합니다.

결과적으로 ctor 및 dtor에서 backptr, frontptr, midptr 및 current를 NULL로 설정하고 new 및 delete 항목 만 사용해야합니다.

Btw, 귀하의 작업이 그것을 허용할지 모르겠지만 배열 대신 링크 된 목록을 사용하면 목록 관리 (backptr, frontptr, midptr 및 current에 대해 int 유형을 사용할 수도 있음) .

1

items 어레이를 삭제할 때 두 가지 가능한 원인이 발생할 수 있습니다.

  1. 클래스에는 사용자 지정 복사본 생성자 또는 할당 연산자가 없습니다. 내장 된 것이 좋지 않기 때문에 이것은 필수적입니다. 값으로 quack을 매개 변수로 전달하거나 함수에서 하나를 반환하거나 quack을 변수에 복사하면 두 quack은 동일한 items 배열을 가리키게됩니다. 두 번째 파일이 파괴되면, 두 번째로 delete 배열을 시도 할 것이고 John Lennon은 힙 오브젝트 삭제에 대한 유명한 노래에서 "아니, 아니, 두 번째 시간은 아닙니다"를 관찰했습니다.

  2. 코드 내에 items 배열에 많은 내용을 기록합니다. 배열의 끝 (또는 시작 전에)을 쓰는 경우 삭제할 때 힙 구현은 메모리 블록을 비우는 데 필요한 일부 관리 정보를 삭제했기 때문에이를 삭제할 때 감지됩니다 .대부분의 사람들이이 코드를 작성하려고 할 때와 마찬가지로 코드에 버그가있을 가능성이 큽니다.

C++에서이를 쉽게 감지 할 수 있습니다. 원시 배열을 사용하지 마십시오. 배열을 래핑하고 클래스에 대한 모든 액세스에 대해 경계 검사를 수행하는 클래스를 사용합니다. 연산자 (경계가 확인되지 않음) 대신 std::vector을 사용하고 at 함수를 사용하면됩니다.

+0

(2)에서 items 배열 앞에 쓰면 힙 손상이 발생할 가능성이 큽니다. 대부분의 구현은 블록 바로 앞에 할당 된 메모리 블록에 정보를 넣는 것처럼 보입니다. 사실, 내가 할 수만 있다면 더 많은 업보트를 줄 것입니다. –