一、为什么要用结构体?
- 结构体是类型不同的一组数据集合,数据更多,类型更丰富,信息量更大
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
//这样定义一个结构体
struct student
{
int score;
char name[128];
};//注意分号要写
int main()
{
//stu1 是结构体变量名
struct student stu1 = {100,"free"};//大括号里面的是初始值
//访问结构体数据
printf("stu1结构体的: score=%d\n",stu1.score);
printf("stu1结构体的:name=%s\n",stu1.name);//结构体变量名.内部变量名
struct student stu2;//没做初始化的结构体
stu2.score = 99;//给结构体内部数据赋值
//stu2.name = "张三";这样是不行的
strcpy(stu2.name,"张三");
printf("stu2结构体的: score=%d\n",stu2.score);
printf("stu2结构体的:name=%s\n",stu2.name);
return 0;
}
2.运行结果:
3.注意常犯的错误 “野指针”
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct stu
{
char *name;
};
struct text
{
char name[128];
};
int main()
{
struct stu a;
struct text b;
/*第一种
strcpy(a.name,"感觉自己萌萌哒");
printf("stu的name = %s\n",a.name);
*/
//第二种
strcpy(b.name,"感觉自己萌萌哒");
printf("text的name = %s\n",b.name);
return 0;
}
第一种运行结果:
因为是对野指针直接赋值,出现段错误,人家都还只是一个地址,都还没有开辟空间呢你就给人家赋值,所以对使用指针一定要注意,要先开辟空间再初始化,最后再赋值!!!
第二种运行结果:
因为是对字符串数组进行赋值,数组定义出来就已经申请了空间,所以可以直接赋值。
二、结构体数组来玩成绩
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct student
{
int score;
char *name;
};
int main()
{
int i;
struct student stu[3];//定义了一个结构体数组,也是通过下标法来访问
for(i=0;i<sizeof(stu) / sizeof(stu[0]);i++){
printf("请输入第%d个学生的成绩:\n",i+1);
scanf("%d",&(stu[i].score));
printf("请输入第%d个学生的名字:\n",i+1);
stu[i].name = (char *)malloc(128);//注意对结构体内部指针,使用前要申请开辟空间
scanf("%s",stu[i].name);
}
for(i=0;i<sizeof(stu) / sizeof(stu[0]);i++){
printf("你输入的%d个学生的成绩是:%d 名字是:%s\n",i+1,stu[i].score,stu[i].name);
}
struct student maxStu;
struct student minStu;
maxStu = minStu = stu[0];
for(i=0;i<sizeof(stu) / sizeof(stu[0]);i++){
if(maxStu.score < stu[i].score){
maxStu = stu[i];
}
if(minStu.score > stu[i].score){
minStu = stu[i];
}
}
printf("考最高分的是:%s 分数是:%d\n",maxStu.name,maxStu.score);
printf("考最低分的是:%s 分数是:%d\n",minStu.name,minStu.score);
return 0;
}
运行结果:
三、结构体指针
1.注意:
- 如果结构体指针,访问结构体中的变量时就不能用点运算符,要用->
- 使用结构体指针时,要注意是否是野指针或者是NULL!!!
- 结构体指针的偏移值是整个结构体的大小
2.看代码:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct student
{
int score;
char name[128];
};
int main()
{
struct student *p;//这样定义一个结构体指针,不过这是野指针,还没有开辟空间
p = (struct student *)malloc(sizeof(struct student));//开辟空间
p->score = 98;//赋值
strcpy(p->name,"李四");
printf("结构体指针的score=%d name=%s\n",p->score,p->name);
//看下偏移值
printf("结构体指针的地址是:%p\n",p);
printf("++后的地址是:%p\n",++p);
return 0;
}
3.运行结果:
四、结构体指针函数综合处理学生成绩
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct student
{
int score;
char *name;
};
struct student * initStuScore(int len)
{
int i;
//在堆上开辟空间,函数结束调用不会释放
struct student *p = (struct student *)malloc(len * sizeof(struct student));
for(i=0;i<len;i++){
printf("请输入第%d个学生的名字:\n",i+1);
p->name = (char *)malloc(128);
scanf("%s",p->name);
printf("请输入第%d个学生的成绩:\n",i+1);
scanf("%d",&(p->score));
p++;
}
return p - len;
}
void printMes(struct student *p,int len)
{
int i;
for(i=0;i<len;i++){
printf("你输入的第%d个学生的成绩是:%d 名字是:%s\n",i+1,p->score,p->name);
p++;
}
}
struct student *findMax(struct student *p,int len)
{
int i;
struct student *max;
max = p;
for(i=0;i<len;i++){
if(max->score < p->score){
max = p;
}
p++;
}
return max;
}
struct student *findMin(struct student *p,int len)
{
int i;
struct student *min;
min = p;
for(i=0;i<len;i++){
if(min->score > p->score){
min = p;
}
p++;
}
return min;
}
float getAverage(struct student *p,int len)
{
int i;
int total = 0;
for(i=0;i<len;i++){
total += p->score;
p++;
}
return (float)total / len;
}
int findSomeOneName(struct student *p,int len,char *name)
{
int i;
for(i=0;i<len;i++){
if(strcmp(name,p->name) == 0){
return 1;
}
p++;
}
return -1;
}
int main()
{
int len = 0;
printf("请输入学生总人数:\n");
scanf("%d",&len);
struct student *max;
struct student *min;
struct student *pstus = initStuScore(len);
printMes(pstus,len);
max = findMax(pstus,len);
min = findMin(pstus,len);
printf("你输入学生成绩的最高分是:%d 名字是:%s\n最低分是:%d 名字是:%s 平均分是:%f\n",max->score,max->name,min->score,min->name,getAverage(pstus,len));
if(findSomeOneName(pstus,len,"王五") == -1){
printf("没有此人\n");
}else{
printf("恭喜,找到了\n");
}
return 0;
}
>运行结果:
五、结构体大小的计算方式:
1)结构体成员的偏移量必须是成员大小的整数倍(0被认为是任何数的整数倍)
2)结构体大小必须是所有成员大小(数组除外,结构体除外)的整数倍
注意:
- 对齐方式确实很浪费空间,但是按照计算机的访问规则,这种对齐方式大大提升了效率
代码段:
#include<stdio.h>
#include<string.h>
struct s1
{
char ch1;
char ch2;
int i;
};
struct s2
{
char ch1;
int i;
char ch2;
};
struct s3
{
char ch1;
int i;
char str[10];
};
struct s4
{
char ch1;
int i;
struct s{
char ch;
int j;
};
float f;
};
struct s5
{
char ch1;
int i;
union{
char ch;
int j;
};
};
//#pragma pack(4) //指定向4对齐,最大是8,指定的大小没有超过结构体成员的大小,所以指向4对齐
struct s6
{
char ch;
int i;
float f;
double d;
};
#pragma pack(10)//指定向10对齐,超过了结构体成员最大的大小,所以指向8对齐
struct s7
{
char ch;
int i;
float f;
double d;
};
int main()
{
printf("s1:%ld\n",sizeof(struct s1));//结果:8
printf("s2:%ld\n",sizeof(struct s2));//结果:12
printf("s3:%ld\n",sizeof(struct s3));//结果:20
printf("s4:%ld\n",sizeof(struct s4));//结果:12
printf("s5:%ld\n",sizeof(struct s5));//结果:12
printf("s6:%ld\n",sizeof(struct s6));//结果:20
printf("s7:%ld\n",sizeof(struct s7));//结果:24
return 0;
}
六、typedef关键字
1)typedef为c语言的关键字
2)作用是为一种数据类型定义一个新名字
3)这里的数据类型包括内部数据类型(int ,char 等)和自定义数据类型(struct 等)
4)和struct 来匹配为了代码编写简洁,和普通类型匹配,通过名字来获取一些信息
代码段:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
//在单片机开发,寄存器8位,16位,32位
typedef unsigned char u_int8;
typedef unsigned short int u_int16;
typedef unsigned int u_int32;
typedef struct student
{
int score;
char *name;
}STU,*PSTU;
int main()
{
u_int8 data1 = 10;
u_int16 data2 = 20;
u_int32 data3 = 30;
printf("%d %d %d\n",data1,data2,data3);
STU stu1;
stu1.score = 99;
printf("stu1的score=%d\n",stu1.score);
PSTU pstu;
pstu = (PSTU)malloc(sizeof(STU));
pstu->score = 100;
printf("pstu的score=%d\n",pstu->score);
}
运行结果: