2013-06-14 2 views
1

포인터를 삭제하는 데 문제가 있습니다. 나는 불법적으로 컴파일하는 어떤 것도하지 않는다고 생각하지만, 아마도 나는 그렇습니다. 누군가 내 논리의 결함을 설명 할 수 있다면 고맙겠습니다. 아래에 함수가 충분히 도움이되기를 바랄뿐입니다. 코드 전체가 필요하다면 알려주세요. 추가하겠습니다!임시 포인터를 삭제할 수 없습니까?

아래는 내가 만든 링크 된 목록에서 사물함을 제거하는 기능입니다. 나는 생각할 수있는 모든 사건을 다루기 위해 최선을 다했습니다. 문제는 내가 삭제하려는 사물함의 메모리를 실제로 할당 해제하려고 할 때 발생합니다. 내가 잠긴 것을 참조하는 임시 변수를 삭제하려고 시도한 행은 코드가 포함되어 있기 때문에 주석 처리되어 있습니다. 분명히, 그들없이, 나는 내가 원하는 것처럼 사물함을 삭제할 수 없다.

int SelfStorageList::removeLockersOverdue() { 

int lockersDeleted = 0; 

if (isEmpty()) { 
    return 0; 
} 

if (head->objLocker.isRentOverdue && head==tail) { //If that was the only locker, the tail needs to be updated to = head = 0 
    delete head; 
    head = tail = 0; 
    return ++lockersDeleted; 
} 

LockerNode *prev = head; 
LockerNode *curr = head->next; 

while (curr != 0) { 

    if((curr == tail) && curr->objLocker.isRentOverdue) { //If the current locker is tail and needs deleting 
     LockerNode *temp = curr; 
     curr = prev; 
     //delete temp; 
     lockersDeleted++; 
    } 


    if(prev->objLocker.isRentOverdue) { //General case: Previous locker needs deleting 
     LockerNode *temp = prev; 
     prev = prev->next; 
     curr = curr->next; 
     //delete temp; 
     lockersDeleted++; 

    } 

    else { //Update the pointers if not updated anywhere else 

    prev = prev->next; 
    curr = curr->next; 

    } 

} 

return lockersDeleted; 

} 

"포인터"가 있습니까? (끔찍한 말 : p)

+5

실제로 발생하는 오류/동작은 무엇입니까? "코드 분할"은 실제로 도움이되지 않습니다. – tangrs

+0

할 수 있다면 더 많은 도움을 드리 겠지만 기술적으로 오류 메시지가 표시되지는 않습니다. 코드는 힙에 _ASSERTE (_BLOCK_TYPE_IS_VALID (pHead-> nBlockUse))라는 행에 전화를 겁니다. –

+1

'꼬리'가 유지되고 있습니까? 'if (curr == tail)'을 체크하는 대신'if (curr-> next! = 0)'를 체크하는 것이 어떻습니까? – bobobobo

답변

3

단일 링크 된 목록을 유지하고 있기 때문에 목록을 반복 할 때 prev 포인터를 추적하고있는 것을 볼 수 있습니다. 이전 노드가 무엇인지 기억하지 않고 단일 링크 된 경우 연결된 노드에서 이전 노드를 가져올 수 없으므로 물론 그렇습니다. 문제는 단순히 논리가 파기 된 것입니다. 삭제가 필요한 경우 curr 노드를 삭제하고 prev 노드를 패치하여 전에 next 포인터가 curr->next에 가리 키도록 패치해야합니다.

생각해 보면 : prev 노드를 삭제하는 것이지만 방금 삭제 한 prev 노드를 가리키는 "이전 노드"보다 가능성이 높습니다. 다음 번에리스트를 반복 할 때, 이전에 할당 된 노드를 반복 할 것이며,이 노드는 그 시점에서 완전히 다른 목적으로 할당 될 수 있습니다. 메모리 할당자는 다음에 removeLockersOverdue()를 호출 할 때 메모리가 아직 다른 것으로 할당되지 않았고 이미 삭제 한 동일한 노드를 계속 찾고 있기 때문에 메모리 내부 할당자가 일부 내부 어설 션에 실패했습니다. 기한이 지났고 다시 삭제하면 메모리 할당자가 할당되지 않은 메모리를 삭제한다고 불평하고 있습니다. (메시지가 분명하지 않다면 정말 좋을 것입니다!)

또한 첫 번째 노드 & 마지막 노드를 처리하기위한 특별한 경우는 &을 단순화 할 수 있습니다. 나는 당신을 위해 그것을 다시 작성하는 것을 피할 것이다. 그래서 당신이 그것을 당신 자신을 단순화 할 수 있는지 알 수있다.

+0

고마워요! 좋은 설명! 나는 당신과 @ Casey의 충고를 토대로 내 솔루션을 재 작업 할 수 있다고 생각합니다. 고맙습니다! –

3
while (curr != 0) { 
    if((curr == tail) && curr->objLocker.isRentOverdue) { 
     LockerNode *temp = curr; 
     curr = prev; 
     //delete temp; 
     lockersDeleted++; 
    } 

이전 노드의 다음 포인터를 여기에서 업데이트하지 않으므로 매달려 있습니다 (삭제 된 메모리 가리키기). 또한 tail은 삭제 된 노드를 가리 킵니다.

if(prev->objLocker.isRentOverdue) { 
     LockerNode *temp = prev; 
     prev = prev->next; 
     curr = curr->next; 
     //delete temp; 
     lockersDeleted++; 

    } 

다시 말하지만, 당신은 삭제 된 노드를 가리키는 목록에서 next 포인터를 업데이트하지 않습니다.

else { //Update the pointers if not updated anywhere else 

    prev = prev->next; 
    curr = curr->next; 

    } 
} 

루프에서 두 개의 포인터를 들고 다니면 혼란 스럽습니다. 현재 검사하고있는 노드를 추적하는 단 하나의 포인터로 다시 쓰고, 제거 논리를 올바로 취할 수 있도록 세 가지 가능한 경우의 그림을 그립니다 (첫 번째 노드 제거, 마지막 노드 제거, 내부 노드 제거).

+0

나중에 26 초 때려! – phonetagger

+0

@phonetagger 거짓말 쟁이! 겨우 23 초. – Casey

+0

하하, 두 분 덕분에! 당신은 모든 포인터를 추적하는 것이 조금 혼란 스러웠다는 것을 알았습니다 - 저는 제안 된대로 목록의 종이 일러스트레이션을 따르려고했습니다. 내가 관리하기가 쉽다는 점을 알았지 만 어쨌든 두 가지 가독성을 향상시킬 수 있다고 생각했습니다. 나는 그것을 하나로 구현할 수 있는지 살펴볼 것이다. 다시 한 번 감사드립니다! –

관련 문제