目录
序言:
构造数据类型:用户自己建立的数据类型(自定义数据类型)。
C语言中的构造数据类型有:数组类型、结构体类型、共用体类型和枚举类型。
结构体:
用户根据自己的需求建立的由不同类型数据组成的组合型的数据类型。
即,
结构体这种数据类型他能根据用户需要来更芳年的存储各种各样的信息。
■.结构体类型的声明
(1)声明时定义结构体变量
struct 结构体类型名
{
成员列表;
}结构体变量名; // 可以在声明时定义结构体变量名
// 声明时未定义变量的话,分号(;)勿漏
(2)先声明后定义结构体变量
基本格式:结构体类型名 变量名;
例如:
struct student s1;
s1.id=12345;
■.结构体成员的使用
基本格式:
结构体变量名.成员名
结构体成员引用符:
.
例如:
#include<stdio.h>
struct pananzhongxue //构造结构体,名为“pananzhongxue”
{
int id;
int age;
float zongscore;
int gender;
char name[10];
}s1 = {85422103,19,536,1,"chenchen"}, s2; //声明时定义结构体变量s1,s2,
//并对s1初始化赋值
int main()
{ //输出“pananzhongxue”结构体类型中的s1的各个数据
printf("%d\t%d\t%d\t%f\t%s\n", s1.id, s1.age, s1.gender, s1.zongscore, s1.name);
return 0;
}
说明:
(1) struct 为结构体关键字,
(2)struct pananzhongxue 为结构体类型名,
(3)id、age... 为结构体成员名,
(4)s1、s2 为结构体变量。
区分清楚:结构体类型名、结构体成员名以及结构体变量
■.结构体变量的定义:
(1)可以在声明时直接定义结构体变量;
(2)也可以先声明后定义结构体变量;(用数据类型名定义结构体变量)
#include<stdio.h>
struct pananzhongxue
{
int id;
int age;
float zongscore;
int gender;
char name[10];
}s1, s2;
int main()
{
//声明后定义结构体变量
struct pananzhongxue s3 = {85422104,19,543,1,"xiaohei"};
printf("%d\t%d\t%d\t%f\t%s\n", s3.id, s3.age, s3.gender, s3.zongscore, s3.name);
return 0;
}
结构体数组:
结构体类型的数组
■.结构体数组元素的使用:
结构体数组名[数组下标].成员变量名
例如:
#include<stdio.h>
struct student
{
int id;
int age;
int height;
int weight;
float score;
}arr1[3]; // 声明一个结构体数组arr1[3]
int main()
{
arr1[0].id = 85422103;
printf("%d\n", arr1[0].id);
return 0;
}
■.注意数组类型的成员
1. 数组类型的成员,单个数据元素可以直接进行赋值:
#include<stdio.h>
struct pananzhongxue
{
int id;
int age;
float score[3];
int gender;
char name[10];
}s1, s2;
int main()
{
s2.score[0] = 105; //数组类型单个数据元素赋值
s2.score[1] = 91;
s2.score[2] = 110;
printf("%f\t%f\t%f\n", s2.score[0], s2.score[1], s2.score[2]);
return 0;
}
2. 数组类型的成员不能直接赋值,
可以用字符串拷贝函数strcpy来完成字符数组的赋值:
#include<stdio.h>
#include<string.h> //输入字符串处理函数头文件
struct pananzhongxue
{
int id;
int age;
float score;
int gender;
char name[10];
}s1,s2;
int main()
{
strcpy(s1.name, "cc"); //用字符串拷贝函数strcpy来赋值
printf("%s\n", s1.name);
return 0;
}
■.
相同结构体类型的成员可以相互赋值:
#include<stdio.h>
#include<string.h>
struct pananzhongxue
{
int id;
int age;
float score[3];
int gender;
char name[10];
}s1,s2;
int main()
{
s2.score[0] = 105;
s2.score[1] = 91;
s2.score[2] = 110;
s1.score[0] = s2.score[2]; //进行相互赋值
s1.score[2] = s2.score[0];
s1.score[1] = s2.score[1];
printf("%f\t%f\t%f\n", s2.score[0], s2.score[1], s2.score[2]);
printf("%f\t%f\t%f\n", s1.score[0], s1.score[1], s1.score[2]);
return 0;
}
使用关键字typedef自定义类型名:
关键字typedef:用于给数据类型关键字取别名
typedef的基本格式:
typedef 数据类型名 别名;
typedef取的别名也需要遵循标识符的命名规则。
typedef可以给一个数据类型取多个别名
typedef一般使用在数据类型名比较长的情况下
例如:
#include<stdio.h>
typedef struct chenchenchenchenchen
{
int height;
int weight;
}xxx;
int main(void)
{
xxx s1;
s1.height = 172;
printf("%d\n", s1.height);
return 0;
}
使用typedef语句为数组类型取别名:
一维数组类型的定义格式:
typedef 数据类型 数组名[常量];
例如:
#include<stdio.h>
typedef struct chenchenchenchenhcne
{
int id;
char name[20];
char gender[4];
int age;
float score[3];
}CC;
typedef int I[10]; // 定义了一个数组类型I
// 元素类型为int
// 元素个数为10
int main(void)
{
// int I[10]
I a = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; // 相当于int a[10]={...};
// I换成a即可
for (int x = 0; x < 10; x++) // 可多次定义对象(数组名)
{
printf("%d\t", a[x]);
}
putchar('\n');
return 0;
}
结构体所占内存的大小:
计算结构体内存大小时要考虑其内存布局。
系统为了提高计算机访问数据的效率,
在安排结构体中的每个成员时采用内存对齐的方法。
结构体在内存中按统一单元进行存放,
每个单元的大小取决于结构体成员中最大的基本数据类型大小。
(即,在结构体中,对不同成员类型的大小,在内存中采取内存对齐的方法以提高运行效率)
例如:
#include<stdio.h>
typedef struct student
{
short id; //2
short age; //2
char name[5]; //5
int height; //4
int weight; //4
float score; //4
}xxx;
int main()
{
printf("%d\n", sizeof(xxx)); // 24
return 0;
}
内存储存如下:
补充知识点: 为什么要内存对齐?
1.为了提高代码的可移植性,和提升CPU访问内存的效率(本质:以空间换时间)。
2.不是所有的硬件平台都能访问任意地址上的数据,某些硬件平台只能在某些地址访问某些特定类型的数据,否则会抛出硬件异常,以及遇到未对齐的边界直接就不进行读取数据。
结构体的嵌套:
用一个结构体的变量作为另一个结构体的成员。
例如:
#include<stdio.h>
struct student
{
int id;
int height;
int weight;
char gender[3];
char name[10];
float score[3];
}s1,s2,s3;
struct teacher
{
int id;
int height;
int weight;
char gender[3];
char name[10];
struct student s1; // 结构体嵌套
}t1,t2,t3; // 结构体类型teacher中的成员s1是结构体类型student
// 中的变量
int main()
{
t1.s1.id = 85422103;
printf("%d\n",t1.s1.id);
return 0;
}
■.注意
一个结构体类型中可以有本身这种结构体类型的成员吗?
struct teacher
{
int id;
int height;
int weight;
char gender[3];
char name[10];
struct teacher t2; //可以吗?
};
-----会报错:不允许使用不完整的类型。
共用体类型:
用同一段内存单元存放不同类型的变量。
同一个内存单元中,它们在内存中所占字节数不同,但共用同一段内存地址。
共用体类型的声明:
一般格式:
union 共用体类型名
{
成员列表;
}共用体变量;
共用体变量的定义:
(1)声明时定义;
(2)声明后定义;
共用体类型名 变量名;
例如:
#include<stdio.h>
union student
{
int id;
float score;
char a;
double b;
}t1,t2;
int main()
{
printf("%d\n", &(t1.id)); //所有输出结果相同
printf("%d\n", &(t1.score)); //为共用内存的首地址
printf("%d\n", &(t1.a));
printf("%d\n\n", &(t1.b));
printf("%d\n", &(t1.b)); //下面也是一样的
printf("%d\n", &t1.b); //且每次运行会重新随机申请存储空间
printf("%d\n", &t1);
return 0;
}
共用体类型所占内存:
■.整个共用体类型所占内存时最大成员所占的内存空间(也存在内存补齐)
例如:
#include<stdio.h>
union student
{
int id;
float score[10];
char a;
double b;
}t1,t2;
int main()
{
printf("%d\n", sizeof(union student)); //40
return0;
}
或
#include<stdio.h>
union student
{
int id;
float score;
char a;
double b;
}t1,t2;
int main()
{
printf("%d\n", sizeof(union student)); //8
return 0;
}
■.注意:所占内存空间为最大基本数据类型的最小整数倍
例如:
#include<stdio.h>
union student
{
int id;
float score;
char a[10];
double b;
}t1,t2;
int main()
{
printf("%d\n", sizeof(union student)); //16
return0;
}
■.存储和读取数据时:
#include<stdio.h>
union student
{
int id;
float score;
char a;
double b;
}t1,t2;
int main()
{
t1.id = 0x11223344;
t1.a = 0x55;
printf("%x\n",t1.id); //11223355
printf("%x\n",t1.a); //55
return 0;
}
大端模式:
小端模式:
■.共用体变量只能给一个成员初始化赋值,
共用体同一时刻只能保存一个成员的数据(数据相应位置覆盖)
枚举类型:
枚举类型enum:将类型中所有可能的取值一一列举出来,
枚举值只能从列举出的范围内取值,
否则没有意义。
枚举类型可以初步简单理解为取值受限的整型,其值被按照整型数据来处理和运算。
如果一个变量只有几种可能的值,就可以定义为枚举类型。
枚举类型的声明:
enum 枚举类型名
{
枚举元素列表;
}枚举类型变量名;
例如:
enum weekday
{
sun,mon,tue,wed,thu,fri,sat
}weekend,workday;
//声明了一个枚举类型的变量weekday,
//其变量的取值范围为星期天至星期六,
//声明时定义了两个枚举类型变量weekend和workday。
注意:
声明的枚举类型也可以没有类型名,
但如果需要使用此枚举类型的话,就必须在声明时同时定义变量。
枚举类型的使用:
■.C语言中的枚举元素是按照常量进行处理的,所以又称为枚举常量。
不能因为它们是标识符而把它们当作变量来使用,在使用时是不能对它们赋值的。
sun=0;mon=1;//错误,不能给枚举常量赋值
■.每一个枚举元素都代表一个整数,
C语言编译器按照定义时的顺序默认它们的值为0,1,2,3,4,5,6......
workday=mon;//相当于workday=1;
枚举常量的引用和输出:
printf("%d",sun); //输出整数0
枚举变量的引用和输出:
workday=mon;
printf("%d",workday); // 输出整数1
■.我们也可以人为的指定枚举元素的数值,在声明的枚举类型时指出即可。
例如:
enum weekend{sun=7,mon=1,tue,wed,thu,fri,sat}weekend,workday;
// 星期二2,星期三3,......星期六6
■.枚举类型可以用来进行比较和判断
if(workday==mon){......};
if(workday==sat){......};
示例:
#include<stdio.h>
enum weekday{sun=7,mon=1,tue,wed,thu,fri,sat};
int main()
{
printf("%d %d %d %d %d %d %d\n", sun, mon, tue, wed, thu, fri, sat);
return 0;
}
// 输出7 1 2 3 4 5 6
简单的枚举类型应用示例:
根据你输入的数字输出对应的星期数:
#include<stdio.h>
enum weekday{sun=7,mon=1,tue,wed,thu,fri,sat}day;
int main()
{
while (1)
{
scanf("%d", &day);
switch (day)
{
case 7:
printf("你输入了周日\n");
break;
case 6:
printf("你输入了周六\n");
break;
case 5:
printf("你输入了周五\n");
break;
case 4:
printf("你输入了周四\n");
break;
case 3:
printf("你输入了周三\n");
break;
case 2:
printf("你输入了周二\n");
break;
case 1:
printf("你输入了周一\n");
break;
default:
printf("你输入了无效数字\n");
}
}
return 0;
}