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苏格版每个班级的人数都不一样,我们处理数据的方法是建立一个数组,但是也存在一定的问题,我们建立一个数组的时候,只能建立最长的那个班级人数的数组,这样相对于其他班级人数少的时候,是不是对于数组来说就造成储存空间的一种浪费。那么我们能不能建立一种动态储存空间,能随班级的人数来动态分配内存,能够需要来动态建立储存单元的结构叫做链表。
如图所示,链表必须要有一个
头指针 :只用来存放地址;
表尾:存放一个数据,而且其中存放指针地址的区域存放空指针,不知想任何类型。
看这个链表,去掉一头一尾部,剩下的中间那些称之为一个又一个的节点。
看这些节点,它包括两个东西:
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; }
9.4.3 建立动态链表
/*写一个函数建立一个有三个学生数据的单向动态链表*/ #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; }