~构造类型~

数据类型分类
1. 基本类型
整数型
短整型:short(2个字节)
整型(默认):int(4个字节)
长整型:long(8个字节)
长长整型:long long
浮点型
单精度:float(4个字节)
双精度:double(8个字节)
字符型:char(1个字节)
2. 指针类型
数据类型*: int*,char*,float*等
void*:任意数据类型的指针
3. 空类型
void:没有返回值或没有形参(不能定义变量)
4. 自定义类型/构造类型
结构体类型:struct

共用体类型(联合体):union
枚举类型:enum
注意:整数型和字符型分有符号signed和无符号unsigned,默认是有符号,有符号可以省略关键字
signed
结构体
结构体的定义
定义:自定义数据类型的一种,关键字 struct ,结构体类型的变量可以存储多个不同数据类型的
数据。
定义格式:

struct 结构体名
{
数据类型1 成员名称1;
数据类型2 成员名称2;
...
}

注意:结构体中定义的变量,我们称之为成员变量。
格式说明:
结构体名:合法的标识符,建议单词的首字母大写
数据类型n:C语言支持的所有类型
成员名称:合法的标识符,就是变量的命名标准
数据类型n 成员名称n:类似于定义变量,定义了结构体中的成员
注意:
结构体在定义的时候,成员不能赋值

举例:

struct Cat
{
int age = 5;// 错误,结构体定义的时候,成员不能赋值
double height; // 正确
}

常见的定义格式:
方式1:常规定义(命名结构体,只定义类型)---推荐

struct Student
{
int num;// 学号
char name[20];// 姓名
char sex;// 性别
int age;// 年龄
char address[100];// 家庭住址
}

方式2:定义匿名结构体(常用于作为其他结构体的成员使用)

struct Dog
{
char *name;// 姓名
int age;// 年龄
struct // 此时这个结构体就是匿名
{
int year;// 年
int month;// 月
int day;// 日
} birthday;
}

注意:定义匿名结构体的同时必须定义结构体变量,否则编译报错,结构体可以作为另一个结
构体的成员。
总结:
1. 结构体可以定义在局部位置,也可以定义在全局位置;
2. 全局位置的结构体名和局部位置的结构体名可以相同,就近原则(和普通变量的定义
同理)
结构体类型的使用:
利用结构体类型定义变量,定义数组;结构体类型的使用与基本数据类型的使用类似。
结构体变量的定义
三种形式定义结构体变量:
结构体变量也称为结构体的实力。
第一种
① 先定义结构体
② 然后使用 struct 结构体名 变量名 ;

// 先定义结构体(先定义结构体这个数据类型)
struct A
{
int a;
char b;
}
// 定义结构体变量
struct A x;
struct A y;

第二种

在定义结构体的同时,定义结构体变量;

// 定义结构体的同时定义结构变量
struct A
{
int a;
char b;
} x,y;
struct A z;

此时定义了一个结构体A,x和y是这个结构体类型的变量。
第三种:不推荐
在定义匿名结构体的同时,定义结构体变量;

struct
{
int a;
char b;
} x,y;
struct
{
int a;
char b;
} z;

此时定义了一个没有名字的结构体(称为匿名结构体);y,x是这个匿名结构体类型的变量;
匿名结构体:---弊大于利(尽量少用)
优点:少写一个结构体名称
缺点:只能使用一次;定义的结构体类型的同时就必须定义变量
应用场景:
当结构体的类型只需要使用一次,并且定义类型的同时定义变量。
作为其他结构体的成员使用。

定义结构体的同时,定义结构体变量初始化

struct Cat
{
int age;
char color[20];
} cat;

结构体成员部分初始化是,大括号不能省略。
结构体的成员,没有默认值,是不确定的数
案例:
 

/**
* 结构体变量的定义
*/
#include <stdio.h>
// 先定义结构体,再定义结构体变量
void fun1()
{
// 先定义结构体
struct A
{
int a;
char b;
};
// 再定义结构体变量
struct A x;
struct A y;
}
// 定义结构体的同时定义结构体变量
void fun2()
{
struct A
{
int a;
char b;
} x,y;
struct A z;
}
// 定义匿名结构体的同时定义结构体变量
void fun3()
{
struct
{
int a;
char b;
} x,y;
struct
{
int a;
char b;
} z;
}
int main()
{
fun1();
fun2();
fun3();
return 0;
}

结构体变量的使用
结构体变量访问结构体成员
格式 :       结构体变量名.成员名;
可以通过访问给成员赋值(存数据)
可以通过访问获取成员的值(取数据)
结构体变量未初始化,结构体的成员值随机(不确定)

结构体变量在定义时,可以初始化
建议用大括号标明数据的范围
结构体成员初始化时,可以部分初始化,部分初始化时一定要带大括号标明数据的范围
案例:

/**
* 结构体变量的初始化
*/
#include <stdio.h>
/* 全局的结构体(数据类型) */
struct Dog
{
char *name;// 姓名
int age;// 年龄
char sex;// M:公,W:母
};
/* 先定义,再初始化 */
void fun1()
{
// 定义一个结构体
// struct Dog
// {
// char *name;// 姓名
// int age;// 年龄
// char sex;// M:公,W:母
// };
// 定义结构体变量
struct Dog dog;
// 给结构体变量的成员赋值
dog.name = "旺财";
dog.age = 5;
// 访问结构体变量的成员
printf("%s,%d,%c\n",dog.name,dog.age,dog.sex);
}
/* 定义的同时初始化 */
void fun2()
{
// 定义结构体变量并初始化
struct Dog dog = {"招财",23,'M'};
// 修改成员的值
dog.name = "进宝";
// 访问结构体变量的成员
printf("%s,%d,%c\n",dog.name,dog.age,dog.sex);
}
int main()
{
fun1();
fun2();
return 0;
}

结构体数组的定义
什么时候需要结构体数组?
比如:我们需要管理一个学生对象,只需要定义一个 struct Student majie;
假如:我们需要管理多个学生对象,此时就需要一个结构体的数组 struct Student students[6
4]; 。
三种形式定义结构体数组
第一种:先定义结构体类型,然后定义结构体变量,再将变量存储到结构体数组中

// 定义一个学生类型的结构体
struct Student
{
char *name;
int age;
float scores[3];// 三门课程的成绩
};
// 定义结构体对象
struct Student zhangsan = {"张三",23,{67.5,89.0,90.0}};
struct Student lisi = {"李四",21,{77.0,80.0,85.0}};
// 定义结构化数组
struct Student students[3] = {zhangsan,lisi};

第二种:定义结构体类型,然后定义结构体数组并初始化

// 定义一个学生类型的结构体
struct Student
{
int id;
char *name;
int age;
float scores[3];// 三门课程的成绩
};
// 定义结构体数组并初始化
struct Student students[3] = {
{1,"张三",23,{67.5,89.0,90.0}},// 注意:这里赋值的顺序需要跟成员在结构体中的顺序一致
{2,"李四",21,{77.0,80.0,85.0}}
};

第三种:定义结构体类型同时定义结构体数组并初始化

// 定义一个学生类型的结构体
struct Student
{
int id;
char *name;
int age;
float scores[3];// 三门课程的成绩
} students[3] = {
{1,"张三",23,{67.5,89.0,90.0}},// 注意:这里赋值的顺序需要跟成员在结构体中的顺序一致
{2,"李四",21,{77.0,80.0,85.0}}
};

第四种:定义结构体类型同时定义结构体数组,然后通过索引给结构体成员赋值

// 定义一个学生类型的结构体
struct Student
{
int id
char *name;
int age;
float scores[3];// 三门课程的成绩
} sts[3];
sts[0].id = 1;
sts[0].name = "张三";
sts[0].age = 12;
sts[0].scores[0] = 98;

结构体类型

结构体数组

结构体指针

定义:结构体类型的指针变量指向结构体变量或者数组的起始地址。
语法:struct 结构体名 *指针变量列表;
举例:

struct Dog
{
char name[20];
int age;
};
struct Dog dog;
struct Dog *p = &dog;

结构体成员访问
结构体成员访问
结构体数组名访问结构体成员
格式:结构体数组名 -> 成员名;
结构体成员访问符
. :左侧是结构体变量(结构体对象/实例),也可以叫做结构体对象访问成员符;右侧是结
构体成员。
-> :左侧是一个指针,可也以叫结构体指针访问成员符;右侧是结构体成员。
访问结构体成员有两种类型,三种方式:
类型1:通过结构体对象访问成员
 

struct Stu
{
int id;
char name[20];
} stu;
// 访问成员
stu.name;

类型2:通过结构体指针访问成员

        1. 指针引用访问成员

struct Stu
{
int id;
char name[20];
} stu;
struct Stu *p = &stu;
// 指针引用访问成员
p -> name;

        2. 指针解引用间接访问成员

struct Stu
{
int id;
char name[20];
} stu;
struct Stu *p = &stu;
// 指针解引用间接访问成员
(*p).name;

结构体数组中元素的访问

struct Stu
{
int id;
char name[20];
float scores[3];
} stus[3] = {
{1,"张三",{86,88,56}},
{2,"李四",{75,66,78}},
{3,"王五",{70,99,90}}
};
// 取数据 --- 下标法
printf("%s,%2f\n",stus[1].name,stus[1].scores[2]);// 李四,78
// 结构体成员引用符号:-> 指针法
printf("%s,%2f\n",stus -> name,stus -> scores[2]);// 张三,56
printf("%s,%2f\n",(stus + 1)-> name,(stus + 1)-> scores[2]);// 李四,78
printf("%s,%2f\n",(*(stus + 1)).name,(*(stus + 1)).scores[2]);// 李四,78

小贴士:

结构体是自定义数据类型,它是数据类型,用法类似于基本类型的int;
结构体数组它是存放结构体对象的数组,类似于int数组存放int数据;
基本类型数组怎么用,结构体数组就怎么用--->可以遍历,可以作为形式参数,也
可以做指针等;
 

结构体类型求大小
规则:字节对齐(默认,数据在内存中存储在其类型大小的整数倍上)
1. 首先保证结构体中的成员存储在自身的对齐边界(类型大小的整数倍);
2. 在满足1的条件下,最终大小要满足 最大成员 所占存储单元的整数倍;
为什么要使用字节对齐:

节省内存,提高访问效率。
在GNU标准中,可以在定义结构体时,指定对齐规则:

__attribute__((packed)); 结构体所占内存大小是所有成员所占内存大小之和
__attribute__((aligned(n))); 设置结构体占n个字节,如果n比默认值小,n不起作用;n必须是2的次方

柔性数组:

struct st
{
...
char a[0];
}

柔性数组不占有结构体的大小。
共用体/联合体类型
定义:
使几个不同的变量占用同一段内存的结构。共用体按定义中需要存储空间最大的成员来分配存储单
元,其他成员也是用该空间,他们的首地址是相同。
定义格式:

union 共用体名称
{
数据类型 变量名;
数据类型 变量名;
...
};

共用体的定义和结构体类型类似:
1. 可以有名字,也可以匿名;
2. 共用体在定义时也可以定义共用体变量;
3. 共用体在定义时也可以初始化成员;
4. 共用体也可以作为形参和返回值类型使用;
5. 共用体也可以定义共用体数组
...
也就是说,结构体的语法,共用体都支持。
注意:
共用体弊大于利,尽量少用,一般很少用;
共用体变量在某一时刻只能存一个数据,并且也只能取出一个数。
公用题和结构体都是自定义数据类型,用法类似于基本数据类型
共用体可以是共用体的成员,也可以是结构体的成员。
结构体可以是共用体的成员,也可以是共用体的成员。

枚举类型

定义:
我们一般情况下,定义常量使用宏定义(#define 宏名称 值),宏定义非常适合没有关联关系的常
量;但是有时候我们可能需要对一组拥有关联关系的量进行定义,比如 周一~周日 、 1月~12月 等,
那么使用宏定义,就不是很清晰在,这个时候就需要使用到枚举。
枚举的存在就是将多个拥有关联关系的常量组合到一起,提高代码的可读性。
说明:
枚举类型定义了一组常量,我们在开发中直接使用这些常量。(常用)
当然枚举类型也可以类似于结构体一样定义变量等操作。(不常用)
枚举常量有默认值,从0开始依次加1;我们可以在定义时指定它的值,如果个别没有赋值,可以根
据赋值依次加1推导。
特点:
定义了一组常量,类似于定义了多个自定义常量(宏定义)
提供了代码的可读性(避免了魔术数字)
定义语法:

定义枚举类型名以后就可以定义该枚举类型的变量

enum 枚举类型名 变量表;

在定义枚举类型的同时定义该枚举类型的变量。

enum 枚举类型名{ 枚举元素列表 }变量表;

直接定义枚举类型变量。

enum { 枚举元素列表 }变量表;

typedef
说明:给类型重命名,不会影响到类型本身
作用:给已有的类型起别名
格式:

typedef 已有类型名 新别名;

使用:

// 定义结构体
struct Student
{
int id;
char *name;
char sex;
int age;
};
// 类型重命名
typedef struct Student Stu;
// 定义变量
struct Stu stu = {1,"张甜",'M',21};
// 定义结构体的同时类型重命名
typedef struct PersonInfo
{
int a;
double b;
} Per;
// 定义变量
struct Per per = {2,5};

应用场景
1. 数据类型复杂(结构体,共用体,枚举,结构体指针)时使用

2. 为了跨平台兼容性,例如:
        1. size_t:类型重命名后的数据类型, typedef unsigned long size_t;
        2. unit_16:类型重命名后数据类型

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值