目录
序言:
结构体:
结构体数组:
结构体数组的定义和引用 :
使用关键字typedef自定义类型名:
使用typedef语句为数组类型取别名:
结构体所占内存的大小:
结构体的嵌套:
共用体类型:
共用体类型的声明:
共用体变量的定义:
共用体类型所占内存:
枚举类型:
枚举类型的声明:
枚举类型的使用:
序言:
构造数据类型:用户自己建立的数据类型(自定义数据类型)。
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 = {085422103,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; //声明时定义结构体变量s1,s2
int main()
{ //声明后定义结构体变量s3
struct pananzhongxue s3 = {085422103,19,536,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 = 085422103;
printf("%d\n", arr1[0].id);
return 0;
}
■. 注意数组类型的成员
1. 数组类型int的成员,单个数据元素可以直接进行赋值:
#include<stdio.h>
struct pananzhongxue
{
int id;
int age;
float score[3];
int gender;
char name[10];
}s1, s2;
int main()
{
s2.age[0] = 15; //数组类型单个数据元素赋值
s2.age[1] = 11;
s2.age[2] = 10;
printf("%f\t%f\t%f\n", s2.age[0], s2.age[1], s2.age[2]);
return 0;
}
2. 数组类型(如char)的成员不能直接赋值,
可以用字符串拷贝函数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;
}
结构体数组的定义和引用 :
#include<stdio.h>
struct student
{
int id;
char name[10];
};
int main()
{
struct student arr1[2]={854221,"chenchen",854222,"chenhnch"};
printf("id\tname\n);
for(int i=0;i<2;i++)
{
printf("%d\t%s\n",arr1[i].id,arr1[i].name);
}
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)
{
I a = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; // 相当于int a[10]={...};
// I换成a即可
for (int i = 0; i < 10; i++) // 可多次定义对象(数组名)
{
printf("%d\t", a[i]);
}
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; // 结构体类型student中的变量s1是结构体类型teacher中的成员
// teacher中的成员
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; //4
float score[10]; //4*10
char a; //1
double b; //8
}t1,t2;
int main()
{
printf("%d\n", sizeof(union student)); //8*5
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 day{
sun,mon,tue,wed,thu,fri,sat
}weekend,workday;
//声明了一个枚举类型,数据类型名day,
//其变量的取值范围为星期天至星期六,
//声明时定义了两个枚举类型变量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;
}
_____________#