结构体的概念
结构体的声明
struct 结构体名
{
类型说明符 成员名;//成员列表
...
};
成员列表由若干个成员组成,每个成员都是该结构的一个组成部分,对每个成员也必须作类型声明。
成员可以是基本数据类型或者另一个构造类型
"{}"不表示复合语句,其后需要加上分号。
结构体的声明可以放置在程序的开始部分,位于头文件声明之后,也可以声明在头文件中。
结构体名与其成员可以重名,结构体成员和其他变量可以重名。
结构体类型名称是“struct 结构体名”,注意struct关键字不能省略。
结构体可以用来定义变量的类型,和其他标准数据类型不同的是,结构体需要用户自己指定。
结构体的使用必须要定义对应的__结构体变量__
结构体类型相当于一个模型,系统对其不分配实际内存,只有定义相应的变量才实际分配内存。
结构体变量的定义
结构体变量成员的引用
结构体变量的赋值
结构体变量的赋值就是给结构体变量的各成员进行赋值
student.xh=100;
student.name="zhangsan";
可用输入语句来完成对成员的赋值
scanf("%c %f",&student.sex,&student.score);
允许具有相同类型的结构体变量相互赋值
student1=student2;
结构体变量的初始化
struct 结构体名 变量名1={成员值列表},...,变量名n={成员值列表};
例
struct student stu1 =
{1,"zhangsan","male",20,"shanghai"};
struct student stu2 =
{2,"lisi","female",21,"beijing"};
struct 结构体名
{
成员列表;
}变量名1={成员值列表;},...,变量名n={成员值列表;};
struct //省略结构名
{
成员列表;
}变量名1={成员值列表;},...,变量名n={成员值列表;};
结构体变量的嵌套
struct student
{
int xh;
char name[20];
struct address addr;
}stu;
例
/*文件:student.c*/
struct address
{
char *country;
char *city;
char *street;
};
struct student{
/*成员列表*/
int xh;
char *name;
char *gender;
//char name[30];
//char gender[20];
int age;
struct address addr; //嵌套结构体
};
/*文件:out_student.c*/
#include
#include
#include"student.h"
void out_student(struct student stu);
int main(void){
/*定义结构体变量并初始化*/
struct address addr =
{"china","shanghai","fanghua road"}
struct student stu1 =
{1,"zhangsan","male",20,addr};
struct student stu2 =
{2,"lisi","female",21,{"china","beijing","gugong road"}};
/*
/*定义结构体变量*/
struct student stu1,stu2;
stu1.xh=1;
stu1.name="zhangsan";//对应char *name,字符指针可以用字符串赋值
stu1.gender="male";
//strcpy(stu1.name,"zhangsan");//当结构中为数组时使用
//strcpy(stu1.gender,"male");
stu1.age=20;
/*结构体变量的赋值*/
//stu2 = stu1;
scanf("%d %s %s %d",&stu2.xh,stu2.name,stu2.gender,&stu2.age);
*/
out_student(stu1);
printf("------------\n");
out_student(stu2);
}
void out_student(struct student stu){
printf("xh:%d\n",stu.xh);
printf("name:%s\n",stu.name);
printf("gender:%s\n",stu.gender);
printf("age:%d\n",stu.age);
printf("country:%s\n",stu.addr.country);
printf("city:%s\n",stu.addr.city);
printf("street:%s\n",stu.addr.street);
}
结构体数组的概念
元素为结构体类型的数组称为结构体数组
在实际应用中,经常用结构体数组来表示具有_相同数据结构_的一个群体。例如一个班的学员档案,公司员工档案等。
结构体数组的定义和初始化
struct 结构体名{成员列表;};
struct 结构体名 数组名[长度]={{成员值列表},...,{成员值列表}}
struct [结构体名]{成员列表;}
数组名[长度]={{成员值列表},...,{成员值列表}};
例
struct student
{
int xh;
char name[20];
char sex;
float score;
}stus[3];
strcpy(stus[0].name,"jack");//设置第一个学生的名字
stus[1].age++;//增加第二个学生的年龄。
结构体数组的引用
结构体数组名[下标].成员名
void out_students(struct student stus[],int n)
{
int i;
for(i=0;i<n;i++){
out_student(stus[i]);//逐个输出学员的全部信息
printf("======\n");
}
}
案例介绍:使用结构体数组完成学生信息的增删改查
设计流程:
/*文件名:student.h*/
struct address
{
char country[20];
char city[20];
char street[30];
};
struct student{
int xh;
char name[20];
char gender[10];
int age;
struct address addr;
};
//-----------------------------------------
/*文件名:stumis.h*/
#include "student.h"
#define MAX_SIZE 100
/*增加学生*/
extern void add_student(struct student stu);
/*删除学生*/
extern void del_student(int xh);
/*更新学生*/
extern void update_student(int xh,struct student newstu);
/*查找学生*/
extern struct student find_student(int xh);
/*查找所有学生*/
extern void findall();
//-----------------------------------------
/*文件名:stumis.c*/
#include "stumis.h"
#include
#include
static struct student stus[MAX_SIZE];
static int counter;
/*查找学生所在数组的位置(下标)*/
static int find_position(int xh){
int position;
for(position=0;position<MAX_SIZE;position++){
if(stus[position].xh == xh)return position;
}
return -1;
}
/*输出学生信息*/
static void out_student(struct student stu){
printf("xh:%d\n",stu.xh);
printf("name:%s\n",stu.name);
printf("gender:%s\n",stu.gender);
printf("age:%d\n",stu.age);
printf("country:%s\n",stu.addr.country);
printf("city:%s\n",stu.addr.city);
printf("street:%s\n",stu.addr.street);
}
/*增加学生*/
extern void add_student(struct student stu){
if(counter>=MAX_SIZE)return;
stus[counter]=stu;
counter++;
}
/*删除学生*/
extern void del_student(int xh){
int position=find_position(xh);
if(position==-1){
printf("delete student is not exist!\n");
return;
}
int i;
for(i=position;i<counter-1;i++){
stus[i]=stus[i+1];
}//删除就是用后面的数据前移覆盖掉该需要删除的数据
counter--;
}
/*更新学生*/
extern void update_student(int xh,struct student newstu){
int pos=find_position(xh);
if(pos==-1){
printf("update student is not exist!\n");
return;
}
strcpy(stus[pos].name,newstu.name);
stus[pos].age=newstu.age;
strcpy(stus[pos].addr.country,newstu.addr.country);
strcpy(stus[pos].addr.city,newstu.addr.city);
strcpy(stus[pos].addr.street,newstu.addr.street);
}
/*查找学生*/
extern struct student find_student(int xh){
int pos=find_position(xh);
if(pos==-1){
printf("find student is not exist!\n");
return;
}
return stus[pos];
}
/*查找所有学生*/
extern void findall(){
int i;
for(i=0;i<counter;i++){
out_student(stus[i]);
printf("---------------\n");
}
}
//-----------------------------------------
/*文件名:stumis_test.c*/
#include
#include "stumis.h"
int main(void){
struct address addr1={"china","shanghai","fanghua road"};
struct student stu1={10,"zhangsan",20,"male",addr1};
struct address addr2={"china","beijing","changan road"};
struct student stu2={11,"lisi",22,"female",addr2};
printf("**********add student**********\n");
add_student(stu1);
add_student(stu2);
printf("**********find all student**********\n");
findall();
printf("**********find student**********\n");
struct student stu = find_student(10);
printf("%d %s %d %s\n",stu.xh,stu.name,stu.age,stu.addr.city);
printf("**********update student**********\n");
struct address newaddr={"china","wudangshan","zhongsan road"};
struct student newstu={10,"zhangsanfeng",100,"male",newaddr};
update_student(10,newstu);
stu=find_student(10);
printf("%d %s %d %s\n",stu.xh,stu.name,stu.age,stu.addr.city);
printf("**********delete student**********\n");
del_student(11);
printf("**********find all student**********\n");
findall();
return 0;
}
通过结构体指针访问结构体变量的成员
结构体指针->成员名;
或者
(*结构体指针).成员名;
访问结构体变量的三种方式
void out_student(struct student *stup)
{
printf("xh:%d\n",stup->xh);
printf("name:%s\n",stup->name);
}
结构体的自引用
在一个结构体内部包含指向该结构体本身的指针(事实上指向的是同一类型的不同结构体变量)
struct SELF_REF1{
int a;
struct SELF_REF1 *b;
int c;
}
结构体的不完整声明
C语言允许用户自己定义类型说明符,允许用户自己为数据类型去别名
语法:
typedef 原类型名 新类型名(类型别名);
用typedef定义数组、指针、结构体等类型别名将带来很大的方便。
易于理解,容易修改,可移植性好。
示例:
typedef float Dollars;
Dollars cash_in,cash_out;
typedef定义类型别名也可以用预处理指令#define即宏定义来代替
语法:
#define 新类型名 原类型名
结尾没有分号
示例
#define INTEGER int
INTEGER a=100;
#define指令是在预处理阶段完成的,而typedef则是在编译时完成的,后者更为灵活方便。
#define无法正确处理指针类型,typedef更为合适。
typedef char* ptr_char;
ptr_char a,b,c; //a,b,c都为指针
#define PTR_CHAR char*
PTR_CHAR a,b,c; //a为指针,b和c为char类型
1.字节对齐的概念
现代计算机中内存空间都是按照byte划分的,在访问特定类型变量的时候经常在特定的内存地址访问。
字节对齐的定义:
字节对齐的原因和作用
字节对齐示例(假定运行在32位系统)
struct A{int a; char b; short c;};
sizeof(struct A);//8--aaaa bcc0
struct B{char b; int a; short c;};
sizeof(struct B);//12--b000 aaaa cc00
2.#pragma指令设置字节对齐
/*指定按2字节对齐*/
#pragma pack(2)
struct C{char b; int a; short c;};
#pragma pack()
sizeof(struct C);//6--b0 aa aa
/*指定按1字节对齐*/
#pragma pack(1)
struct D{char b; int a; short c;};
#pragma pack()
sizeof(struct D);//7--b a a a a c c
4.编译器的字节对齐原则
基本概念
重要概念
5.字节对齐的编程设置
空间换取时间
结构体中的成员按类型大小从小到大定义
struct A{char a;char reserved[3];int b;};
sizeof(A); //8
1.位段的概念
2.位段的定义
语法:
类型说明符 [位段名]:位长
struct node{
unsigned int a:4;
unsigned int :0;
unsigned int b:4;
int c:32;
int :6;
};
联合的概念
要求:
/*文件名:student_teacher.c*/
#include
struct{
char name[10]; char sex;
char job; int num; //job分为"s"和"t"
union{
int class; //班级号
char position[10];//职位名称
}category;
}person[2];
//-----------------------------
int main(void){
int n,i;
for(i=0;i<2;i++){
printf("Please enter num,name,sex,job\n");
scanf("%d %s %c %c",
&person[i].num,&person[i].name,
&person[i].sex,&person[i].job);
if(person[i].job=='s'){
printf("Please enter Class:");
scanf("%d",&person[i].category.class);
}else if(person[i].job=='t'){
printf("Please enter Position:");
scanf("%s",&person[i].category.position);
}else printf("input error!");
}
printf("\n");
printf("No.\tName\tsex\tjob\tclass/position\n");
for(i=0;i<2;i++){
if(person[i].job=='s'){
printf("%-6d %-10s %-3c %-3c %-6d\n",
person[i].num,person[i].name,
person[i].sex,person[i].job,person[i].category.class);
}else{
printf("%-6d %-10s %-3c %-3c %-6s\n",
person[i].num,person[i].name,
person[i].sex,person[i].job,
person[i].category.position);
}
}
}