您的位置:首页 > 编程语言 > C语言/C++

C/C++中结构体(struct)知识点强化(二)

2010-01-21 16:10 507 查看

C/C++中结构体(struct)知识点强化(二)

出处:PConline 2005年03月07日 作者:管宁 责任编辑:xietaoming

  首先,我们写这个程序,要考虑到由于是一个链表结构,我们不可能知道它的大小到底是多大,这个问题我们可以用动态开辟堆内存来解决,因为堆内存在程序结束前始终是有效的,不受函数栈空间生命期的限制,但要注意的是我们必须有一个指针变量来存储这一链状结构的进入地址,而在函数内部来建立这一指针变量显然是不合适的,因为函数一旦退出,这个指针变量也随之失效,所以我们在程序的开始声明了一个全局指针变量。

test *head;//创建一个全局的引导进入链表的指针
  好解决了这两个问题,我们接下去思考

  有输入就必然有输出,由于输出函数和输入函数是相对独立的,为了不断测试程序的正确性好调试我们先写好输出函数和main函数捏的调用,创建函数我们先约定好名为create。

  我们先写出如下的代码:

#include <iostream>
using namespace std;

struct test
{
char name[10];
float socre;
test *next;
};

test *head;//创建一个全局的引导进入链表的指针

test *create()
{

return head;//返回链首指针
}

void showl(test *head)
{
cout<<"链首指针:"<<head<<endl;
while(head)//以内存指向为null为条件循环显示先前输入的内容
{
cout<<head->name<<"|"<<head->socre<<endl;
head=head->next;
}
}

void main()
{
showl(create());
cin.get();
cin.get();
}
  程序写到这里,基本形态已经出来,输入和调用我们已经有了。

  下面我们来解决输入问题,链表的实现我们是通过循环输入来实现的,既然是循环我们就一定得考虑终止循环的条件,避免死循环和无效循环的发生。

在create()函数内部我们先写成这样:

test *create()
{
test *ls;//节点指针
test *le;//链尾指针
ls = new test;//把ls指向动态开辟的堆内存地址
cin>>ls->name>>ls->socre;
head=NULL;//进入的时候先不设置head指针指向任何地址,因为不知道是否一上来就输入null跳出程序
le=ls;//把链尾指针设置成刚刚动态开辟的堆内存地址,用于等下设置le->next,也就是下一个节点的位置

le->next=NULL;//把链尾指针的next设置为空,因为不管如何循环总是要结束的,设置为空才能够在循环显链表的时候不至于死循环
delete ls;//当结束的时候最后一个动态开辟的内存是无效的,所以必须清除掉
return head;//返回链首指针
}
  在循环创建之前我们必须考虑一个都不输入的情况。

  程序一单进入create函数我们首先必然要创建一个节点,我们先创建一个节点指针,后把者个节点指针指向到动态开辟的test类型的动态内存地址位置上。

  所以我们有了

test *ls;
ls = new test;
  程序既然是循环输入,而结构成员test *next又是用来存储下一个接点的内存地址的,每次循环我们又要动态创建一个新的内存空间,所以我们必须要有一个指针来存储上一次循环动态开辟的内存地址,于是就有了

test *le;
  接下来在进入循环前我们要创建链表的第一个节点,第一个节点必然是在循环外创建,于是就有了

cin>>ls->name>>ls->socre;
  程序执行者的情况是位置的,所以我们必然要考虑,一上来就不想继续运行程序的情况,所以我们一开始先把head引导指针设置为不指向任何地址也就是

head=NULL;

  为了符合le也就是链尾指针的设计思路,我们在循环前一定要保存刚刚动态开辟的内存地址,好在下一次循环的时候设置上一个节点中的next成员指向,于是我们便有了:

le=ls;
  为了实现循环输入我们又了下面的代码:

while(strcmp(ls->name,"null")!=0)
{
if(head==NULL)
{
head=ls;
}
else
{
le->next=ls;
}
le=ls;
ls=new test;
cin>>ls->name>>ls->socre;
}
  程序是循环必然要有终止循环的条件,所以我们的循环条件是:

while(strcmp(ls->name,"null")!=0)
  输入的名字是null的时候就停止循环。

  为了保证第一次进入循环,也就是在循环内准备创建第二个节点前,设置引导指针的指向我们有了如下的判断代码:

if(head==NULL)
{
head=ls;
}
else
{
le->next=ls;
}
代码中的else条件是为了设置前一个节点next指向而写的,这点我们记住先看下面的代码,稍后大家回过头想就明白了
le=ls;
ls=new test;
cin>>ls->name>>ls->socre;
  le=ls;这么写就是为了保存上一次循环指针的位置而设的,正是为了上面的else代码而做的预先保留

ls=new test;
cin>>ls->name>>ls->socre;
  这两行代码的意思就是继续开辟下一个节点空间,和输入节点内容!

  循环一旦结束也就结束了程序,为了保持程序不出错,也就是最后一个节点的next成员指向为空我们有了下面的代码

le->next=NULL;

  程序的思路始终是以先开辟后判断为思路的,所以到最后一个不成立的时候总会有一个多开辟的内存空间,为了删除掉它,我们有了下面的代码

delete ls;
  程序到最后由于返回head指针

return head;
  显示链表的函数没有什么太多特别的也只需要注意下面这样就可以了!

head=head->next;
  我们之所以不用head+=1;来写就是因为链表是我们动态开辟的,而每一个节点的位置并不是相连的,next成员指针的意义也就是下一个节点的内存地址。

  到这里整个创建函数的设计思路也都说完了,笔者不一定说的很好,但基本思路是这样的,希望读者多思考,多对比,相信此教程还是对大家有帮助的,程序设计就是利用逐步思考的方式进行的,写好的代码往往直接看看不懂就是因为中间的细节并不是一次都能够想到的。

  下面我们来说一下链表节点的删除!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: