谭浩强C-结构体
一、结构体的定义
1、定义形式
struct 结构名
{成员列表;}; //定义为语句,分号不能丢
2、结构类型变量的声明
(1)声明形式1
struct student
{ int number;
char name[10];
float score;
};
struct student st1,st2,st3;
(2)声明形式2
struct student
{ int number;
char name[10];
float score;
}st1,st2,st3;
(3)结构体变量的赋值
如上例:
struct student
{ int number;
char name[10];
float score;
}st1={101,"wang",87.5};
3、结构数组的定义
struct student
{ int number;
char name[10];
float score;
}stu[50]={
{101,"wang",87.5},
{102,"li",90},
...
}; //定义并初始化50个数组元素,每个元素均具有结构体student的结构。
二、结构指针
1、声明形式
struct 结构名 *指针变量名 //方法一:须在声明结构指针变量前应已说明该结构体
struct 结构名
{结构体
}*指针变量名; //方法二:与结构体变量一样
2、结构指针的赋值
struct student{
...
};
struct student *p;
struct student st1={..};
p=&st1; //取该结构体变量的首地址
3、通过结构指针变量访问结构变量成员
若st1为上述student结构体变量,p为该结构体指针变量:
使p=&st1;则可用下列方法访问st1各成员:
p->num、p->name、p->score。
或(*p).num、(*p).name ...
与st1直接引用:st1.num都可以用来表示st1的成员。
4、指向结构数组的指针
struct student
{ int num;
char name[10];
}stu[10]={...}; //声明并初始化结构数组stu
struct student *p; //声明结构指针p
p=stu; //对p赋值,指向数组stu首地址
for(;p<stu+10;p++) //stu+10表示第10个数组元素的首地址,p++表示指向下一个 数组元素
printf("%d,%s",p->num,p->name[10]); //通过指针变量引用结构数组元素的成员
三、动态存储分配
1、malloc函数
在内存动态存储区里分配一块长度为N字节的连续区域,返回值为该内存区首地址,类型说明符表示该内存区存贮的数据类型,(类型说明符*)表示将该返回值指针强制转换成该类型指针:
(类型说明符*)malloc(N)
如:
(int*)malloc(100);
(struct student*)malloc(sizeof(struct student));
2、calloc函数
(类型说明符*)calloc(n,N) //动态存储区内分配n个长度为N字节的连续区域,返回值为该区首地址,(类型说明符*)表示将该返回值指针强制转换成该类型指针;
3、free函数
free(void*ptr); //释放指针变量ptr指向的一块内存空间,使用free函数前:ptr指向的必须是事先通过malloc或calloc分配的区域。
四、链表
如何分配空间来存储学生的数据?可想到使用结构体数组,但如何确定学生的数量?新增或删减学生如何处理?引申出链表描述:
链表各元素首先均是一个结构体,各个元素称为结点,各结点对应结构体内有一成员为指针变量,指向该结点下一个结点的首地址,第0个结点称为头结点,仅存有指针变量,指向第1个结点;最后一个结点的指针变量成员指向为空(NULL)。
例:建立一个学生数据的链表结构
struct student{ char *name; struct student *pnext; //指向下一个结点的指针变量,下一结点数据类型为结构体 }; //完成链表结构声明 int i; struct student *head,*p1,*pass; for(i=0;i<N;i++) { p1=(struct student*)malloc(sizeof(struct student));//分配一块结点空间 if(i==0) {head=p1;pass=p1;} //头结点初始化 else {pass->next=p1;pass=p1;} //用pass暂存当前地址,作为中间量传递 printf("input name:\n"); scanf("%s",p1->name); //链接结点内容输入 p1->next=Null; //每次循环当前分配区为最后一个结点,使其指针指向空 } return head; //返回链表头结点