一、链表
链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。
链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。
指针作为维系结点的纽带,可以通过它实现链式存储。假设有五个学生某一门功课的成绩分别为A、B、C、D和E,这五个数据在内存中的存储单元地址分别为1248、1488、1366、1022和1520,其链表结构如图5.4所示。
图5.4单链表示意图
链表有一个“头指针”变量,图5.4中以 head表示,它存放一个地址,该地址指向链表中第一个结点,第一个结点又指向第二个结点……直到最后一个结点。该结点不再指向其他结点,它称为“表尾”,它的地址部分存放一个“NULL”(表示“空地址”),链表到此结束。链表中每个结点都包括两个部分:用户需要用的实际数据和下一个结点的地址。
可以看到链表中各结点在内存中可以不是连续存放的。要找到某一结点C,必须先找到其上一个结点B,根据结点B提供的下一个结点地址才能找到C。链表有一个“头指针”,因此通过“头指针”可以按顺序往下找到链表中的任一结点,如果不提供“头指针”,则整个链表都无法访问。链表如同一条铁链一样,一环扣一环,中间是不能断开的。打个比方,幼儿园的老师带领孩子出来散步,老师(作为头指针)牵着第一个小孩的手,第一个小孩的另一只手牵着第二个孩子……这就是一个“链”,最后一个孩子有一只手空着,他是“链尾”。要找这个队伍,必须先找到老师,然后按顺序找到每一个孩子。
图5.4的链表每个结点中只有一个指向后继结点的指针,该链表称为单链表。其实结点中可以有不止一个用于链接其他结点的指针。如果每个结点中有两个用于链接其他结点的指针,一个指向前趋结点(称前趋指针),另一个指向后继结点(称后继指针),则构成双向链表。双向链表如图5.5所示。
图5.5双向链表示意图
链表的一个重要特点是插入、删除操作灵活方便,不需移动结点,只需改变结点中指针域的值即可。而数组由于用存储单元的邻接性体现数组中元素的逻辑顺序关系,因此对数组进行插入和删除运算时,可能需要移动大量的元素,以保持这种物理和逻辑的一致性。如数
组中有m个元素,往第i(i 双向链表的插入和删除动态图: 双向链表的删除 双向链表的插入 链表的基本操作 • 生成结点 • 输出链表 • 查找结点 • 插入结点 • 删除结点 • 清空链表 结合程序来进行学习! 二、“打开”对话框和“保存”对话框的设计及其实现 1、CFileDialog类 (1)派生层次关系 (2)构造函数 CFileDialog( BOOL bOpenFileDialog, LPCTSTR lpszDefExt = NULL, LPCTSTR lpszFileName = NULL, DWORD dwFlags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, LPCTSTR lpszFilter = NULL, CWnd* pParentWnd = NULL ); 参数1:BOOL bOpenFileDialog TRUE——构建“打开”对话框;FALSE——构建“保存”对话框; 参数2:LPCTSTR lpszDefExt = NULL 指定默认的扩展文件名(如:“txt”);为NULL时,没有扩展名。 参数3:LPCTSTR lpszFileName = NULL 指定对话框中的文件对话框中的“初始文件名”;为NULL时,没有文件名。 参数4:DWORD dwFlags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT 定制对话框的一个或多个标记的组合。OFN_HIDEREADONLY隐藏只读标记;OFN_OVERWRITEPROMPT保存文件时出现是否覆盖对话框。 参数5:LPCTSTR lpszFilter = NULL 指定一个或一组文件过滤器。如\"Text Files(*.txt)|*.TXT|\" 参数6:CWnd* pParentWnd = NULL 例: 1、“打开”对话框 CFileDialog xfile(TRUE,\"TXT\ \"Text Files(*.txt)|*.TXT|\ Xfile.m_ofn.lpstrTitle=”打开指定的通讯录文件”; 2、“保存”对话框 CFileDialog xfile(FALSE,\"TXT\ \"Text Files(*.txt)|*.TXT|\ Xfile.m_ofn.lpstrTitle=”保存通讯录到指定的文件”; 二、文件操作与文件流 1、基本概念 文件,一般指存储在外部介质上数据的集合。 一批数据是以文件的形式存放在外部介质上的。操作系统是以文件为单位对数据进行管理的。要向外部介质上存储数据也必须先建立一个文件(以文件名标识),才能向它输出数据。 常用到的文件有两大类:程序文件(program file);数据文件(data file) 程序中的输入和输出的对象就是数据文件。 根据文件中数据的组织形式,可分为ASCII文件和二进制文件。 (1) ifstream类,它是从istream类派生的。 用来支持从磁盘文件的输入。 (2) ofstream类,它是从ostream类派生的。 用来支持向磁盘文件的输出。 要以磁盘文件为对象进行输入输出,必须定义一个文件流类的对象,通过文件流对象将数据从内存输出到磁盘文件,或者通过文件流对象从磁盘文件将数据输入到内存。 例如:ifstream fin; ofstream fout; 2、文件的打开与关闭 (1)打开磁盘文件 打开文件是指在文件读写之前做必要的准备工作,包括: 1) 为文件流对象和指定的磁盘文件建立关联,以便使文件流流向指定的磁盘文件。 2) 指定文件的工作方式。 以上工作可以通过两种不同的方法实现。 方法1:使用open()成员。函数说明:如果打开操作失败,open函数的返回值为0(假),因此经常使用下面的语句判断打开文件操作是否成功! 读入文件: ifstream fin; fin.open(xfile.GetFileName(),ios::in); //调用成员函数open if(!fin) { MessageBox(\"File Open Error!\OnOK(); } 保存文件: ofstream fout; fout.open(xfile.GetFileName(),ios::out); if(!fout) { MessageBox(\"Writing File Error!\OnOK(); } 方法2:ostream outfile(″f1.dat″,ios::out); (2)关闭磁盘文件 在对已打开的磁盘文件的读写操作完成后,应关闭该文件。 关闭文件用成员函数close。 如:fin.close(); fout.close(); 所谓关闭,实际上是解除该磁盘文件与文件流的关联,原来设置的工作方式也失效,这样,就不能再通过文件流对该文件进行输入或输出。 3、对ASCII文件的操作 如果文件的每一个字节中均以ASCII代码形式存放数据,即一个字节存放一个字符,这个文件就是ASCII文件(或称字符文件)。程序可以从ASCII文件中读入若干个字符,也可以向它输出一些字符。 对ASCII文件的读写操作可以用以下两种方法: (1) 用流插入运算符“<<”和流提取运算符“>>”输入输出标准类型的数据。 (2) 用文件流的put,get,geiline等成员函数进行字符的输入输出。 工程训练——编程实习 一、题目:设计并实现一个“简单的通讯录管理系统” 二、目的:通过“简单的通讯录管理系统”的设计,培养学生综合利用C++语言进行程序设计的能力,要求学生利用系统提供的标准函数及典型算法进行设计加强函数的运用及学生对软件工程思想的初步认识,提高软件系统分析能力和程序文档建立、归纳总结的能力。 三、基本要求: (1)要求用C++语言编程,在Visual C++环境下调试完成; (2)要求划分功能模块,各个功能分别使用函数来完成; (3)源代码程序要有必要的注释。 四、功能描述及要求 本程序实现的功能是一个简单的通讯录管理信息系统。它以对话框的方式弹出界面,用户所进行的所有操作都是在这个对话框中完成的。该程序类似与数据库,但是使用数据文本文件结合链表结构进行实现。体现了可视化和人性化的要求。通讯信息包括姓名、性别、通讯地址、电话号码等,具有查找记录,追加记录,删除记录等功能。 详细功能描述 (1)查找记录:以姓名为关键字,查找并显示该记录; (2)追加记录:将当前记录追加到通讯录; (3)删除记录:删除当前显示的记录; (4)第一条记录:显示通讯录中的第一条记录; (5)后一条记录:显示通讯录中的后一条记录; (6)前一条记录:显示通讯录中的前一条记录; (7)末一条记录:显示通讯录中的末一条记录; (8)加载数据:通过菜单加载通讯录对应的数据文件; (9)保存数据:通过菜单保存通讯录到指定的数据文件; (10)清除数据:清除当前数据; (11)结束程序:退出程序。 五、创新要求 在基本要求达到后,进行创新设计: (1)对程序功能进行拓展,使其更加实用。例如: 1)增加以电话号码为关键字,查找并显示该记录; 2)在追加记录的函数中,增加:若追加记录中姓名与通讯录中已有记录同名,则不能追加; 3)插入记录:给出插入位置,执行插入后,查询并显示是否被插入。 六、考核方式 1、30%:上机考试或回答问题。周五全天。 2、70%:撰写“工程训练——编程实习报告”及其程序,周五中午交。 报告格式要求如下:1)封面: 工程训练 编程实习报告 简单的通讯录管理系统设计与实现 AddressBook V1.0 姓名: 学号: 班级: 专业: 指导教师: 完成日期: 2)正文要包括的内容: 一、功能描述及要求 本程序实现的功能是一个简单的通讯录管理信息系统。它以对话框的方式弹出界面,用户所进行的所有操作都是在这个对话框中完成的。该程序类似与数据库,但是使用数据文本文件结合链表结构进行实现。体现了可视化和人性化的要求。通讯信息包括姓名、性别、通讯地址、电话号码等,具有查找记录,追加记录,删除记录等功能。详细功能描述如下: (1)查找记录:以姓名为关键字,查找并显示该记录; (2)追加记录:将当前记录追加到通讯录; (3)删除记录:删除当前显示的记录; (4)第一条记录:显示通讯录中的第一条记录; (5)后一条记录:显示通讯录中的后一条记录; (6)前一条记录:显示通讯录中的前一条记录; (7)末一条记录:显示通讯录中的末一条记录; (8)加载数据:通过菜单加载通讯录对应的数据文件; (9)保存数据:通过菜单保存通讯录到指定的数据文件; (10)清除数据:清除当前数据; (11)结束程序:退出程序。 „ 二、程序运行界面截图及其说明 三、对题目的分析、设计中遇到的主要问题及解决办法,对设计的感想和心得。 四、有注释行的源程序清单(全部的*.h和*.cpp文件) 通讯录的设计与实现步骤及其说明 一、建立一个应用程序框架 1、启动Microsoft Visual C++ 6.0; 2、File——New——Projects——路径——Project name:“AddressBook”—— MFC AppWizard(exe)——OK——选择“Dialog based”——Next>——Next>——选择“As a statically linked library”;——Next>——Finish——OK; 3、Build——Rebuild All——运行!——观察自动生成的应用程序。 二、主窗口设计:构造应用程序的用户接口 1、删除窗体中的“确定”、“取消”、“ToDo”控件; 2、在窗体中加入必要的控件,设计好的界面如图1所示,注意使用对齐按钮; 其中涉及到的控件及其属性如下: 控件类型 Static Text Radio Button Edit Button ID IDC_STATIC IDC_RADIOMALE IDC_EDNAME IDC_EDTEL IDC_EDADD IDC_EDITPOS IDC_BTFIND IDC_BTAPPEND IDC_BTDELETE IDC_BTINSERT IDC_BTEXIT IDC_BTTOP IDC_BTPREVIOUS IDC_BTNEXT IDC_BTLAST Caption 姓名、性别、电话、地址、当前记录 男 查询 追加 删除 插入 退出 第一个 前一个 后一个 末一个 备注 选择Group 不选择Group 选中ReadOnly IDC_RADIOFEMALE 女 3、设计查询窗口 在用姓名查询时要用到一个输入姓名以供查询的窗口,增加这个窗口的方法是: (1)左键单击ResourceView标签——右击AddressBook Resource——Insert ——Insert Reource对话框中选择Dialog——New按钮; (2)右击新建的对话框——Properties:——修改IDD_DIALOG1为IDD_GETNAME——删除“OK”、“Cancel”按钮; (3)在IDD_GETNAME中加入一个静态文本、一个文本输入框、两个按钮,属性如下: 控件类型 Static Text Edit Button ID IDC_STATIC IDC_EDGETNAME IDC_BTOK IDC_BTCANCEL Caption 输入姓名 确定 取消 备注 (4)适当调整窗口大小,设计好的窗口如图2所示。 4、增加变量 (1)把IDD_GETNAME对话框与窗体关联 1)单击ResourceView标签中的IDD_GETNAME——View菜单——Class Wizard——弹出一个对话框,要求把IDD_GETNAME与一个类进行关联; 2)单击“Create a new class”——OK——Name中输入Getname——OK(说明:这样就为IDD_GETNAME对话框建立起了一个新类Getname); (2)为IDD_GETNAME和IDD_ADDRESSBOOK_DIALOG对话框增加变量; 1)View菜单——Class Wizard——Member Variables 2)完成后的变量及相关属性如下: Control Ids IDC_EDADD IDC_EDPOS IDC_EDNAME IDC_EDTEL IDC_RADIOMALE 变量名 m_add m_pos m_name m_tel m_sex 变量类型 CString CString CString CString CString int 所属类 Getname 作用 存储姓名 IDC_EDGETNAME m_getname CAddressBookDlg 存储地址 CAddressBookDlg 存储位置 CAddressBookDlg 存储姓名 CAddressBookDlg 存储电话 CAddressBookDlg 存储性别 (3)把两个对话框关联 说明:IDD_GETNAME与IDD_ADDRESSBOOK_DIALOG对话框向关联就是把Getname类和CAddressBookDlg类相关联。IDD_ADDRESSBOOK_DIALOG为主对话框,程序在运行时首先建立它的对象,并用该对象的DoModal()成员函数显示;类似地在查询时要有一个Getname类的对象,并用该对象去调用DoModal()成员函数,以便显示IDD_GETNAME查询窗口。因此,我们可以在CAddressBookDlg类中定义一个Getname类的对象即可,具体如下: 1)FileView——AddressBookDlg.h——在该文件头部加入“#include “Getname.h””——在CAddressBookDlg类定义的public:成员中加入:“Getname getnameobj;”来说明:由于 getnameobj作为CAddressBookDlg类的一个成员变量,因此,在系统生成CAddressBookDlg类的对象时,会先调用Getname类的构造函数生成getnameobj对象,而当程序结束时,又会调用Getname类的析构函数释放该对象。 通过上述步骤,我们可把两个对话框关联起来,在CAddressBookDlg类的任何成员函数中都可以使用这个getnameobj变量。 5、增加菜单 (1)左键单击ResourceView标签——右击AddressBook Resource——Insert ——Insert Reource对话框中选择Menu——New按钮; (2)依次增加菜单项,属性如下: ID ID_MENUITEMLOAD ID_MENUITEMSAVE ID_MENUITEMEXIT Caption 加载数据 保存数据 退出 备注 不选Pop_up 不选Pop_up 不选Pop_up 不选Pop_up ID_MENUITEMCLEAR 清除数据 (3)把菜单与类进行关联 菜单View——Class Wizard——弹出“Adding a Class”对话框(表示菜单资源要与某个类关联起来)——选择“Select an existing Class”——OK——弹出“Select Class”对话框——选择CAddressBookDlg——OK即可。 说明:CAddressBookDlg类对应了主窗体,把菜单与该类关联,则菜单函数就可以访问CAddressBookDlg的各个成员。 (4)为窗口设置菜单(截止(3)为止,还不可见菜单)——窗口与菜单进行关联 ResourceView——双击IDD_ADDRESSBOOK_DIALOG——右击对话框——Properties——General标签中的Menu——选择设计的菜单即可。 三、将菜单映射到消息处理函数 菜单View——Class Wizard——Message Maps标签——Class name:选择CAddressBookDlg——Object IDs:选择具体的ID——Messages:选择COMMAND——Add Function——代码后续添加。 ID_MENUITEMLOAD ID_MENUITEMSAVE ID_MENUITEMCLEAR ID_MENUITEMEXIT 1、AddressBookDlg.h文件中: //{{AFX_MSG(CAddressBookDlg) afx_msg void OnMenuitemexit(); afx_msg void OnMenuitemclear(); afx_msg void OnMenuitemload(); afx_msg void OnMenuitemsave(); //}}AFX_MSG 2、AddressBookDlg.cpp文件中: BEGIN_MESSAGE_MAP(CAddressBookDlg, CDialog) //{{AFX_MSG_MAP(CAddressBookDlg) ON_COMMAND(ID_MENUITEMEXIT, OnMenuitemexit) ON_COMMAND(ID_MENUITEMCLEAR, OnMenuitemclear) ON_COMMAND(ID_MENUITEMLOAD, OnMenuitemload) ON_COMMAND(ID_MENUITEMSAVE, OnMenuitemsave) //}}AFX_MSG_MAP END_MESSAGE_MAP() 3、AddressBookDlg.cpp文件中: void CAddressBookDlg::OnMenuitemexit() { // TODO: Add your command handler code here } void CAddressBookDlg::OnMenuitemclear() { // TODO: Add your command handler code here } void CAddressBookDlg::OnMenuitemload() { // TODO: Add your command handler code here } void CAddressBookDlg::OnMenuitemsave() { // TODO: Add your command handler code here } 四、将按钮映射到命令 菜单View——Class Wizard——Message Maps标签——Class name:选择CAddressBookDlg——Object IDs:选择具体的ID——Messages:选择BN_CLICKED——Add Function——代码后续添加。 IDC_BTFIND IDC_BTAPPEND IDC_BTDELETE IDC_BTINSERT IDC_BTEXIT IDC_BTTOP IDC_BTPREVIOUS IDC_BTNEXT IDC_BTLAST 查询 追加 删除 插入 退出 第一个 前一个 后一个 末一个 1、AddressBookDlg.h文件中: //{{AFX_MSG(CAddressBookDlg) virtual BOOL OnInitDialog(); afx_msg void OnSysCommand(UINT nID, LPARAM lParam); afx_msg void OnPaint(); afx_msg HCURSOR OnQueryDragIcon(); afx_msg void OnMenuitemexit(); afx_msg void OnMenuitemclear(); afx_msg void OnMenuitemload(); afx_msg void OnMenuitemsave(); afx_msg void OnBtappend(); afx_msg void OnBtdelete(); afx_msg void OnBtexit(); afx_msg void OnBtfind(); afx_msg void OnBtinsert(); afx_msg void OnBtlast(); afx_msg void OnBtnext(); afx_msg void OnBtprevious(); afx_msg void OnBttop(); //}}AFX_MSG 2、AddressBookDlg.cpp文件中: BEGIN_MESSAGE_MAP(CAddressBookDlg, CDialog) //{{AFX_MSG_MAP(CAddressBookDlg) ON_WM_SYSCOMMAND() ON_WM_PAINT() ON_WM_QUERYDRAGICON() ON_COMMAND(ID_MENUITEMEXIT, OnMenuitemexit) ON_COMMAND(ID_MENUITEMCLEAR, OnMenuitemclear) ON_COMMAND(ID_MENUITEMLOAD, OnMenuitemload) ON_COMMAND(ID_MENUITEMSAVE, OnMenuitemsave) ON_BN_CLICKED(IDC_BTAPPEND, OnBtappend) ON_BN_CLICKED(IDC_BTDELETE, OnBtdelete) ON_BN_CLICKED(IDC_BTEXIT, OnBtexit) ON_BN_CLICKED(IDC_BTFIND, OnBtfind) ON_BN_CLICKED(IDC_BTINSERT, OnBtinsert) ON_BN_CLICKED(IDC_BTLAST, OnBtlast) ON_BN_CLICKED(IDC_BTNEXT, OnBtnext) ON_BN_CLICKED(IDC_BTPREVIOUS, OnBtprevious) ON_BN_CLICKED(IDC_BTTOP, OnBttop) //}}AFX_MSG_MAP END_MESSAGE_MAP() 3、AddressBookDlg.cpp文件中: void CAddressBookDlg::OnBtappend() { // TODO: Add your control notification handler code here } void CAddressBookDlg::OnBtdelete() { // TODO: Add your control notification handler code here } void CAddressBookDlg::OnBtexit() { // TODO: Add your control notification handler code here } void CAddressBookDlg::OnBtfind() { // TODO: Add your control notification handler code here } void CAddressBookDlg::OnBtinsert() { // TODO: Add your control notification handler code here } void CAddressBookDlg::OnBtlast() { // TODO: Add your control notification handler code here } void CAddressBookDlg::OnBtnext() { // TODO: Add your control notification handler code here } void CAddressBookDlg::OnBtprevious() { // TODO: Add your control notification handler code here } void CAddressBookDlg::OnBttop() { // TODO: Add your control notification handler code here } 五、创建新增的类 1、引入双向链表——增加记录节点类 (1)ClassView——右击“AddressBook classes”——New Class…——Class type: Generic Class——Name:node——OK; (2)ClassView——分别右击“node()”和”~node()”——删除这两个函数; (3)ClassView——双击node——输入如下代码: class node { public: CString name,tel,add; int sex; node *prev,*next; node(CString n,CString t,CString a,int s) {name=n;tel=t;add=a;sex=s;prev=NULL;next=NULL;} }; 说明:name、tel、add、sex分别表示姓名、电话、地址、性别。Sex=0表示“男”,sex=1表示“女”。prev为指向前节点的指针、next为指向下一节点的指针,各个节点之间一个双向链表。node类有一个构造函数。 2、在AddressBookDlg.cpp的开始位置——定义全局变量和全局函数 (1)全局变量定义:FileView——双击AddressBokDlg.cpp——在#include…预处理命令后面加入以下语句。 #include “node.h” node *head,*curp; int pnum,tnum; 说明:AddressBookDlg对应主窗体,在其前面定义的变量就是该程序的全局变量。作用域:整个程序;初始值:0和NULL 作用:head——指针:指向链表的“头指针”,其值不为NULL curp——指针:指向链表中的当前节点 pnum——用于存储当前的节点序号 tnum——用于存储总的节点数 (2)全局函数的定义:FileView——双击AddressBokDlg.cpp——在int pnum,tnum;语句后面定义下面3个全局函数。 //定义全局函数 void PutData(CAddressBookDlg *t) { //该函数完成当前节点数据显示在窗口上 char buf[16]; t->m_name=curp->name; t->m_tel=curp->tel; t->m_add=curp->add; t->m_sex=curp->sex; sprintf(buf,\"%d/%d\ t->m_pos=CString(buf); t->UpdateData(FALSE); } void GetData(C AddressBookDlg *t) { //此函数完成把显示在窗口上的数据转入当前节点 t->UpdateData(TRUE); curp->name=t->m_name; curp->tel=t->m_tel; curp->sex=t->m_sex; curp->add=t->m_add; } void RefreshControls(C AddressBookDlg *t) { //控件刷新函数 if(curp==head) { PutData(t); t->GetDlgItem(IDC_BTLAST)->EnableWindow(FALSE); t->GetDlgItem(IDC_BTNEXT)->EnableWindow(FALSE); t->GetDlgItem(IDC_BTTOP)->EnableWindow(FALSE); t->GetDlgItem(IDC_BTPREVIOUS)->EnableWindow(FALSE); t->GetDlgItem(IDC_BTDELETE)->EnableWindow(FALSE); t->GetDlgItem(IDC_BTINSERT)->EnableWindow(FALSE); t->GetDlgItem(IDC_EDNAME)->EnableWindow(FALSE); t->GetDlgItem(IDC_EDTEL)->EnableWindow(FALSE); t->GetDlgItem(IDC_EDADD)->EnableWindow(FALSE); t->GetDlgItem(IDC_RADIOMALE)->EnableWindow(FALSE); t->GetDlgItem(IDC_RADIOFEMALE)->EnableWindow(FALSE); t->GetDlgItem(IDC_BTFIND)->EnableWindow(FALSE); return; } else { t->GetDlgItem(IDC_BTDELETE)->EnableWindow(TRUE); t->GetDlgItem(IDC_EDNAME)->EnableWindow(TRUE); t->GetDlgItem(IDC_EDTEL)->EnableWindow(TRUE); t->GetDlgItem(IDC_EDADD)->EnableWindow(TRUE); t->GetDlgItem(IDC_RADIOMALE)->EnableWindow(TRUE); t->GetDlgItem(IDC_RADIOFEMALE)->EnableWindow(TRUE); t->GetDlgItem(IDC_BTFIND)->EnableWindow(TRUE); } if(curp->next) { t->GetDlgItem(IDC_BTLAST)->EnableWindow(TRUE); t->GetDlgItem(IDC_BTNEXT)->EnableWindow(TRUE); } else { t->GetDlgItem(IDC_BTLAST)->EnableWindow(FALSE); t->GetDlgItem(IDC_BTNEXT)->EnableWindow(FALSE); } if(curp->prev!=head) { t->GetDlgItem(IDC_BTTOP)->EnableWindow(TRUE); t->GetDlgItem(IDC_BTPREVIOUS)->EnableWindow(TRUE); } else { t->GetDlgItem(IDC_BTTOP)->EnableWindow(FALSE); t->GetDlgItem(IDC_BTPREVIOUS)->EnableWindow(FALSE); } } 六、添加系统消息映射,完成一些初始化、释放内存等工作 1、查询对话框: (1)初始化查询中的对话框的姓名初始值。菜单View——Class Wizard——Message Maps标签——Class name:选择Getname——Object IDs:选择Getname——Messages:选择WM_INITDIALOG——Add Function——代码后续添加。 BOOL Getname::OnInitDialog() { CDialog::OnInitDialog(); m_getname=\"\"; UpdateData(FALSE); return TRUE; } (2)两个按钮“确定”和“取消”的消息映射 void GetName::OnBtok() { // TODO: Add your control notification handler code here UpdateData(TRUE); OnOK(); } void GetName::OnBtcancel() { // TODO: Add your control notification handler code here OnCancel(); } 2、在BOOL CAddressBookDlg::OnInitDialog()中加入如下的初始化代码。非常重要! // TODO: Add extra initialization here head=new node(\"\ //初始化时只建立一个头节点 curp=head; PutData(this); RefreshControls(this); 说明:程序开始执行后,马上执行该函数进行初始化 3、程序结束时释放链表内存。菜单View——Class Wizard——Message Maps标签——Class name:选择CAddressBookDlg——Object IDs:选择CAddressBookDlg——Messages:选择WM_DESTROY——Add Function——代码后续添加。 void CFriendsDlg::OnDestroy() { CDialog::OnDestroy(); curp=head; while(curp) //窗口消失时同时释放链表内存 { head=curp->next; delete curp; curp=head; } } 七、完成其他函数的代码——力求理解 八、构造(Build)、测试和调试应用程序! 因篇幅问题不能全部显示,请点此查看更多更全内容