class CListNode
{
public:
CListNode();
CListNode(int i);
int m_Data;
CListNode *m_Next;
};
CListNode::CListNode():m_Data(0), m_Next(0)
{
}
CListNode::CListNode(int i):m_Data(i), m_Next(0)
{
}
class CList
{
public:
CList();
CList(int i);
CList(CList *pNew);
~CList();
int NextNode();
void _InsertAfter(int iNew);
void _DeleteAfter();
void _DeleteFront();
void _PrintData();
CListNode m_Head;
private:
CListNode *c_m_Head;
int m_iCount;
protected:
};
CList::CList()
{
m_Head.m_Next = NULL;
c_m_Head = &m_Head;
cout<<"1:"<<&m_Head<<endl;
}
CList::CList(int i)
{
_InsertAfter(i);
}
CList::~CList()
{
m_Head = *c_m_Head;
CListNode *p;
while( m_Head.m_Next!=NULL )
{
p = m_Head.m_Next;
m_Head = *(p->m_Next);
delete p;
}
}
void CList::_InsertAfter(int iNew)
{
CListNode *p= new CListNode(iNew);
p->m_Next = m_Head.m_Next;
m_Head.m_Next = p;
}
void CList::_DeleteFront()
{
}
void CList::_DeleteAfter()
{
CListNode *p;
p = m_Head.m_Next;
m_Head.m_Next = p->m_Next;
delete p;
}
void CList::_PrintData()
{
m_Head = *c_m_Head;
while( m_Head.m_Next!=NULL )
{
m_Head = *(m_Head.m_Next);
cout<<m_Head.m_Data<<endl;
}
}
int main()
{
CList *clist = new CList;
int i;
for(i=0; i<10; i++)
{
clist->_InsertAfter(i);
}
clist->_PrintData();
delete clist;
return 0;
}
先看析构函数和_PrintData()中的代码中的取地址可以说是一样的
可以发现,在clist->_PrintData();时,还可以顺利打出。
但是析构里连while都进不了.
跟踪m_Head地址发现是一样的。但是在分构里面m_Head.m_Next已经是NULL了
这里的原因是,delete时,先把clist的非指针变量给释放掉了。
所以要注意这样变量和指针混淆的情况
分享到:
相关推荐
在这段代码中,`p` 是一个指向堆内存的指针,它本身位于栈区。`new int[5]` 用于在堆区分配内存,而指针 `p` 存储在栈区,用来记录这块堆内存的起始地址。需要注意的是,释放这块内存时应使用 `delete[] p` 而不是 `...
- **生命周期**:变量从创建到销毁的时间段。栈上的变量在退出作用域后自动销毁,堆上的需要手动删除。 9. **常量(const)与枚举(enum)**: - **常量**:用const关键字声明的变量,其值不能改变。 - **枚举**...
1. **返回局部变量指针**:不要返回局部变量的地址,因为该变量在函数返回后会被销毁。如果需要返回一个指向特定对象的指针,应当使用动态分配的内存或者其他更安全的方法。 2. **局部变量与全局变量交互**:如果...
- **数组和指针混淆**:在某些情况下,数组和指针的行为相似,但在其他情况下则不同。 #### 22. C语言防止缓冲区溢出方法 - **使用安全的字符串函数**:如`strncpy()`替代`strcpy()`。 - **验证输入长度**:确保...
改错题中可能涉及函数声明与定义不匹配、返回值类型错误、局部变量与全局变量混淆等问题。 5. **数组与指针**:数组和指针是C语言的两大特色。改错题可能涉及到数组下标越界、指针未初始化、指针操作错误(如解引用...
- 局部变量使用后设为NULL,尤其是数组和集合,防止内存泄漏。 7. **安全性**: - 安全访问数组,避免越界。 - 避免同名变量混淆,局部变量不应与类或对象成员变量同名。 - 使用()明确操作符优先级,避免混淆。...
1. 动态内存:谨慎使用malloc、calloc、realloc和free,防止内存泄漏和悬挂指针。 2. 指针安全:确保指针初始化,避免野指针,且在使用后及时释放。 五、结构化编程 1. 函数封装:每个函数应有明确的职责,避免大...
全局变量和局部变量在内存中有显著的区别: - **全局变量**存储在静态数据区中。 - **局部变量**存储在堆栈中。 #### 平衡二叉树 平衡二叉树是一种特殊的二叉树,具有以下特征: - 左右子树都是平衡二叉树。 - ...
数组是一段连续的内存空间。当声明数组名作为函数参数时,两者声明相同,但实际上数组传递的是首地址。区分:`int arr[5];`是数组,`int *p;`是指针。 7. 左值(lvalue)是可以出现在赋值操作符左侧的表达式,右值...
- 使用局部变量存储中间结果,提高可读性。 **6.4 其它建议** - 遵循单一职责原则,一个函数只做一件事情。 - 使用适当的函数模板提高代码复用率。 **6.5 使用断言** - 断言用于调试阶段验证假设条件是否成立。 - ...
- 常见的内存错误包括野指针、内存泄漏、越界访问等。 - 通过代码审查、单元测试等手段检测并修复这些问题。 **7.3 指针与数组的对比** - 指针和数组在C/C++中有着紧密的联系,但也存在区别。 - 数组的大小是固定的...
- 理解堆和栈的区别,以及如何正确使用`new`和`delete`,是防止内存泄漏和段错误的关键。 15. **设计模式**: - 设计模式是面向对象编程中的最佳实践,如工厂模式、单例模式、观察者模式等,它们为解决常见问题...
3. **非法返回值**:非void函数应返回有效值,避免返回void或局部变量的地址,因为局部变量在函数退出后可能被回收。 4. **内存泄漏**:程序中分配的内存未在适当的时候释放,长期积累可能导致系统资源耗尽。 5. *...
- **局部变量的管理**:再入函数要求每次调用时都有独立的局部变量副本,这些副本通常存储在堆栈上。为了避免多个并发调用之间的数据混淆,可以使用静态分配或堆分配的方法来为每个调用创建独立的变量空间。 - **...
- 学习和遵循正确的内存分配和释放规则,如使用malloc/free或new/delete进行动态内存管理,避免内存泄漏。 以上规范旨在提高代码的可读性、可维护性和可靠性,遵循这些指导原则,可以帮助开发者编写出高效、稳定的...
- **智能指针**:为防止内存泄漏,C++11引入了智能指针如`std::unique_ptr`、`std::shared_ptr`和`std::weak_ptr`,它们自动管理内存。 - **栈与堆的区别**:栈内存由编译器自动管理,而堆内存需要程序员手动管理...
8. **理解动态内存管理**:C++的动态内存管理要求程序员手动管理内存,这可能导致内存泄漏和悬挂指针。理解何时使用`new`和`delete`,以及何时使用智能指针(如`shared_ptr`、`unique_ptr`)来自动化内存管理至关...
- 函数内部实现的注意事项,如局部变量的管理和异常处理机制。 - 断言的正确使用,用于调试阶段检查预设条件是否满足。 - 引用与指针的区别及其应用场景分析。 7. **内存管理**: - 内存分配的不同方式,如栈...
- **指针与引用**:指针是一个变量,存储地址,可以改变指向;引用是一个别名,一旦初始化后,就不能再改变引用的变量。 - **常量指针与指针常量**:`const int * p1`表示指针指向的内容不可变,`int * const p1`...