? 第一章 C语言概述
? 第二章 数据类型、运算符与表达式
? 第三章 最简单的 C程序设计
? 第四章 逻辑运算和判断选取控制
? 第五章 循环控制
? 第六章 数组
? 第八章 编译预处理
? 第九章 指针
? 第十章 结构体与共用体
? 第十二章 文件的基本操作
? 第十三章 位运算
§ 10.1 结构体及其类型定义
已介绍的数据类型:简单变量、数组、指针。
例,建立学生档案
每一个学生的,学号 (int num)
姓名 (char name[20])
性别 (char sex)
年龄 (int age)
存在的问题:难以处理一些较复杂的数据结构。
成绩 (float score)
地址 (char addr[30])
C程序可将 上述数据的集合定义为一种结构体类型,
struct student
{ int num;
char name[20];
char sex;
int age;
float score;
char addr[30];
}
上述定义中,
struct ––– 关键词 (保留字 ),表示定义一种结
构体类型。
结构体定义的一般形式,
struct 结构体名
{成员表列 };
成员表列:类型标识符 成员名
以上仅说明了定义一种类型的方法,尚未定
义变量。
strudent –––结构体名
如,struct exp
{ int times;
char flag;
float meter;
}
结构体名
成员表列
§ 10.2 定义结构体变量
一、先定义结构体类型再定义结构体变量
三种方法可用来定义结构体变量,
struct student x1,x2;
则 x1,x2为 student 结构型变量,x1,x2可存
放 student类型数据。
例, struct student
{ int num;
char name[20];
char sex;
int age;
float score;
char addr[30];
}
类型标识符
例,struct student
{ int num;
char name[20];
char sex;
int age;
char addr[30];
} x1,x2;
定义形式 struct 结构体名
{成员表列 } 变量名表列;
二,在定义结构体类型的同时定义变量,
定义形式 struct
{成员表列 } 变量名表列;
不出现结构体类型名
三、直接定义结构类型变量
如, struct
{ int num
char name[20];
char sex;
int age;
char addr[30];
} x1,x2;
1,类型名与变量名是不同的概念
2,允许成员名又为另一个已定义的结构型变量
3,每一个成员地位如同该类型的变量
4,成员名与程序中的变量名可相同但意义不同
几点说明,
一个嵌套定义的例子,
struct date
{ int month;
int day;
int year;
}
struct student
{int num;
char name[20];
char sex;
int age;
struct date birthday;
char addr[30];
} x1,x2;
x1
或 x2 num name sex age
birthday
month day year addr
§ 10.3 结构体类型变量的引用
如, x1为 student型变量,则
x1.num,表示 x1的学号
x1.name,表示 x1的名字
x1.birthday.day,表示 x1的出生日
1,只能用成员,不可用结构体变量名直接运算
2,每一个分量的引用与其同类型的简单变量的引用
相同。
引用结构体变量实质上为引用其成员
用分量运算符,优先级最高
§ 10.4 结构体变量的初始化
struct student x1={8906,"Li Ming ",'M’,
25,8,3,1928,"Yu Lushan 123 "}
与其它变量的初始化完全一样,结构体变量
在定义时可初始化,
关于结构体变量的几点说明,
1,结构体变量不是一个简单变量,它的值
是由许多个基本数据组成。
2,在内存中占有一段连续的存储单元
3,占有的连续存储单元大小取决于成员的数
据类型
如,struct exp
{ int a;
float b;
char yn[8];
}
struct exp x={1234,56.7,"text"}
若 x 的起始地址为 2000,则 x 在内存中
占有的存储单元为,
共用 14个字节的连续单元
1234
56.7
t e
s t
\0
a
b
2000
2002
2006
2013
yn[8]
4,结构体定义和变量定义及初始化可二合为一,
struct exp
{ int a;
float b;
char yn[8];
} x={1234,56,7,"test"};
但不能这样写,
struct exp
{ int a=1234;
float b=56.7;
char yn[8]="test";
} x;
5,要注意结构体变量的输入 /输出,
若有 struct student h;
则,scanf("%s",&h);
printf("%s",h); 错误
原因,结构体变量中包含有多个不同类型
的数据项。
正确方法,对结构体变量各成员的值进行
输入 /输出。
如,scanf("%d%s",&h.num,h.name);
printf("%d%s",h.num,h.name);
§ 10.5 结构体数组
同结构体变量定义类似,
struct student w[3];
w[0].num,表示 w[0]的学号
w[1].name,表示 w[1]的姓名
对 w数组也可初始化,
struct student w[3]={{8901,"Li Ming ",…},{…},
{ }};
则有三个元素 w[0],w[1],w[2],每一个元素为一
个结构 student型变量。
结构体类型标识符
可省略大小说明,直接用赋初值确定其大小
struct student w[ ]={{…},{…},{…}};
struct person
{ char name[20];
int count;
} leader[3]={"Li",0,"Zhang",0," Hang ",0};
例, 有三个侯选人,每一侯选人的数据包括其姓
名和得票数,则可定义结构类型 person和结
构数组 leader
程序如下,
/*exp14_1.c*/
struct person
{ char name[20];
int count;
} leader[3]={"Li",0,"Zhang",0," Hang ",0};
main ( )
{int i,j;
char leader_name[20];
for (i=1; i<=10; i++)
{scanf ("%s",leader_name);
for (j=0; j<3; j++)
if (strcmp (leader_name,leader[j].name)= =0)
leader[j].count++;
}
printf ("\n");
for (i=0; i<3; i++)
printf("%5s, %d\n",leader[i].name,
leader[i].count);
}
Li ?
Li ?
Hang ?
Zhang ?
Zhang ?
Hang ?
Li ?
Hang ?
Zhang ?
Li ?
输入,
运行情况如下,
count name
Li
Zhang
Hang
0
0
0
Li, 4
Zhang, 3
Hang, 3
显示,
§ 10.6 结构指针
结构指针,指向结构型变量的起始地址,
一、结构指针变量
例, struct student
{
char name [10];
char sex;
int age;
float score;
char addr[20];
}x1;
则 p为结构指针变量,它可用来存放 student型变
量的地址
num
name

addr
p?
x1
令 p=&x1;
则 p为 x1的首地址,
struct student ?p;
(?p).name
(?p).score

或者用,?, 运算符,p? num,
p?name,p ?score,称 ?为指向运算符,
,?,优先级高于 ++,– –。
则,p ?num+1?(x1.num)++
++p?num ?++(x1.num)
先使用 x1.num,再加 1
先使 x1.num加 1,再
用 x1.num
访问 x1的成员,
小结,引用结构变量中的成员有三种方法,
(2) 用指针变量 (?p).成员名 (?p).num
(3) 用指向运算符 ?成员名 p ?num
(1) 结构体变量名,成员名 x1.num
注意, 指针变量 p必须是结构指针型,
且有 p=&x1;
例,请指出下列程序的错误所在,
struct person
{ char name[20];
int count;
} x1={"ZhongHua",10};
main( )
{ int *p;
p=&x1;
printf ("%s\n%d\n",(*p).name,(*p).count)
}
错误的原因,p不是结构
指针变量
可改为,struct person *p
例, struct student
{ int num;
char name[20];
char sex;
int age;
};
二、指向结构体数组的指针
与指向数组的指针一样,可用指针指向结构体
数组。
main ( )
{ struct student stu[3]={{10101,"Li Lin ",'M',?},
{…},{…}};
struct student ?p;
p=stu;
while (p<stu+3)
printf("…",p ?num,p ?name,p ?sex,p ?age);
}
内存结构如下,
注,p+1为指向
下一个元素
的首地址。
stu[0]
p+1
p+2
?
(p)
用地址传送,函数中形参用指针变
量,实参可用 地址量或指针
三、用指向结构体的指针作函数参数
例, /*---exp14_3.c---*/
#include <stdio.h>
struct person
{ char name[20];
int count;
} x[3]={{"zhao",4},{"qian",3},{"sun",6}};
void prt(struct person *pp);
main( )
{ int i;
for (i=0; i<3; i++)
prt(&x[i]);
}
void prt (struct person *pp)
{ printf("%s,%d",pp->name,pp->count);
}
运行结果,
zhao,4
qian,3
sun,6
§ 10.7 共用体类型数据
一、共用体数据类型的特点
与结构体类似之处:由不同的数据项组成一
个整体。
与结构体不同之处:占用的内存单元不同。
二、共用体类型定义
定义方式与结构体类型完全相同。
把结构体类型中的关键字 struct换成 union即可。
例, struct memb
{ float v;
int n;
char c;
} stag;
stag占内存 7个
字节的空间
union memb
{ float v;
int n;
char c;
} ustag;
utag占的内
存空间为
1001
1005
1007
v
n
c
2001
v
n c
2002
2003
2004
? 共用体类型变量每次只能存放一个成员的值。
三、共用体类型变量的引用
引用方法同结构体变量,
(共用体类型变量名 ).<成员名 >
共用体类型变量的输入输出同结构体类
型变量相同。
例, #include<stdio.h>
union memb
{ float v;
int n;
char c;
}
main( )
{ union memb utag;
utag.v=36.7
utag.c='T '
utag.n=18
printf("%5.1f\n%d\n%c\n",utag.v,utag.n,
utag.c); }
运行结果, 36.7
?13107
想一想,若改变成员的赋值顺序,
utag.v=36.7
utag.c='T '
utag.n=18
则 运行结果为, 36.5
84
T
构造类型 (数组,结构体,共用体 )的定义可以嵌套。
struct priv
{ int n;
float f;
char c;
}
union publ
{ int ns;
float fs;
struct priv mud;
} spe[5];
spe为共用体类型数组,每个数组元素所
占用的内存单元为,
2001
mud
fs
ns
2002
2003
2004
2005
2006
2007
§ 10.8 链表
1,什么是链表?
? 解决了内存分配零乱的问题
? 解决了数组存放数据的弊端
是用指针变量将非连续的数据块连成一
个整体的一种数据结构。
一种动态分配的数据结构。
例如,
Head
Head,称为表头,仅存放一个地址,无数据。
数据 D
Null
数据 C 数据 B 数据 A
数据
指针
,为数据块,又称为链表的结点,由两部分
组成,数据和指针。
数据,该结点的具体数据
指针,下一个结点的地址
实现方法,
2,用指向该种类型的结构指针作为表头;
3,每一个结点中包含同种类型的指针变
量用以存放下一个结点的地址。
1,用结构型变量表示每一个结点;
内存分配函数,在动态区中分配一个长度为
size的连续空间,分配成功,返回一个指向该空间
首地址的指针,未成功,返回值= 0,
实现过程中用到的三个函数 (由系统提供 )
? malloc(size)
ptr为指针变量,该函数释放最近一次调用 malloc
或 calloc分配且由 ptr指向的内存空间。
原 C标准,malloc返回一个指向 char型数据的指针。
新的 C标准:为 void ?类型,可通过强制类型转换。
? free(ptr)
struct student
{ long num;
float score;
struct student ?next;
};
同时定义三个指向这种类型的指针变量 head,p1,p2,
2,建立链表
例, 写一个函数,建立 5名学生数据的单向链表,
每一个学生的数据块 (结点 )定义如下,
一开始 head?null
约定:当输入学号 =0时,结束,返回表头
#define NULL 0
#define LEN sizeof(struct student)
struct student
{long num;
float score;
struet student ?next;
};
int n;
p1,新分配的结点地址
p2,已分配的最后一个结点地址
struct student ?creat( )
{ struct student ?head,?p1,?p2;
n=0;
p1=p2=(struct student ?) malloc(LEN);
scanf("%d,%f",&p1?num,&p1?score);
head=NULL;
while (p1?num!=0)
{ n+ +;
if(n= =1) head=p1;
else p2?next = p1;
p2=p1;
p1=(struct student ?) malloc(LEN);
scanf("%ld,%f",&p1?num,&p2?score);
}
p2?next=NULL;
return(head);
}
void print (head)
struet student ?head;
{ struet student ?p;
p=head;
if (p=NULL) return;
do
{ printf("%ld %5.1f \n",p?num,p?score);
3,输出链表
该问题比较容易解决。
p=p?next;
} while (p!=NULL);
}
一般给出某一条件,当某一条件成立时,则删除
该结点,
? 当第一个结点被删除时,修改表头
? 当最后一个结点不满足条件时,返回。
struct student ?del(head,num)
struct student ?head;
long num;
{ struct student ?p1,?p2;
4,删除一个结点
? 表为空时,无任何删除
if (head= =NULL) { printf("\n list null!=\n");
return (head);
}
p1=head;
while (num!=p1?num &&p1?next!=NULL)
{ p2=p1; p1=p1?next;}
if (num= =p1?num)
{if (p1= =head) head=p1?next;
else p2?next=p1?next;
printf ("delete,%ld \n",num);
n – – ;
}
else printf ("%ld not been found!\n",num);
return;
}
一般情况:链表中结点的关键数据已排好序,
待插入结点的关键数据与链表中的关键数据一一比
较,插入适当的位置。
方法:设链表中按 num已排序好
struct studetn ?insert (head,stud)
struct student ?head,?stud;
{ struct student ?p0,?p1,?p2;
p1=head;
5,对链表的插入操作
p0=stud;
if (head= =NULL)
{ head=p0; p0?next=NULL;}
else
{while((p0?num>p1?num)&&(p1?next!=NULL))
{p2=p1; p1=p1?next;}
if (p0?num<=p1?num)
{if (head= =p1) head=p0;
else { p2?next =p0;
? p0?next=p1;
else { p1?next=p0; p0?next=NULL; }}
n+ +;
return (head);
}
将以上函数集中,由 main( )函数调用,可建
立一个处理链表结构的程序。
main 函数如下,
main( )
{struct student * head,*stu;
long del_num;
printf("input records,\n ");
head=creat( );
print (head);
printf(" \ninput the deleted number,");
scanf("%ld ",&del_num);
while (del_num!=0)
{head=del(head,del_num);
print(head);
printf("input the deleted number,");
scanf("%ld ",&del_num);}
prinft("\ninput the inserted record,");
stu=(struct student * ) malloc (LEN);
scanf("%ld,%f ",&stu- >num,&stu- >score);
while (stu- >num!=0)
{head=insert(head,stu);
print ("input the inserted record,");
stu=(struct student * ) malloc(LEN);
scanf("%ld,%f ",&stu- >num,&stu- >score);
}
} 运行情况如下,
input records,
98101,99 ?
89103,87 ?
89105,77 ?
0,0 ?
Now,These 3 records are,
89101 99.0
89103 87.0
89105 77.0
input the deleted number,98103 ?
delete,89103
Now,These 2 records are,
89101 99.0
89105 77.0
input the deleted number,98105 ?
delete,89105
Now,These 1 records are,
89101 99.0
input the deleted number,0
input the inserted record,89104,87 ?
Now,These 2 records are,
89101 99.0
89104 87.0
input the inserted record,89106,65 ?
Now,These 3 records are,
89101 99.0
89104 87.0
89106 65.0
input the inserted record,0,0?