文章目录
9.1 结构体变量定义、引用、初始化
9.1.1 结构体概述
类型回顾: int float double char int a[10] float b[100]
结构体概述:
结构体也是一种数据类型,被叫做结构体类型
结构体: 将多种不同类型的数据组到一起。目的是为了表达更丰富的信息。类似于SQL语言中的“记录”。
形式:
#include "stdio.h"
int main(){
struct student
{
int num; //学号
char name[100]; //姓名
int sex; //性别, 0->女, 1->男
int age; //年龄
char address[100]; //地址
};
}
总结:
结构体类型 定义的一般形式
struct 结构体名
{
//成员列表(可以有多个) 各个成员之间都带一个分号;
}; // 不能忘记这个分号;
9.1.2 定义结构体类型变量的方法
二: 定义结构体类型变量的方法
需要将结构体名看成一个类型名就行了,
总共有三种写法
1. 普通写法
struct 结构体名 变量名列表;
例如:
struct student s1,s2; //定义两个结构体类型变量
2. 定义结构类型的时候顺便定义了变量。变量位于} 之后 ; 之前多个变量之间使用 , 分割
struct 结构体名
{
//成员列表
**}变量名列表;**
#include "stdio.h"
int main(){
struct student
{
int num; //学号
char name[100]; //姓名
int sex; //性别, 0->女, 1->男
int age; //年龄
char address[100]; //地址
**}s1,s2;**
}
1. 直接定义结构类型变量,连结构体名都省略了
struct
{
//成员列表
**} 变量名列表;**
说明:
- 使用结构体,我们一般要先定义一个结构体类型,然后定义某些变量为该类型的变量。
- 结构体内可以套结构体
struct date
{
int month;
int day;
int year;
};
struct student
{
int num; //学号
char name[100]; //姓名
int sex; //性别, 0->女, 1->男
int age; //年龄
char address[100]; //地址
**struct date birthday; //生日,结构体类型变量**
};
int main()
{
struct student s1,s2;
}
- 结构体内的成员变量,可以与程序中的变量名相同,彼此间不影响
9.1.3 结构体类型变量的引用
三: 结构体类型变量的引用
- 不能将结构体变量作为一个整体进行引用,比如s1,s2都是结构体变量,但不能拿过来直接用,只能对结构体变量中的各个成员分别引用,
引用方法:
**// 结构体变量名.成员名**
**s1.num = 1; //将1赋值给s1变量中的成员num; 这个 . 叫结构成员运算符
//该 . 运算符的优先级跟()是同级别 还有 ->**
**所以可将s1.num当成一个整体来看待**
如果成员本身又属于一个结构体类型,则要用若干个成员运算符,一级一级的找到最低一级成员,只能对最低级别成员进行赋值或者存取。
#include "stdio.h"
struct date {
int month;
int day;
int year;
};
struct student //定义一个结构体类型
{
int num; //学号
char name[100]; //姓名
int sex; //
int age; //年龄
char address[100]; //地址
struct date birthday;
// }s1,s2;
};
int main() {
int num; //这个名字和结构体变量的名字相同,但互不影响.
struct student s1,s2;
s1.num = 001; //将001赋值为s1结构体变量中的成员num.
//
**s1.birthday.day = 1; //如果成员本身又属于一个结构体类型,则要用若干个成员运算符,一级一级的找到最低一级成员,只能对最低级别成员进行赋值或者存取。**
return 0;
}
成员变量
//成员变量,可以像普通变量一样进行各种运算
s1.age = 19;
s2.age = s1.age;
int AgeSum = s1.age + s2.age;
s1.age++; //年龄自加1,因为.的优先级最高,所以s1.age是个整体
9.1.4 结构体变量的初始化
// 成员变量也是有地址的.
//结构体名不可以有地址
// s1++ s1.birthday++ 这都是错的
int *p = &s1.num;
printf("%d",*p); //也可以使用指针变量来取得其地址
//结构体变量的初始化,定义时初始化
struct student s3 = {1003,"网速",1,19,"浦东",10,14,2018};
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Aw4VI4cA-1667044997212)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/3520ce3c-9115-41d9-abb7-fcc7d3c06369/Untitled.png)]
9.2 结构体数组、结构体指针
9.2.1结构体数组
如何定义结构体数组
a. 单独写成一行定义
struct studeng stu[3]; //可以用的下标 0-2
b. 定义结构的时候顺便定义结构体数组
struct student //定义一个结构体类型
{
int num; //学号
char name[100]; //姓名
int sex; //
int age; //年龄
char address[100]; //地址
struct date birthday;
}stu[3];
c. 定义结构体数组的时候还可以同时进行初始化
一般形式:
struct student stu[] = { {…},{…},{…}};
struct student stu[3] = { //stu包含的元素程序自己会判断出来,所以可以写成stu[]
{2019250116,"zhangsan",1,18,"2401",12,30,2000},
{2019250119,"振华",0,22,"小区2401",11,11,1999},
{2019250118,"郭襄",0,20,"平凉",9,23,2001}
};
printf("stu[%d]",stu[1].age);
9.2.2 结构体指针
- 就是结构体变量的指针,这个指针肯定是指向该结构体变量所占据的内存段的起始地址
- 结构体变量指针,也可以指向结构体数组中的元素。因为结构体数组中的每个元素就相当于一个结构体变量
#include "stdio.h"
#include "string.h"
struct date {
int month;
int day;
int year;
};
struct student //定义一个结构体类型
{
int num; //学号
char name[100]; //姓名
int sex; //
int age; //年龄
char address[100]; //地址
struct date birthday;
};//stu[3];
int main() {
**//结构体指针
//就是结构体变量的指针,这个指针肯定是指向该结构体变量所占据的内存段的起始地址
//结构体变量指针,也可以指向结构体数组中的元素。因为结构体数组中的每个元素就相当于一个结构体变量
struct student stu{}; //定义一个结构体变量,
struct student *ps; //定义结构体变量的指针
ps = &stu;
strcpy(stu.name,"小虎");
stu.age = 18;
//ps已经指向了stu,stu里面的内容若改变了,就等于ps所指向的内容改变了。
//如何通过结构体变量的指针来访问结构体变量的成员呢?两种方法:
//1.
(*ps).age=29; //* 与 . 的运算等级不一样, .是最高的,所以这里要用 (*ps).age
ps -> num = 2019250119;
//2.
ps -> sex = 1; //其中 -> 叫指向结构体成员运算符 .
printf("name=%s\n",ps->name);
printf("age=%d\n",ps->age);
printf("num=%d\n",stu.num);
printf("sex=%d\n",stu.sex);
return 0;
}**
#include "stdio.h"
#include "string.h"
struct date {
int month;
int day;
int year;
};
struct student //定义一个结构体类型
{
int num; //学号
char name[100]; //姓名
int sex; //
int age; //年龄
char address[100]; //地址
struct date birthday;
};//stu[3];
int main() {
struct student stu[3] = { //stu包含的元素程序自己会判断出来,所以可以写成stu[]
{2019250116,"zhangsan",1,18,"2401",12,30,2000},
{2019250119,"振华",0,22,"小区2401",11,11,1999},
{2019250118,"郭襄",0,20,"平凉",9,23,2001}
};
printf("stu[%d]",stu[1].age);
**//演示指向结构体数组的指针**
**struct student *ps;
ps = stu; //数组名代表数组首地址。
int i; //随时使用随时定义
for(i=0;i<3;i++){
printf("num=%d\n",ps->num);
printf("name=%s\n",ps->name);
printf("age=%d\n",ps->age);
ps++; //ps指向了下一个数组元素的开始地址
printf("-----------------\n");
}
int ILen = sizeof(struct student);
printf("%d\n",ILen);**
#include "stdio.h"
#include "string.h"
struct date {
int month;
int day;
int year;
};
struct student //定义一个结构体类型
{
int num; //学号
char name[100]; //姓名
int sex; //
int age; //年龄
char address[100]; //地址
struct date birthday;
};//stu[3];
int main() {
struct student stu[3] = { //stu包含的元素程序自己会判断出来,所以可以写成stu[]
{2019250116,"zhangsan",1,18,"2401",12,30,2000},
{2019250119,"振华",0,22,"小区2401",11,11,1999},
{2019250118,"郭襄",0,20,"平凉",9,23,2001}
};
printf("stu[%d]",stu[1].age);
**//演示指向结构体数组的指针
struct student *ps;
ps = stu; //数组名代表数组首地址。
(++ps)->num; //值为2019250119,指针指向了2019250119
(ps++)->num; //值为2019250116,指针指向了2019250119
}**
(2)不能让ps指向某一个数组元素中的成员。
错误写法
ps =&stu[0].num; //可以强制转,但没有意思
ps = &stu[0]; //这是对的
9.2.3 用指向结构体的指针做函数参数
#include "stdio.h"
#include "string.h"
struct date {
int month;
int day;
int year;
};
struct student //定义一个结构体类型
{
int num; //学号
char name[100]; //姓名
int sex; //
int age; //年龄
char address[100]; //地址
struct date birthday;
};//stu[3];
int main() {
struct student stu[3] = { //stu包含的元素程序自己会判断出来,所以可以写成stu[]
{2019250116,"zhangsan",1,18,"2401",12,30,2000},
{2019250119,"振华",0,22,"小区2401",11,11,1999},
{2019250118,"郭襄",0,20,"平凉",9,23,2001}
};
printf("stu[%d]",stu[1].age);
**//演示指向结构体数组的指针
struct student *ps;
ps = stu; //数组名代表数组首地址。
(++ps)->num; //值为2019250119,指针指向了2019250119
(ps++)->num; //值为2019250116,指针指向了2019250119
}**
(2)不能让ps指向某一个数组元素中的成员。
错误写法
ps =&stu[0].num; //可以强制转,但灭有意思
ps = &stu[0]; //这是对的
9.3 共用体、枚举类型、typedef
9.3.1共用体(联合)
将几种不同类型的变量存放到同一段内存单元(同一个内存地址开始的单元中)。
几个变量共同占同一段内存的结构,叫共用体
union 共用体名
{
//成员列表
} 变量列表;
union myuni
{
int carnum; //车编号,
char cartype; //车的类型
char cname[60]; //轿车名
}a,b,c;
结构体与共用体的区别
结构体:
占用的内存是其成员所占内存之和。 如果定义的结构体不能被4整除或被某个数整除的话,系统会多分配几个字节以保证字节对齐
保证字节对齐的目的是为了效率问题。
#include "stdio.h"
#include "string.h"
struct student //结构体
{
int num;
char name[101];
int sex;
};
int main(){
union MyUni a,b,c;
int StructLen(sizeof(struct student)); //StructLen=112;
// 4+101+4=109; 112-109=3
//保持的是4k对齐,108/4=27 109-112是4个字节。
printf("StructLen=%d\n",StructLen); // 112
共用体: 所占用内存长度等于最长的成员长度。
#include "stdio.h"
#include "string.h"
union MyUni //共用体
{
int CarNum; //车编号,
char CarType; //车的类型
char name[60]; //轿车名
};
int main(){
union MyUni a,b,c;
int UnionLen(sizeof(union MyUni));
printf("UnionLen=%d\n",UnionLen); // UnionLen=60
//最长的成员类型长度
说明:
a、共用体变量的引用
a.name;
a.CarNum;
b、共用体变量的特点
同一段内存存放几种不同类型的成员,但每一个瞬间只能存放其中一种。也就是说,每个瞬间只能由一个成员起作用,其他成员不起作用,并不是同时存在、都起作用
程序代码中最后给哪个成员赋值,那么哪个成员就起作用
#include "stdio.h"
#include "string.h"
union MyUni //共用体
{
int CarNum; //车编号,
char CarType; //车的类型
char name[60]; //轿车名
};
struct student //结构体
{
int num;
char name[101];
int sex;
};
int main(){
union MyUni a,b,c;
int StructLen(sizeof(struct student)); //StructLen=112;
// 4+101+4=109; 112-109=3 保持的是4k对齐,108/4=27 109-112是4个字节。
int UnionLen(sizeof(union MyUni));
printf("StructLen=%d\n",StructLen);
printf("UnionLen=%d\n",UnionLen);
**a.name;
a.CarNum = 12; //这个不起作用
strcpy(a.name,"ab"); //这是最后一个成员,所以这个才起作用
printf("%d\n",a.CarNum); //不确定的值
printf("%s\n",a.name); //ab**
c、共用体变量的地址 和 其他成员地址都相同
&a &a.Carnum &a.name &a.CarType
这三个地址都相同
d、共用体变量不能在定义的时候初始化,而结构体可以初始化
e、不能把共用体变量作为函数参数,也不能让函数带回共用体变量
9.3.2枚举类型
例如:
//四种颜色: 红,绿,蓝,黄
// Red表红色
//Green
//Blue
//Yellow
枚举值当成整型值用就行了
枚举类型关键字
enum
enum color
{
Red, //枚举常量,值不能被改变(可以当成一个整形数字)
//占用4个字节
Green,
Blue,
Yellow
};
枚举就是将值一一列举出来,那么定义的枚举变量值就只限于列出来的这些值的范围内;
可以直接定义枚举变量,不要枚举名,这就要直接定义枚举变量才行
enum
{
Red,
Green,
Blue,
Yellow
}MyColor1,MyColor2;
这些Red,Green,Blue,Yellow叫做枚举常量,这些常量的值不能被改变
//枚举常量,值不能被改变(可以当成一个整形数字),占用4个字节
d、可以直接给 枚举类型变量 赋值
#include "stdio.h"
#include "string.h"
enum color
{
Red, //0,默认从0开始,
Green, //1
Blue, //2
Yellow //3
};
int main(){
**enum color MyColor1,MyColor2;**
printf("%d\n",Red);
printf("%d\n",Yellow);
**MyColor1 = Red; // 0
Mycolor2 = Yellow; // 3**
}
e、定义枚举类型时,直接给枚举常量一个值。
#include "stdio.h"
#include "string.h"
enum color
{
Red= 12, // 从12开始 往下走每次加1
Green, //13
Blue, //14
Yellow //15
};
int main(){
enum color MyColor1,MyColor2;
printf("%d\n",Red); //12
printf("%d\n",Yellow); //15
MyColor1 =Red; //Red当做常量
printf("%d\n",MyColor1); //12
}
f、枚举值,理解成整型值
枚举值可以做比较
MyColor1 = (enum color)-8;
//强制转换将-8给了Red这个常量
if(MyColor1 == Red // 枚举值可以做比较
{
printf("OK");
}
MyColor1 = (enum color)20000
printf("%d\n",MyColor1);
//枚举值其实就是整型值,可以互通
g、枚举值可以赋给一个整形
int abc;
abc = Green;
printf("%d\n",Green);
printf("%d\n",abc);
//两个的值都是一样的
9.3.3用typedef来定义类型
使用typedef来定义新的类型名,可以用来代替已有的类型名,
#include "stdio.h"
#include "string.h"
enum color
{
Red = 12,
Green,
Blue,
Yellow
};
int main(){
typedef int INTEGER; //可以使用INTEGER来代表int型,那再次定义整形变量时我们
//就可以如下定义
INTEGER a,b,c; //
int a1,a2,a3; // 这两个都是一样的
**//如何定义结构体类型
typedef struct date
{
int month;
int day;
int year;
}DATE;
DATE birthday;
DATE *p1; //p为指向此结构体类型数据的指针
//变形:
typedef int NUM[100]; //定义num数组是整形
NUM n; // 等价于int n[100];
typedef char *RNG; //定义RNG为字符指针类型
RNG p,q; // char *p,*q;**
**//指向函数的指针
typedef int (*POINTER)(); //定义pointer为指向函数的指针类型,该函数返回的是整型值
POINTER x,y;**
}
//总结: 第一步:先写出常规的整形数组定义方式
int n[100];
//第二步:将变量名替换成自己想用的类型名
int NUM[100];
//第三步:在前面加上typedef
typedef int NUM[100];
说明:
- typedef中用的类型别名使用大写
- typedef用来定义类型名的,不是定义变量
- typedef只是对已存在的类型增加一个类型名,没有创建新的类型
- typedef是在编译的时候处理的,是在编译环节进行的
可执行文件需要经过编译(预处理(#define,#include,#ifdef)**,编译(typedef),**汇编),链接,
1. typedef主要作用:
程序的通用性和可移植性
int a,b,c;
typedef int INTEGER;
INTEGER a,b,c;