注:本文是对苏小红版c语言程序设计第12章的笔记
- 结构体的定义
结构体的声明(主要目的:用已有的数据类型定义一个新的数据类型):
struct 结构体名//结构体名成为结构体标签
{
数据类型 成员1的名字;
数据类型 成员2的名字;
...
数据类型 成员n的名字;//构成结构体的变量称为结构体成员
}
e.g.:
struct student
{
char[10] name;
int age;
char gender;
};
注意,结构体模板只是声明了一种数据类型,并未声明结构体类型的变量
- 结构体变量的定义:
方法一:
struct student
{
char[10] name;
int age;
char gender;
};
struct student stu1;
方法二:
struct student//此时结构体标记可以不填
{
char[10] name;
int age;
char gender;
}stu1;
- 用typedef定义数据类型
e.g.:
typedef struct student STUDENT;
或
typedef struct student
{
char[10] name;
int age;
char gender;
}STUDENT;
则 struct student sut1; 和 STUDENT stu1等价
- 访问结构体的成员必须使用成员选择运算符
结构体变量名.成员名
e.g.:stu1.name
- 在函数体外部声明的结构体类型可为所有函数使用
在函数体内声明的结构体类型只能在本函数体内使用 - 结构体变量的地址是结构体变量所占内存空间的首地址,而结构体成员的地址值与结构体成员在结构体中所处的位置及该成员所占内存的字节数相关
- 结构体类型所占内存的字节数并非所有成员所占内存字节数的总和(存在补位)(机器相关)
- 结构体数组的初始化
e.g.:
STUDENT [3] = {{"Amy", 19, 'F'}
{"Tom", 18, 'M'}
{"Cindy", 18, 'F'}
}
- 结构体指针
STUDENT*pt = &stu1
指向运算符:指向结构体的指针变量名 -> 成员名
e.g.:pt -> name = "Amy"
与(*pt).name = "Amy"
等价(但后者不常用) - 向函数传递结构体:
向函数传递结构体的单个成员(不常用)或结构体的完整结构(时空开销大):在函数内对形参结构体成员值的修改不会影响相应是惨结构体成员的值
用结构体指针或结构体数组作函数参数(效率更高):函数内部对形参结构体成员值的修改影响实参结构体成员的值 - 共用体:声明方式与结构体类似,只是将关键字换为union
- 共用体类型所占的内存空间的大小取决于其成员中占内存空间最多的那个成员变量。
共用体采用覆盖技术来实现内存的共用,只能对一个成员进行初始化(每一瞬时起作用的成员就是最后一次被赋值的成员)
e.g.:
#include <stdio.h>
typedef union student{
int age;
int number;
char name[10];
char gender;
}STUDENT;
int main(){
STUDENT stu1;
stu1.gender = 'F';
printf("%c", stu1.gender);
printf("%d", stu1.age);
printf("%d", stu1.number);
puts(stu1.name);
return 0;
}
输出结果为:F7070F(共用体的值相同)
- 枚举类型
定义:
enum response{yes, no};//response成为枚举标签
enum response answer;
也可以写成
enum response{yes, no} answer;//枚举标签response可以省略
c语言允许在枚举类型定义是明确地制定每一个枚举常量的值,如:
enum resonse{yes = 1, no = -1};
enum week{Monday = 1, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday};
注意,枚举标签后面花括号内的标识符代表枚举类型的可能取值,其值时整型常数,不是字符串。
- 节点:
数据域:存储数据
指针域:和节点类型一致的指针变量 - 链表:
一系列节点
每个节点至少包括:一条数据,一个该节点类型的指针(指向下一个节点)
头指针:指向第一个节点的指针
尾节点:节点指针指向空 - 动态链表的生成:
用malloc动态申请内存
头节点指向第一个节点
prePt永远指向当前的尾节点
e.g.;
#include <stdio.h>
#include <stdlib.h>
typedef struct student {
int age;
int number;
struct student*next;
}STUDENT;
STUDENT* Build(int n);
int main(){
int n;
STUDENT *head;
scanf("%d", &n);
head = Build(n);
...
return 0;
}
STUDENT* Build(int n){
STUDENT *Pt, *prePt, *head;
Pt = (STUDENT*)malloc(sizeof(STUDENT));//创建一个节点
if(Pt != NULL){
head -> next = Pt;//头指针指向首节点
scanf("%d %d", &(*Pt).age, &(*Pt).number);
prePt = Pt;//尾指针移动到尾节点
}else{printf("error");}
for(int i = 1; i < n; i ++){
Pt = (STUDENT*)malloc(sizeof(STUDENT));//创建下一个节点
if(Pt != NULL){
prePt -> next = Pt;//上一个节点的next指向本节点
scanf("%d %d", &(*Pt).age, &(*Pt).number);
prePt = Pt;//尾指针移动到尾节点
}else{printf("error");}
}
prePt -> next = NULL;//尾指针指向NULL
return head;
}
- 查找节点
pr存储当前节点
e.g.:
STUDENT* FindLast( STUDENT *head){//查找尾节点
STUDENT * Pr = head;//找到头节点
while(Pr -> next != NULL){//如果下一个节点的地址不是NULL(即本节点不是尾节点)
Pr = Pr->next;//指向下一个节点
}
return Pr;
}
STUDENT* Findn(STUDENT *head, int n){//查找第n个节点
STUDENT *Pt = head;//找到头节点
int i = 0;//初始化计数变量
while(i != n && Pt-> next != NULL){//不是第n个节点且未到尾节点
Pt = Pt -> next;//下一个
}
return Pt;//返回所求或NULL
}
- 插入节点
STUDENT*InserttoTail(STUDENT*head, STUDENT *New){//在尾部插入节点
STUDENT* Pt;
Pt = FindLast(head);//找到尾部
Pt -> next = New;//将尾部的next指向新节点
New -> next = NULL;//将新节点的next指向NULL
return head;//返回头节点
}
STUDENT* Insert(STUDENT* head, STUDENT* New, int n){//在第n个节点后插入节点
STUDENT* Pt = Findn(head, n);//找到需要插入的位置
if(Pt != NULL){//判断位置是否存在
New->next = Pt -> next;//将要插入的节点的next指向下一节点(同时也是Pt的下一节点)
Pt -> next = New;//(将Pt的下一节点指向要插入的节点)
//注意,以上两步顺序不能交换
}else{printf("error!");}
return head;
}