chapter 9用户自己建立数据类型(中)

简介: chapter 9用户自己建立数据类型

9.3 结构体指针


每个结构体都有一个地址,定义一个指针变量,他只能储存结构体类型的地址的话,我称之为结构体指针。结构体指针可以指向结构体。


9.3.1指向结构体变量的指针


首先咱们看一个例子;


/*通过指向结构体变量的指针变量输出结构体变量中的相关信息*/
#include <stdio.h>
#include <string.h>
int main()
{
  struct student
  {
  long num;
  char name[20];
  char sex;
  float  score;
  };//定义一个结构体;
  struct student stu_1; //定义一个结构体变量
  struct student *p;//定义一个指针变量指向结构体
  p=&stu_1;
  stu_1.num=10101;
  strcpy(stu_1.name,"li lin");//字符串赋值函数;把"li lin"赋值stu.1.name;
  stu_1.sex='M';
  stu_1.score=89.5;
  printf("no.:%ld\nname:%s\nsex:%c\nscore:%5.1f\n",stu_1.num,stu_1.name,stu_1.sex,stu_1.score);
  printf("no.:%ld\nname:%s\nsex:%c\nscore:%5.1f\n",(*p).num,(*p).name,(*p).sex,(*p).score);//
  return 0;
} 
(*p).num;p是变量名字,包含地址,*p意思是指向结构体()优先级大于.num,
所以说先指向某一个结构体,然后就是找到里面对应的num;
 如果没有括号,就是.num优先于*运算符,所以显示p.num;p是变量名字;
 所以p.num没有意义;所以说必须加括号;


以下三种情况等价:

**

stu.num stu;本身相当于一个抽象的变量,所以就不代表地址的意思,直接就是数值

(*p).num;

p->num;->指向运算符。前面是地址,后面是具体那个元素;

**


9.3.2指向结构体数组的指针


#include <stdio.h>
struct student 
{
  int num;
  char name [20];
  char sex;
  int age;
};
struct student stu[3]={{10101,"lilin",'M',18},{10102,"ZHANG FANG",'M',19},{10104,"WANGMIN",'F',20}};
int main()
{
  struct student*p;
  printf("no.name                                 sex age\n");
  for(p=stu;p<stu+3;p++)
  printf("%5d %-20s %2c %4d\n",p->num,p->name,p->sex,p->age);
  return 0;
}


9.4 用指针处理链表


9.4.1 什么是链表


在前面的学习中,当我们处理数据,比如ABCD苏格版每个班级的人数都不一样,我们处理数据的方法是建立一个数组,但是也存在一定的问题,我们建立一个数组的时候,只能建立最长的那个班级人数的数组,这样相对于其他班级人数少的时候,是不是对于数组来说就造成储存空间的一种浪费。那么我们能不能建立一种动态储存空间,能随班级的人数来动态分配内存,能够需要来动态建立储存单元的结构叫做链表。

1670499401791.jpg

如图所示,链表必须要有一个

头指针 :只用来存放地址;

表尾:存放一个数据,而且其中存放指针地址的区域存放空指针,不知想任何类型。


看这个链表,去掉一头一尾部,剩下的中间那些称之为一个又一个的节点。

看这些节点,它包括两个东西:

a.用户需要用的实际数据

b.下一个节点的地址;


所以我们看一看链表有什么特点:

1.看上图,链表各节点之间的地址是可以不连续的。

2.结构体变量,用它去建立链表是最合适的。

3.在结构体中定义的某一个指针,根据定义的在指针类型,可以指向自己所在的结构体数据,也可以指向其他类型的结构体数据。

我们看一下:

struct student
{
  int num;
  float score;
  struct student *next;//定义的结构体上面两行就是所谓的实际数据,下面指针定义的就是只能只想自己的数据类型。
}


9.4.2建立简单的静态链表


我们看一个例子,建立一个静态链表:

/*建立一个简单链表,有三个同学的数据节点组成,要求输出节点的数据*/ 
#include <stdio.h>
struct student
{
   int num;
   float score;
   struct student *next;//地址指向下一个节点的关键。
} ;//建立一个结构体,可以用来充当各个节点了。
int main()
{
  struct student a,b,c,*head,*p;
   a.num=10101;a.score=89.5;
   b.num=10103;b.score=90;
   c.num=10107;c.score=85;
   head=&a;
   a.next=&b;
   b.next=&c;
   c.next=NULL;
   p=head;
   do
   {
    printf("%ld%5.1f\n",p->num,p->score);//p是地址,->只想运算符,p->意思就是指向b这个结构体了,然后·取num的数值。
    p=p->next;//p是地址,->只想运算符,p->意思就是指向b这个结构体了,然后取next值
    } while(p!=NULL);
   return 0;
 }

1670499452130.jpg

1670499460437.jpg


9.4.3 建立动态链表


1670499472516.jpg

1670499487955.jpg

/*写一个函数建立一个有三个学生数据的单向动态链表*/
#include <stdio.h>
#include <stdlib.h>
#define LEN sizeof(struct student) //测量字节
struct student
{
 long num;
 float score;
 struct student*next;
};
int n;
struct student *creat(void)
{
 struct student*head;
 struct student*p1,*p2;
 n=0;
 p1=p2=(struct student*)malloc(LEN);//建立一个动态储存区返回一个地址,这个动态储存区的长度为LEN;
 scanf("%ld,%f",&p1->num,&p1->score);
 head=NULL;
 while(p1->num!=0)
 {
  n=n+1;
  if(n==1)head=p1;
  else p2->next=p1; 
  p2=p1;
  p1=(struct student*)malloc(LEN);
  scanf("%ld,%f",&p1->num,&p1->score);
  } 
  p2->next=NULL;
  return(head);
}
int main()
{
 struct student *pt;
 pt=creat();
 printf("\nnum:%ld\nscore:%5.1f\n",pt->num,pt->score);
 return 0;
}

里面出现了n.一开始n=0,然后n=1;n=2,3,4;

n=0;还没有建立链表;

n=1;建立了一个链表节段;赋值时把p1给head,让p2等于p1;

n=2;建立了第二个链表节段;赋值时让p1等于上一个变量中的next,p2等于此时的p1;

所以n可以作为建立链数的标志。


9.4.4输出链表


首先按一个例子,编出一个输出链表的函数。

#include <stdio.h>
#include <stdlib.h>
#define LEN sizeof(struct student)//用sizeof 测量结构体的长度字节,让LEN恒等于这个字节。
struct student
{
   long num;
   float score;
   struct student *next;
};//定义一个结构体。包含两个数据,和一个指针。
int n;
void print(struct student *head)//定义一个函数。形参定义为 struct student *head .输入一个结构体变量的地址。让他传递到这个函数。
{
   struct student *p;//定义一个为结构体变量
   printf("\nnow,these.%d records are :\n",n);//输出n
   p=head;
   if(head!=NULL)
   {
    do
    {
      printf("%ld %d5.1f\n",p->num,p->score);
      p=p->next;
    }while(p!=NULL); 
   }
}
整体将这个链表输出。直到遇到NULL为止。

也就是说在print 函数里面

do
    {
      printf("%ld %d5.1f\n",p->num,p->score);
      p=p->next;
    }while(p!=NULL);


这就是输出链表的关键,用do while 循环。也可以用while 循环。这里不需要计数,只要遇到NULL就行。所以用 do-while 和 while循环是比较好的。


我们把上面的一道例题和这一道立体综合起来。

/*建立一个动态链表,然后输出*/
#include <stdio.h>
#include <stdlib.h>
#define LEN sizeof(struct student)//
struct student
{
  long num;
  float score;
  struct student*next;
};
int n;
struct student *creat(void)//建立一个动态链表
{
  struct student*head;
  struct student*p1,*p2;
  n=0;
  p1=p2=(struct student*)malloc(LEN);//建立一个动态储存区返回一个地址,这个动态储存区的长度为LEN;
  scanf("%ld,%f",&p1->num,&p1->score);
  head=NULL;
  while(p1->num!=0)
  {
  n=n+1;
  if(n==1)head=p1;
  else p2->next=p1; 
  p2=p1;
  p1=(struct student*)malloc(LEN);
  scanf("%ld,%f",&p1->num,&p1->score);
  } 
  p2->next=NULL;
  return(head);
}
void print(struct student*head)//建立一个输出链表的函数
{
  struct student *p;
  printf("\nnow,these.%d records are :\n",n);
  p=head;
  if(head!=NULL)
  {
  do
  {
    printf("%ld %5.1f\n",p->num,p->score);
    p=p->next;
  }while(p!=NULL); 
  }
}
int main()//主函数
{
  struct student *head;
  head=creat();
  print(head);
  return 0; 
}

1670499562573.jpg

相关文章
(PD)Powerdesigner在连接线上不显示关系名称
(PD)Powerdesigner在连接线上不显示关系名称
204 0
(PD)Powerdesigner在连接线上不显示关系名称
|
C语言
chapter 9用户自己建立数据类型(下)
chapter 9用户自己建立数据类型
68 0
chapter 9用户自己建立数据类型(下)
|
算法 C++ 容器
list以及使用举例--C++基础
list以及使用举例--C++基础
88 0
list以及使用举例--C++基础
|
Java 数据处理 开发者
包含问题|学习笔记
快速学习 包含问题
Go基础(复杂类型):映射
映射 映射将键映射到值。 映射的零值为 nil 。nil 映射既没有键,也不能添加键。 make 函数会返回给定类型的映射,并将其初始化备用。
811 0