结构体
C语言中的数据类型:
基本数据类型:char/int/short/double/float/long
构造数据类型:数组,指针,结构体,共用体,枚举
概念:
结构体是用户自定义的一种数据类型,可以是相同的数据类型,也可以是不同的数据类型的集合
格式:
struct 结构名
{
数据类型 成员1;
数据类型 成员2;
数据类型 成员3;
数据类型 成员4;
......
数据类型 成员n;
}; //结尾的";"不可省略
*分析:
struct:是结构体的关键字
结构名:满足命名规范
{}:不能省略
数据类型:可以是基本数据类型,也可以是构造数据类型
成员:可以是任意个成员
结构体的声明可以在任意位置,但一般在头文件中
结构体在声明类型时不占用内存空间,当使用结构体类型定义变量时申请空间
结构体的初始化和赋值
间接初始化和赋值
格式:
struct 结构名
{
数据类型 成员1;
数据类型 成员2;
数据类型 成员3;
数据类型 成员4;
......
数据类型 成员n;
};
struct 结构名 变量={数据类型 成员1,...,数据类型 成员n} //按顺序初始化
struct 结构名 变量={.成员1=,...,.成员n=} //不按顺序初始化(用". 成员"+成员对应的数据类型的数据)
输出结构体(结构体变量访问内部成员,通过"."访问)
printf("占位符\n",变量.成员1,变量.成员2,...)
间接初始化练习:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct student
{
char name[128];
int age;
double score;
};
int main(int argc, const char *argv[])
{
struct student s1={"张三",24,98};
struct student s2={"李四",36,87};
struct student s3={"王五",18,43};
printf("姓名:%s年龄:%d成绩%lf\n",s1.name,s1.age,s1.score);
printf("姓名:%s年龄:%d成绩%lf\n",s2.name,s2.age,s2.score);
printf("姓名:%s年龄:%d成绩%lf\n",s3.name,s3.age,s3.score);
return 0;
}
间接赋值练习:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct student
{
char name[128];
int age;
double score;
};
int main(int argc, const char *argv[])
{
//间接初始化
struct student s1={"张三",24,98};
struct student s2={"李四",36,87};
struct student s3={"王五",18,43};
printf("姓名:%s年龄:%d成绩%lf\n",s1.name,s1.age,s1.score);
printf("姓名:%s年龄:%d成绩%lf\n",s2.name,s2.age,s2.score);
printf("姓名:%s年龄:%d成绩%lf\n",s3.name,s3.age,s3.score);
//赋值方式1
struct student s4;
strcpy(s4.name,"牛二");
s4.age=25;
s4.score=67;
printf("姓名:%s年龄:%d成绩%lf\n",s4.name,s4.age,s4.score);
//赋值方式2
struct student s5;
printf("输入学生姓名\n");
scanf("%s",s5.name);
printf("输入学生年龄\n");
scanf("%d",&s5.age);
printf("输入学生成绩\n");
scanf("%lf",&s5.score);
printf("姓名:%s年龄:%d成绩%lf\n",s5.name,s5.age,s5.score);
return 0;
}
直接初始化和赋值
直接初始化是将变量定义在结构体类型的后面
如果使用直接初始化,可以省略结构名不写
如果省略结构名,则只能使用已有的结构类型变量
格式:
struct 结构名
{
数据类型 成员1;
数据类型 成员2;
数据类型 成员3;
数据类型 成员4;
......
数据类型 成员n;
}
变量1={.成员1=,...,.成员n=},
变量2={.成员1=,...,.成员n=},
变量3={.成员1=,...,.成员n=}
...
;
练习:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct dog
{
char name[128];
int age;
char color[128];
}d1={.name="小黑",.age=2,.color="白色"},
d2={.name="小白",.age=2,.color="黑色"},
d3,
d4
;
void out(struct dog d)
{
printf("名字:%s年龄:%d毛色:%s\n",d.name,d.age,d.color);
}
int main(int argc, const char *argv[])
{
out(d1);
out(d2);
//赋值方式1
struct dog d3;
strcpy(d3.name,"小黄");
d3.age=25;
strcpy(d3.color,"黄色");
out(d3);
//赋值方式2
struct dog d4;
printf("输入姓名\n");
scanf("%s",d4.name);
printf("输入年龄\n");
scanf("%d",&d4.age);
printf("输入毛色\n");
scanf("%s",d4.color);
out(d4);
return 0;
}
结构体数组
数组:一次性定义多个类型相同的变量
结构体数组:一次性定义多个类型相同的结构体变量
结构体数组的初始化和赋值
间接初始化和赋值
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct student
{
char name[128];
int age;
int id;
};
void out(struct student *s,int n)
{
for(int i=0;i<n;i++)
{
printf("名字:%s 年龄:%d 学号:%d\n",s[i].name,s[i].age,s[i].id);
}
}
int main(int argc, const char *argv[])
{
struct student s[3]={{"张三",18,1008},{"李四",18,1009}}; //按顺序初始化
struct student s1[3]={[2]={.id=1009,.name="王五",.age=20}}; //不按数据初始化
out(s,3);
out(s1,3);
return 0;
}
直接初始化和赋值
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct student
{
char name[128];
int age;
int id;
}
s[3]={{"张三",23,1010}}
;
void out(struct student *s,int n)
{
for(int i=0;i<n;i++)
{
printf("名字:%s 年龄:%d 学号:%d\n",s[i].name,s[i].age,s[i].id);
}
}
void in(struct student *s,int n)
{
for(int i=0;i<n;i++)
{
printf("输入姓名\n");
scanf("%s",s[i].name);
printf("输入年龄\n");
scanf("%d",&s[i].age);
printf("输入学号\n");
scanf("%d",&s[i].id);
}
}
int main(int argc, const char *argv[])
{
out(s,3);
return 0;
}
结构体指针
结构体指针:存储结构体变量的地址
格式:
struct 结构名 *变量名;
结构指针访问内部变量通过"->"访问
练习:
在栈区中用结构体指针实现结构体元素的输入输出
在堆区中用结构体指针实现结构体元素的输入输出
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct student
{
char name[128];
int age;
int id;
};
void out(struct student *s,int n)
{
for(int i=0;i<n;i++)
{
printf("名字:%s 年龄:%d 学号:%d\n",(s+i)->name,(s+i)->age,(s+i)->id);
}
}
void in(struct student *s,int n)
{
for(int i=0;i<n;i++)
{
printf("输入姓名\n");
scanf("%s",(s+i)->name);
printf("输入年龄\n");
scanf("%d",&(s+i)->age);
printf("输入学号\n");
scanf("%d",&(s+i)->id);
}
}
int main(int argc, const char *argv[])
{
struct student s[3];
struct student *p=s;
in(p,3);
out(p,3);
struct student *str=(struct student *)malloc(sizeof(struct student)*3);
struct student *q=str;
in(q,3);
out(q,3);
return 0;
}
typedef结合结构体
格式:
typedef 直接修饰结构体类型(常用)
typedef struct student
{
int id;
int age;
}stu;
stu s; ---> struct student s
typedef 间接修饰结构体类型
struct student
{
int id;
int age;
};
typedef struct student stu;
stu s; ---> struct student s
typedef 起多个名字
typedef struct student
{
int id;
int age;
}student,*ptr_student;
student s; ---> struct student s
ptr_student p=$s; ---> struct student *p
结构体的嵌套
格式:
typedef struct birthday
{
int year;
int month;
}bir;
typedef struct student
{
char name[128];
int age;
bir b; //嵌套一个结构体
}stu;
stu s = {18,"11",2003,12,12};
结构体的嵌套结构体数组
格式:
typedef struct car
{
double price;
char name[128];
}car;
typedef struct student
{
char name[128];
int age;
car b[3]; //嵌套一个结构体数组
}stu;
stu s = {18,"11",{1,"名字"},{2,"名字"},{3,"名字"}};
结构体字节对齐( 字节计算 笔试 )
结构体各个成员的地址是连续的
结构体变量的地址是第一个成员的地址
64位操作系统,8字节对齐:
- 结构体的总字节大小是各个成员字节的总和,但是需要满足是最宽成员的倍数
- 结构体的首地址是最宽成员的倍数
- 结构体各个成员的首地址是该成员字节的整数倍,否则填充空字节
32位操作系统,4字节对齐:
- 结构体的总字节大小是各个成员字节的总和,但是需要满足是最宽成员的倍数
- 结构体的首地址是最宽成员的倍数
- 结构体各个成员的首地址是该成员字节(或该成员字节数大于4则是4)的整数倍,否则填充空字节
共用体
概念:不同或者相同的数据,共用一段内存空间
作用:实现一段内存,存放不同的数据
格式:
union 共用名
{
数据类型 成员1;
数据类型 成员2;
数据类型 成员3;
数据类型 成员4;
......
数据类型 成员n;
}; //结尾的";"不可省略
*分析:
union:是结构体的关键字
共用名:满足命名规范
{}:不能省略
数据类型:可以是基本数据类型,也可以是构造数据类型
成员:可以是任意个成员
共用体的声明可以在任意位置,但一般在头文件中
共用体在声明类型时不占用内存空间,当使用共用体类型定义变量时申请空间
共用体的内存空间是最宽成员的内存大小