我打开了一个处理内存泄漏的动态内存分配的应用程序。这是我在这个类别中的第一个作业,所以对我来说它是相当新的。我的教授已经对作业进行了评分并告诉我,我的内存泄漏了。内存泄漏在DeleteNode()
函数中,我正在删除节点。有人可以向我解释为什么内存泄漏?我对这个主题非常新,我知道我很想念它,我只是需要它指出我想的。我的内存泄漏之外可能还有其他问题(有些地方我忘了查看内存是否已成功分配),但我理解的是,它只是我需要帮助的内存泄漏。另外,我只编写了AddNode()
,DeleteNode()
,BuildList()
和ZapList()
函数,我没有对其余函数进行编码,它是一个已经为我们编写的shell 。任何帮助将不胜感激。
#include <iostream>
#include <ctype.h>
#include <new>
//#include <process.h> // Needed for call to exit
using namespace std;
struct Node
{
enum { DUMMY_VALUE = 1 }; // Value () stored in dummy head node.
char Ch; // Holds the char data.
Node *Link; // Points to another struct of type Node.
};
typedef Node* NodePtr;
void AbortProgram (void);
void AddNode (char NewChar, NodePtr List);
void BuildList (NodePtr List);
void ZapList (NodePtr P);
void DeleteNode (char CharToDelete, NodePtr List, int &CharFound);
void StartList (NodePtr &List);
void ShowList (NodePtr List);
void DisplayMenuAndGetMenuChoice (char &MenuChoice);
void TestAddNode (NodePtr List);
void TestBuildList (NodePtr List);
void TestDeleteNode (NodePtr List);
void TestZapList (NodePtr List);
/***************************** main ********************************/
int main(void)
{
NodePtr List = NULL;
char MenuChoice;
system("cls");
cout << "This program allows you to test the routines needed \n"
"for homework 8. \n\n";
StartList(List);
if (List == NULL) // Unexpected error.
AbortProgram ();
do
{
DisplayMenuAndGetMenuChoice(MenuChoice);
switch( MenuChoice )
{
case 'Q': break; // Exit program
case 'B': TestBuildList(List);
break;
case 'A': TestAddNode(List);
break;
case 'D': TestDeleteNode(List);
break;
case 'Z': TestZapList(List);
break;
default : cout << "\nError: '" << MenuChoice
<< "' is not an option \n\n";
}
}
while ( MenuChoice != 'Q' );
return 0;
}
/********************* DisplayMenuAndGetMenuChoice *********************
Displays a menu of options and reads the user's choice into the
parameter MenuChoice. Unbuffered input is used, so the user does
not have to enter a newline character after typing a menu choice.
The MenuChoice is upcased.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
void DisplayMenuAndGetMenuChoice (char &MenuChoice)
{
const char* Option[] = {"B(uildList", "A(ddNode", "D(eleteNode",
" Z(apList", "Q(uit", "" };
char DottedLine[] ="\n- - - - - - - - - - - - - - - "
"- - - - - - - - - - - - - - - -\n ";
int K = 0;
cout << DottedLine;
while ( Option[K][0] != 0 ) // while we haven't gotten to ""
{
cout << Option[K]; // Display menu option
cout << " "; // Add some white space.
++K;
}
cout << "=> ";
MenuChoice = toupper(cin.get());
cin.ignore(10,'\n');
cout << DottedLine;
}
/************************ TestAddNode ********************************
Facilitates the testing of the function AddNode, a function which
adds a node to the tail end of a linked list. If the enter key is
pressed in response to the prompt, it is assumed that the user
wants to exit and this function is aborted.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
void TestAddNode (NodePtr List)
{
char NewChar;
cout << "\n\n---------------- Testing AddNode -------------------\n\n";
cout << "Character to be added? ";
NewChar = cin.get();
cin.ignore();
if (NewChar == '\n') // User pressed just enter key.
{
cout << "Aborting AddNode...";
return;
}
cout << NewChar;
cout << " -- Adding \'" << NewChar << "\'";
AddNode (NewChar, List);
cout << "\n\nThe new list: ";
ShowList(List);
}
/************************* TestBuildList **************************
Facilitates the testing of the function BuildList, which is supposed
to build an ordered linked list of characters.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
void TestBuildList (NodePtr List)
{
cout << "\n\n================= Testing BuildList ===================";
cout << "\n\nType the characters for the list - "
"when finished, press enter key\n\n ->";
BuildList(List);
cout << "\n\nAfter BuildList, List = ";
ShowList(List);
}
/*********************** TestDeleteNode *****************************
Facilitates the testing of DeleteNode, a function which is supposed
to delete characters from a linked list.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
void TestDeleteNode (NodePtr List)
{
int CharFound;
char CharToBeDeleted;
cout << "\n\n***************** Testing DeleteNode *******************";
cout << "\n\nCharacter to be deleted? ";
CharToBeDeleted = cin.get();
cin.ignore();
DeleteNode (CharToBeDeleted, List, CharFound);
if ( CharFound )
cout << "\n\n'" << CharToBeDeleted << "' has been deleted,";
else
cout << "\n\n'" << CharToBeDeleted << "' was not in the list,";
cout << "\n\nList = ";
ShowList(List);
}
/*********************** TestZapList *********************************
Facilitates the testing of ZapList, a function that is supposed to
return all storage allocated for a linked list to the heap (except the
storage occupied by the dummy head node.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
void TestZapList (NodePtr List)
{
cout << "\n\n^^^^^^^^^^^^^^^^^ Calling ZapList ^^^^^^^^^^^^^^^^^^^^^^^";
ZapList(List);
cout << "\n\nList = ";
ShowList(List);
}
/**************************** AbortProgram ****************************
Displays an error message and returns a non-zero error code to
the operating system.
Requires exit function prototyped in process.h.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
void AbortProgram (void)
{
cout << "\n\n\a A error has occurred while using the new operator. \n"
"Returning to the operating system\n";
cout << "Press ENTER key to continue: ";
cin.get();
exit(1);
}
/************************ StartList *********************************
DESCRIPTION Creates an empty list, i.e. a singly linked list that
contains only a dummy head node.
PARAMETER
OUT, List A pointer to the head node of the list. If the
dynamic memory allocation is unsuccessful, List will
hold NULL on exit.
PRECONDITION List points to NULL. If List points to an actual node,
calling this routine will create inaccessable memory.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
void StartList (NodePtr &List)
{
List = new(nothrow) Node;
if (List == NULL)
return; // Memory allocation error.
List->Ch = List->DUMMY_VALUE; // Fill in dummy head node fields
List->Link = NULL; // Initialize end of list.
}
/************************* ShowList ***********************************
DESCRIPTION Displays the character field of all of the nodes in List, a
singly linked list with a dummy head node. The list is
enclosed in quotes.
The constant MAX_CHARS_PER_LINE controls the maximum
number of characters displayed before a newline char
is displayed.
PARAMETER
IN, List A pointer to a singly linked list with a dummy head node.
NOTE To facilitate debugging this routine displays "NULL"
if called with List == NULL.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
void ShowList (NodePtr List)
{
const int MAX_CHARS_PER_LINE = 50;
int CharCount = 0;
if ( List == NULL )
{
cout << " NULL LIST\n\n";
return;
}
cout << "\""; // Display quote for ease of testing.
while ( List->Link != NULL )
{
List = List->Link;
cout << List->Ch;
if ( List-> Ch != '\n' ) // Increment CharCount unless newline
++CharCount; // char is encountered in List
else
CharCount = 0;
if ( CharCount % MAX_CHARS_PER_LINE == 0 )
cout << "\n ";
}
cout << "\"\n\n";
}
/***************************** ZapList ********************************
DESCRIPTION Frees all the storage space currently occupied by the
linked list pointed to by List. Does NOT delete the delete
the dummy head node.
PARAMETER
OUT, List A pointer to a singly linked list with a dummy head node.
After this call, List will contain only the dummy head node.
PRECONDITION List must point to a linked list that has a dummy head node
and a tail node that points at NULL.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
void ZapList (NodePtr List)
{
NodePtr Temp;
Temp=List->Link;//Temp holds position of first Node after dummy node
while (Temp != NULL)
{
List->Link=List->Link->Link;//rerouting dummy node pointer to skip next node and point to one after
delete Temp;
Temp=List->Link;
}
}
/**************************** AddNode *********************************
DESCRIPTION Adds a node containing NewChar to the end of List.
PARAMETERS
IN, NewChar The character to be added to the end of the list.
IN, List A pointer to a singly linked list with a dummy head node.
The value of List (address of dummy head node) is not
changed by this routine, so List is passed by value.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
void AddNode (char NewChar, NodePtr List)
{
NodePtr NewNode;
NodePtr PlaceHolder;
if (List->Link == NULL) // this if statement is used when the list coming in is empty (containing just the dummy)
{
List->Link = new Node;
List->Link->Ch = NewChar;
return;
}
PlaceHolder=List->Link; //placeholder and NewNode both point to first node after dummy node
NewNode=List->Link;
while (NewNode != NULL)
{
NewNode=PlaceHolder->Link; //Advance NewNode one node down the line
if (NewNode != NULL) // if NewNode is not poing to Null, allow it to point at same value as NewNode
PlaceHolder=NewNode;
} //After loop, NewNode will be pointing at Null
//Placeholder will be one position behind NewNode
NewNode= new Node;
NewNode->Link = NULL;
NewNode->Ch=NewChar;
PlaceHolder->Link = NewNode;
}
/**************************** DeleteNode ****************************
DESCRIPTION Deletes the first node of List that contains the char
CharToDelete. The storage occupied by the deleted
node is returned to the heap.
PARAMETERS
IN, CharToDelete The character to be deleted.
IN, List A pointer to a singly linked list with a dummy head node.
The value of List is not changed by this routine but the
linked list itself is changed.
OUT, CharFound Set to 1 if the CharToDelete is found and deleted and
0 otherwise.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
void DeleteNode (char CharToDelete, NodePtr List, int &CharFound)
{
NodePtr NodeToBeDeleted;
NodePtr PlaceHolder;
NodeToBeDeleted=List->Link; //Both NodeToBeDeleted and Placeholder point to first node after dummy
PlaceHolder=List->Link;
if (List->Link == NULL)// this if-statement is here for empty linked lists coming in
{ // immediately set CharFound to 0 and end function
CharFound=0;
return;
}
while (CharFound != 1) // as soon as character is found, break out
{
if (NodeToBeDeleted->Ch == CharToDelete) // check to see if CharToDelete is found
{
delete NodeToBeDeleted;
CharFound = 1;
}
if (CharFound == 0) // if not found, advance NodeToBeDeleted to the next postion
NodeToBeDeleted=PlaceHolder->Link;
if (NodeToBeDeleted == NULL) // as soon as NodeToBeDeleted points to null, stop testing
return;
if (NodeToBeDeleted->Ch != CharToDelete)
PlaceHolder = NodeToBeDeleted;
// only advance Placeholder to NodeToBeDeleted if CharToBeDeleted
// isn't found. Once found, placeHolder remains one position behind
// to allow linking of the list one node before deleted node
// to one node after deleted node
}
PlaceHolder->Link=PlaceHolder->Link->Link;
NodeToBeDeleted = NULL;
}
/**************************** BuildList *****************************
DESCRIPTION Builds a singly linked list with a dummy head node. The
characters in the list are in the same order in which the
user enters them, i.e. new characters are added to the tail
end of the list.
Input terminates when the enter key is pressed.
PARAMETERS
IN, List A pointer to a singly linked list with a dummy head node.
It is imperative that List be initialized before calling
this routine.
NOTE Before building the new list, ZapList is called. This
ensures that a memory leak does not develop.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
void BuildList (NodePtr List)
{
char NewChar;
NodePtr CurrentNode;
ZapList(List);// ADDED AFTER IT WAS GRADED FOR HW9
cin.get(NewChar);
while (NewChar != '\n')
{
CurrentNode = new Node; // attempt to create new node and have CurrentNode point to it
if (CurrentNode == NULL)
return;
CurrentNode->Link = NULL; //in new node, have node Link pointer point to NULL
CurrentNode->Ch=NewChar;
List->Link=CurrentNode; //connect the newly created and filled node (Current Node) to list
List=List->Link; //advance List to next pointer
cin.get(NewChar);
}
}
答案 0 :(得分:2)
该死,狙击。
以下伊万的回答是正确的。它通常不会出现段错误,因为在重新分配之前,释放的内存实际上没有任何内容,它在引用它时仍然包含有效数据,因此通常不会出现问题。
内存泄漏来自于您正在删除正在(或在这种情况下已被删除)的变量上的链接指针。因此,您放松了列表其余部分的句柄。
您的PlaceHolder指针应指向NodeToBeDeleted上方的一个节点,而不是指向同一节点。
答案 1 :(得分:1)
您可能会遇到内存泄漏的一种方法是在此测试中使用未初始化的变量:
while (CharFound != 1)
CharFound
从调用函数(TestDeleteNode
)传入,该函数未初始化变量CharFound
。
如果CharFound
传入的值为1(可能会发生),那么你根本不会完成你的循环,在这种情况下你只能执行
PlaceHolder->Link=PlaceHolder->Link->Link;
会在“PlaceHolder-&gt;链接&#39;
中泄漏内存在正常情况下,正如@Ivan所说,你正在删除对象,无论是Ivan提到的对象(NodeToBeDeleted->Ch
),还是PlaceHolder->Link->Link
,你都会deleted
PlaceHolder->Link
1}} notnull
指向的内存。