第三十讲 正确的List指针版.docx
- 文档编号:3045258
- 上传时间:2022-11-17
- 格式:DOCX
- 页数:8
- 大小:18.18KB
第三十讲 正确的List指针版.docx
《第三十讲 正确的List指针版.docx》由会员分享,可在线阅读,更多相关《第三十讲 正确的List指针版.docx(8页珍藏版)》请在冰豆网上搜索。
第三十讲正确的List指针版
第三十讲正确的List(指针版)
昨天我们完成了一个数组版的List,但是因为数组的限制,导致那个实现不能收放自如,为了解决这个问题,我们引入指针版本的List,我们还是先来看看接口:
-----------------------------------------
//my_list.h
#ifndef_MY_LIST_H_
#define_MY_LIST_H_typedefstructTelPhone{
charName[20];
charTelNumber[20];
}iTem;/*
typedefstructnode{
iTemitem;
node*next;
}Node;*/structlist{
iTemitem;
list*next;
};typedeflist*List;voidInitializeList(List*plist);
boolListIsEmpty(constList*plist);
boolListisFull(constList*plist);
unsignedintListItemCount(constList*plist);
boolAddItem(iTemitem,List*plist);
voidShowListItem(constList*plist);
voidFreetheList(List*plist);#endif
---------------------------------------
大家应该注意到了,接口还是我们熟悉的接口,我们只是稍微把声明新类型的时候稍作了下修改,所以对于这个接口,我们就不多说,如果还有不了解的可以回头去看看第二十七讲我们关于接口的声明的那一章,不过虽然说没啥好说,有一点还是值得给大家提一提:
-------------------------------------typedeflist*List;--------------------------------------大家可能会觉得奇怪,为什么会是这样的呢?
如果这样取个外号,那么我们下面的List*想要表达的岂不是list**了吗?
是啊,我们要的就是这种效果,指针的指针,指针的指针很多时候又可以用来表示二维数组:
-------------------------------------inta[n][m];//二维数组int**a;//指针的指针---------------------------------------上面这两种声明方式在特定的情况下是可以相互表示。
如果说大家能够很好的理解这个,那么对于我们的List*是不是也很好的理解呢?
List*plist等价于list**plist,可以这么来理解,plist是一个指向list指针的指针,既是*plist的指针,而*plist是指向list的指针,就是我们需要的指针,这样声明的好处是我们很容让*plist成为一个空壳,也就是好初始化。
说到这里,有人会问,既然是一个指向指针的指针,我们可不可以这么来声明呢:
----------------------------------typedefstructTelPhone{
charName[20];
charTelNumber[20];
}iTem;typedefstructnode{
iTemitem;
node*next;
}Node;structlist{
Node**head;
list*next;
};-----------------------------------------这样我们同样可以用下面的方式去初始化:
-------------------------------------------*(plist->head)=NULL;-------------------------------------------这看上去似乎是没错的,而且还可以瞒天过海,当然瞒的是编译器,所以如果这样写,编译不报错,但是运行时报错了,这是为什么呢?
这个问题大概只有大家学完C++的动态类型识别的时候才会得到答案,不过这可能会是很久以后的事。
现在我们回到正题上来,既然我们不能这样写,那么我们还是规规矩矩的这样初始化:
----------------------------------*plist=NULL;----------------------------------那么*plist表示什么呢?
我们只知道他是一个指向list的指针,里面包含了我们需要iTem和next,但是我们可能有些朋友并不知道他实际上就我们要实现的list的首地址,所以这就是指针的方便之处,我们得到了一块内存的指针便得到了这块内存的起始处,这个地址对我们来说极为重要,当然不只是我们,是所有想要使用指针的程序员来说都很重要。
该说的理论大概都说了,如果还有不懂还有懵懂的,可以看下我们的接口的具体实现,如果发现确实还不懂的话可以直接提问,我想今天这是我们C语言的最后一讲了,接下来我们该说说C++或是win32编程的知识了。
--------------------------------------//my_list.c
#include
#include
#include'my_list.h'//全局函数,把元素添加进列表
staticvoidCopyToNode(list*plist,iTemitem)
{
plist->item=item;
}//初始化
voidInitializeList(List*plist)
{
*plist=NULL;
}
//确认列表是否为空
boolListIsEmpty(constList*plist)
{
if(*plist==NULL)
returntrue;
returnfalse;
}
//确认列表是否已满
boolListisFull(constList*plist)
{
plist=(List*)malloc(sizeof(List));
if(plist==NULL)
returntrue;
else
returnfalse;
}
//返回元素个数
unsignedintListItemCount(constList*plist)
{
unsignedintcount=0;
list*pNode=*plist;
while(pNode!
=NULL)
{
count++;
pNode=pNode->next;
}
returncount;
}
//添加元素,由于我们实现的是单向链表,所以使用从尾部添加
boolAddItem(iTemitem,List*plist)
{
list*pNew;
list*pNode=*plist;
pNew=(list*)malloc(sizeof(list));
if(pNew==NULL)
returnfalse;
CopyToNode(pNew,item);
pNew->next=NULL;
if(pNode==NULL)
{
*plist=pNew;
}
else
{
while(pNode->next!
=NULL)
{
pNode=pNode->next;
}
pNode->next=pNew;
}
returntrue;
}//显示列表中的元素
voidShowListItem(constList*plist)
{
list*pNode=*plist;
while(pNode!
=NULL)
{
printf('%-10s:
%s\n',
pNode->item.Name,pNode->item.TelNumber);
pNode=pNode->next;
}
}//释放内存voidFreetheList(List*plist)
{
list*pNode=*plist,*pSave;
while(pNode!
=NULL)
{
pSave=pNode->next;
free(pNode);
pNode=pSave;
}
}
----------------------------------------------------接口的实现和我们有问题的实现看上去差不多,大家可以尝试回头去看看第二十八讲里面的实现,再来对比一下我们今天的实现,看看问题出在那里,我们在二十八讲里面是怎么瞒过大家双眼的,如果大家能够把这个地雷挖出来,C语言也算差不多了,至少在指针一块有所理解了。
下面我们还是用同一个驱动函数来测试:
----------------------------------------------
//ListTest.c
#include
#include
#include'my_list.h'intmain()
{
ListBookPhone;
iTemTempPhone;
unsignedintcount;
//使用初始化接口
InitializeList(&BookPhone);
if(!
ListIsEmpty(&BookPhone))
exit
(1);
printf('请输入联系人的姓名:
\n');
while(gets_s(TempPhone.Name)!
=NULL&&TempPhone.Name[0]!
='\0')
{
printf('请输入联系人的电话号码:
\n');
gets_s(TempPhone.TelNumber);
if(ListisFull(&BookPhone))
{
printf('内存已满,请退出!
');
exit
(1);
}
//使用添加元素接口
if(!
AddItem(TempPhone,&BookPhone))
{
printf('联系人添加失败!
!
!
');
break;
}
while(getchar()!
='\n')
continue;
printf('若还要储存,请输入下一个联系人(空行退出):
\n');
}
//接下来我们该显示我们通信录里面的联系人信息了
//使用判断状态接口
if(ListIsEmpty(&BookPhone))
printf('通信录没有数据!
!
!
');
else
{
printf('通信录:
\n');
ShowListItem(&BookPhone);
}
//使用联系人数量接口
count=ListItemCount(&BookPhone);
printf('联系人数目:
%d\n',count);
//释放内存
FreetheList(&BookPhone);
return0;
}
-------------------------------------------------现在我们来思考这次实践的问题,在这次实践中,我们虽然反转纠结多次,但是我们却没有修改过驱动函数(也就是mian),而且接口我们也没有修改,我们所动到的知识类型的声明和接口的实现,而我们的mian函数
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 第三十讲 正确的List指针版 第三十 正确 List 指针
![提示](https://static.bdocx.com/images/bang_tan.gif)