用户建立自己的数据类型
9.1 定义和使用结构体变量
9.1.1 自己建立结构体类型
1.结构体:用户自己建立由不同类型数据组成的组合型的数据结构
数组:每个数据类型都是一样的
如,一个学生的学号、姓名、性别、年龄、成绩、家庭地址等项,是属于同一个学生的,因此组成一个组合数据,如student_1的变量,反映它们之间的内在联系
2.声明一个结构体类型的一般形式为:
struct Student
{ int num; char name[20]; char sex; int age; float score; char addr[30];
};
//由程序设计者指定了一个结构体类型struct Student
//它包括num,name,sex,age,score,addr等不同类型的成员
3.说明:
(1)结构体类型并非只有一种,而是可以设计出许多种结构体类型,
例如struct Teacher struct Worker struct Date等结构体类型各自包含不同的成员
(2) 成员可以属于另一个结构体类型。
struct Date { int month; int day; int year; };struct Stu { int num;char name[20];char sex;int age;struct Date birthday; char addr[30]; };
9.1.2 定义结构体类型变量
前面只是建立了一个结构体类型,它相当于一个模型,并没有定义变量,其中并无具体数据,系统对之也不分配存储单元。
- 先声明结构体类型,再定义该类型变量声明结构体类型struct Student,可以用它来定义变量
2.在声明类型的同时定义变量
struct Student
{ int num; char name[20]; char sex; int age; float score; char addr[30];
} student1,student2;
3. 不指定类型名而直接定义结构体类型变量
指定了一个无名的结构体类型 。
(1) 结构体类型与结构体变量是不同的概念。 变量可以赋值、存取或运算, 类型不能赋值、存取或运算。
9.1.3 结构体变量的初始化和引用
例9.1 把一个学生的信息(包括学号、姓名、性别、住址)放在一个结构体变量中,然后输出这个学生的信息
#include <stdio.h>
int main()
{struct Student { long int num; char name[20];char sex; char addr[20];}a={10101,"Li Lin",'M',"123 Beijing Road"}; printf("NO.:%ld\n name:%s\n sex:%c\n address:%s\n",a.num,a.name,a.sex,a.addr); return 0;
}
(附录3 ,a
#include <stdio.h>
int main()
{ struct Date { int month; int day; int year; };struct Stu { int num;char name[20];char sex;int age;struct Date birthday; char addr[30]; }a,b;
例9.2 输入两个学生的学号、姓名和成绩,输出成绩较高学生的学号、姓名和成绩
#include <stdio.h>
int main()
{ struct Student { int num;char name[20]//(数组名代表数组地址)float score;}student1,student2; scanf("%d%s%f",&student1.num,student1.name, &student1.score); //student1.name不用加&。(数组名代表数组地址);scanf(“%d%s%f”,&student2.num,student2.name, &student2.score);
printf("The higher score is:\n");if (student1.score>student2.score)printf("%d %s %6.2f\n",student1.num,student1.name, student1.score);else if (student1.score<student2.score)printf("%d %s %6.2f\n",student2.num,student2.name, student2.score);else{printf("%d %s %6.2f\n",student1.num,student1.name, student1.score);printf("%d %s %6.2f\n",student2.num,student2.name, student2.score);}return 0;
}
9.2 使用结构体数组
9.2.1定义结构体数组
例9.3 有3个候选人,每个选民只能投票选一人,要求编一个统计选票的程序,先后输入被选人的名字,最后输出各人得票结果
#include <string.h>
#include <stdio.h>
struct Person
{ char name[20]; int count;
}leader[3]={"Li",0,"Zhang",0,"Sun",0};
//全局的结构体数组(可以初始化)有 3个元素,
//每个元素都是person结构体的实例
//leader是全局变量int main()
{int i,j;//(循环变量) char leader_name[20]; for (i=1;i<=10;i++){ scanf("%s",leader_name); for(j=0;j<3;j++)//strcmp是 C 语言标准库中的字符串比较函数,//用于比较两个字符串leader_name 和 leader[j].name是否相等。//如果两个字符串完全相同,strcmp函数返回值为 0;如果不相同,则返回一个非零值。if(strcmp(leader_name, leader[j].name)==0) leader[j].count++;}for(i=0;i<3;i++)printf("%5s:%d\n",leader[i].name,leader[i].count);return 0;
}
9.3 结构体指针
9.3.1 指向结构体变量的指针
指向结构体对象的指针变量既可以指向结构体变量,也可以用来指向结构体数组中的元素。
指针变量的基类型必须与结构体变量的类型相同。例如: struct Student *pt;
例9.5 通过指向结构体变量的指针变量输出结构体变量中成员的信息。
#include <stdio.h>
#include <string.h>
int main()
{ struct Student{ long num;char name[20];char sex;float score;};struct Student stu_1//stu_1(普通变量,有内存空格); struct Student * p; p=&stu_1; //(p有首地址,指的是整个结构体变量 stu_1.num=10101; strcpy(stu_1.name,"Li Lin");//数组名不能通过“=”来赋值stu_1.sex='M'; stu_1.score=89.5;printf("No.: %ld\n",stu_1.num);//%ld长整型printf("name:%s\n",stu_1.name);printf("sex:%c\n",stu_1.sex);//等价于(*p).sexprintf("score:%5.1f\n",stu_1.score); return 0;}
说明:
为了使用方便和直观,C语言允许把(*p).num用p->num来代替,p是结构体指针
->指向运算符,第二级
如果p指向一个结构体变量stu,以下等价:
stu.成员名(如stu.num)
(*p).成员名(如(*p).num)
p->成员名(如p->num),结构体指针主要作用,创建链表
9.4 用指针处理链表
9.4.1 什么是链表(可以随时插进去,很灵活)
链表是一种常见的重要的数据结构
它是动态地进行存储分配的一种结构
链表必须利用指针变量才能实现
节点必须有数据
null是空指针
9.4.2 建立简单的静态链表
例9.8 建立一个如图所示的简单链表,它由3个学生数据的结点组成,要求输出各结点中的数据
每一个节点是结构体类型
#include <stdio.h>
struct Student
{ int num;float score;struct Student *next;//指向struct Student的指针,指向本身这种类型的指针//struct Student 代表链表的节点,next 指针使得每个 Student 结构体可以指向另一个 Student 结构体,//也就是下一个节点。通过这种方式,多个 Student 结构体可以连接起来,形成一个链表,
};int main()
{ struct Student a,b,c,////3个独立的结构体变量*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; //p指针访问链表各个节点的数据取出来 do {printf("%ld %5.1f\n",p->num,p->score);p=p->next; }while(p!=NULL); return 0;
}
9.4.3 建立动态链表
所谓建立动态链表是指在程序执行过程中从无到有地建立起一个链表,即一个一个地开辟结点和输入各结点数据,并建立起前后相链的关系。
自己定义函数,创建链表,成功,要返回值,返回首地址(一个指针),头指针(地址)指向开始的结点,
例9.9 写一函数建立一个有3名学生数据的单向动态链表。
#include <stdio.h>
#include <stdlib.h>//腾出一个12字节的空间(<stdlib.h>来支持)
#define LEN sizeof(struct Student)//LEN struct Student类型数据的长度
///#预处理命令,sizeof占多少长度,结构体占内存多少字节struct Student
{ long num; //4个字节float score; //4个struct Student *next; //4个
};
int n;
struct Student *creat(void) ////自定义函数(void)不带参
//返回一个 这个struct Student类型的 指针
{ struct Student *head,*p1,*p2; n=0;//定义了三个指向struct Student的指针head(指向链表头节点)//、p1(用于指向当前新创建的节点)、p2(用于指向链表的上一个节点)。p1=p2=( struct Student*) malloc(LEN); //开辟后返回指针,强制转变成这个 struct Student*地址scanf("%ld,%f",&p1->num,&p1->score); head=NULL;while(p1->num!=0){n=n+1;if(n==1) head=p1; //图1 else p2->next=p1;//如果不是第一个节点,将上一个节点(p2指向的节点)的next指针指向当前节点(p1指向的节点),实现节点连接。p2=p1;p1=(struct Student*)malloc(LEN); //图2,往前读scanf("%ld,%f",&p1->num,&p1->score);}p2->next=NULL;return(head);
}
int main()
{ struct Student *pt;pt=creat(); //调用creat函数创建链表,并将返回的头指针赋值给pt。printf("\n num:%ld\n score:%5.1f\n",pt->num,pt->score); return 0;
}