C语言学习笔记(八): 自定义数据类型
结构体变量
什么是结构体
C语言允许用户自己建立由不同类型数据组成的组合型的数据结构,它称为结构体
结构体的成员可以是任何类型的变量,如整数,字符串,浮点数,其他结构体,指针等
struct Student //struct表示建立结构体,Student为结构体类型名
{ int num; //学号为整型
char name[20]; //姓名为字符串
char sex; //性别为字符型
int age; //年龄为整型
float score; //成绩为实型
char addr[30]; //地址为字符串
}; //注意最后有一个分号
/*花括号里的子项称为结构体的成员
每个成员都是结构体的一个域
*/
与此同时,结构体的成员还可以是其他结构体里的成员
struct Date //声明一个结构体类型 struct Date
{ int month; //月
int day; //日
int year; //年
};
struct Student //声明一个结构体类型 struct Student
{ int num;
char name[20];
char sex;
int age;
struct Date birthday; //成员birthday属于struct Date类型
char addr[30];
};
定义结构体类型变量
有两种定义结构体变量的方式,如下代码所示
/*先定义结构体类型,再定义结构体变量*/
struct Student
{ int num; //学号为整型
char name[20]; //姓名为字符串
char sex; //性别为字符型
int age; //年龄为整型
float score; //成绩为实型
char addr[30]; //地址为字符串
}; //注意最后有一个分号
struct Student student1, student2; //student1和student2是结构体变量
/*同时定义结构体类型和结构体变量*/
struct Student
{ int num;
char name[20];
char sex;
int age;
float score;
char addr[30];
}student1, student2;
结构体的初始化
include <stdio.h>
int main()
{
struct Student //声明结构体类型struct Student
{
long int num; //以下4行为结构体的成员
char name[20];
char sex;
char addr[20];
}a = { 10101,"Li Lin",'M',"123 Beijing Road" }; //定义结构体变量a并初始化
struct Student* p = &a;
printf("NO.:%ld\nname:%s\nsex:%c\naddress:%s\n",p->num, a.name, a.sex, a.addr);
return 0;
}
结构体的引用
/*对结构体的成员赋值*/
student1.num=10010; //结构体变量student1中的成员num
student1.birthday.month=6; //结构体变量student1中的成员birthday中的成员month
/*结构体成员可以像普通变量进行各种运算*/
student2.score=student1.score; //赋值运算
sum=student1.score+student2.score; //加法运算
student1.age++; //自加运算
student1=student2; //假设student1和student2已定义为同类型的结构体变量
/*scanf输入给结构体变量赋值,只能一个一个来*/
scanf(″%d″,&student1.num); //输入student1.num的值
printf(″%o″,&student1); //输出结构体变量student1的起始地址
scanf(″%d,%s,%c,%d,%f,%s\n″,&student1); //这种是错误的
结构体数组
结构体数组的定义
/*同时定义结构体类型和结构体数组*/
struct Person
{ char name[20];
int count;
} leader[3]; //定义结构体数组
/*先定义结构体类型,再定义结构体数组*/
struct Person
{ char name[20];
int count;
}
struct Person leader[3]; //leader是结构体数组名
结构体数组的初始化与引用
include <stdio.h>
//先定义后初始化
struct Person
{
char name[20];
int year;
};
int main()
{
struct Person leader[3] = { {"Li",11},{"Zhang",12},{"Sun",13} };
printf("第三位同学的名字叫%s,年龄是%d岁", leader[2].name,leader[2].year); //输出了13
}
include <stdio.h>
//同时定义与初始化
struct Person
{
char name[20];
int year;
}leader[3] = { {"Li",11},{"Zhang",12},{"Sun",13} };
int main()
{
printf("第三位同学的名字叫%s,年龄是%d岁", leader[2].name, leader[2].year); //输出了13
}
结构体指针
什么是结构体指针
所谓结构体指针就是指向结构体变量的指针,一个结构体变量的起始地址就是这个结构体变量的指针。如果把一个结构体变量的起始地址存放在一个指针变量中,那么,这个指针变量就指向该结构体变量。
指向结构体变量的指针
include <stdio.h>
include <string.h>
int main()
{
struct Student //声明结构体类型struct Student
{
long num;
char name[20];
char sex;
float score;
};
struct Student stu_1; //定义struct Student类型的变量stu_1
struct Student* p; //定义指向struct Student 类型数据的指针变量p
p = &stu_1; //p指向stu_1
stu_1.num = 10101; //对结构体变量的成员赋值
strcpy_s(stu_1.name, "Li Lin"); //用字符串复制函数给stu_1.name赋值
stu_1.sex = 'M';
stu_1.score = 89.5;
printf("\nNo.:%ld\nname:%s\nsex:%c\nscore:%5.1f\n", (*p).num, p->name, (*p).sex, (*p).score); //通过结构体指针变量来引用结构体变量:(*p).num或p->num
return 0;
}
指向结构体数组的指针
include <stdio.h>
struct Student //声明结构体类型struct Student
{
int num;
char name[20];
char sex;
int age;
};
struct Student stu[3] = { {10101,"Li Lin",'M',18},{10102,"Zhang Fang",'M',19},{10104,"Wang Min",'F',20} };//定义结构体数组并初始化
int main()
{
struct Student* p = stu; //定义指向struct Student结构体变量的指针变量
int length = sizeof(stu) / sizeof(Student); // 计算结构体数组的长度
for (int i = 0; i < length; i++)
{
printf("num: %d\n", (*p).num);
printf("name: %s\n", (*p).name);
printf("sex: %c\n", (*p).sex);
printf("age: %d\n", (*p).age);
p++;
}
return 0;
}
用指针处理链表
链表的内涵
链表是一种常见的重要的数据结构。它是动态地进行存储分配的一种结构。
head是头指针变量,它里面放了个地址,指向下一个元素。
每个元素又称为结点,它包含两个部分(实际数据、下个结点的地址)。
当某元素不指向其他元素时,这该元素称为表尾,地址放着NULL
建立静态链表
include <stdio.h>
struct Student //声明结构体类型struct Student
{ int num;
float score;
struct Student*next;
};
int main()
{ struct Student a,b,c,*head,*p; //定义3个结构体变量a,b,c作为链表的结点
a.num=10101; a.score=89.5; //对结点a的num和score成员赋值
b.num=10103; b.score=90; //对结点b的num和score成员赋值
c.num=10107; c.score=85; //对结点c的num和score成员赋值
head=&a; //头指针指向结点a
a.next=&b; //a.next指向结点b
b.next=&c; //b.next指向结点c
c.next=NULL; //c结点的next成员不存放其他结点地址
p=head; //使头指针p指向头结点a
do
{ printf("%ld %5.1f\n",p->num,p->score); //输出p指向的结点的数据
p=p->next; //使p指向下一结点,即指向结点b
}while(p!=NULL); //输出完c结点后p的值为NULL,循环终止
return 0;
}
共用体类型
共用体类型的内涵
使几个不同类型的变量共享同一段内存的结构,称为 “共用体”类型的结构。
结构体变量所占内存长度是各成员占的内存长度之和。每个成员分别占有其自己的内存单元。共用体变量可以作结构体的成员,结构体变量也可以作共用体的成员
而共用体变量所占的内存长度等于最长的成员的长度。
共用体变量若其中某个成员的值被改变,那么其他成员的值也会被改变
共用体类型的定义与引用
include <stdio.h>
struct Student //声明结构体类型struct Student
{
int num;
char name[20];
char sex;
int age;
};
union Data
{
int i;
//表示不同类型的变量i,ch,f可以存放到同一段存储单元中
char ch;
}a; //在声明类型同时定义变量
int main()
{
printf("%d\n", sizeof(Data)); //输出共用体类型的大小:4
union Data a; //用共用体类型定义变量
a.i = 99; //对共同体变量初始化,只能一个一个来,不能a={1,'A',1.1}这样一次性赋完
//a.ch = 'd';
printf("%d,%c", a.i, a.ch); //输出99,c (字符c的ascii码为99)
return 0;
}
共用体类型数据的特点
同一个内存段可以用来存放几种不同类型的成员,但在每一瞬时只能存放其中一个成员,而不是同时存放几个。
共用体变量的地址和它的各成员的地址都是同一地址。
允许用共用体变量(同类型)作为函数参数
枚举类型
枚举类型是一种特殊的整型类型,允许程序员为一组整数赋予可读的名称。在C语言中,枚举类型的定义使用关键字enum
,并且枚举的每一项都有一个名字和一个对应的整数值
include <stdio.h>
int main()
{
enum Color { red, yellow, blue, white, black }; //enum 类型名:定义枚举类型
enum Color i, j,k; //定义枚举变量i,j
i = red; j = blue,k = yellow; //给枚举变量赋值,只能是上面花括号里的内容
printf("%d,%d,%d", i,j,k); //输出的是整数,输出"0,2,1"
}
include <stdio.h>
int main()
{
enum color { red, yellow = 2, blue };
printf("%d", red); //输出0
printf("%d", yellow); //输出2
printf("%d", blue); //输出3
}
typedef声明新类型名
定义新的类型名
- 先按定义变量的方法
int i
,将变量名换成类型名int count
- 在前面加typedef,如
typedef int count
- 这样就可以定义整型变量
count i = 1
定义数组变量
int a[100]
,int Num[100]
typedef int Num[100]
Num a
相当于定义了int a[100]
其他类型
/*声明新的字符指针类型*/
typedef char *Sring;
String p; //相当于char *p
/*声明新的类型名表示指向函数的指针类型*/
typedef int (*function)() //声明function为指向函数的指针类型,指向的函数为整型
function p1 //p1为function类型的指针变量
typedef struct
{ int month;
int day;
int year;
}Date; //声明了一个新类型名Date,代表结构体类型
Date birthday; //定义结构体类型变量birthday,不要写成struct Date birthday;
Date* p; //定义结构体指针变量p,指向此结构体类型数据