结构体定义及赋值
定义结构体变量的方式:
l 先声明结构体类型再定义变量名
2 在声明类型的同时定义变量
3 直接定义结构体类型变量(无类型名)
结构体类型和结构体变量关系:
l 结构体类型:指定了一个结构体类型,它相当于一个模型,但其中并无具体数据,系统对之也不分配实际内存单元。
2 结构体变量:系统根据结构体类型(内部成员状况)为之分配空间。
1、复合类型在内存中存放的模型:
定义结构体格式:
struct 结构体名称
{
结构体成员列表;
};
定义结构体变量
struct 结构体名称 结构体变量名
结构体变量名.结构体成员列表 = 值;
如果是字符串类型,需要使用strcpy拷贝。
示例
//声明结构体类型
struct students
{
//成员列表
char name[21];
unsigned int age;
char tel[16];
float scores[3];
char sex;
};
int main(void)
{
//按照结构体顺序 赋值;
//struct students stu = { "张三",50, "13812341234",100.0f,200,300,'M' };
//不按顺序赋值的形式
//struct students stu = {.sex = 'M', .name = "刘能", .tel ="13712241234",.scores[0]=100}
struct students stu;
//stu.name = "刘能"; 这样会被定义为常量,会出错
strcpy(stu.name, "刘能");
stu.age = 50;
strcpy(stu.tel, "13112344123");
stu.scores[0] = 90;
stu.scores[1] = 88;
stu.scores[2] = 89;
stu.sex = 'F';
printf("姓名:%s\n", stu.name);
printf("年龄:%u\n", stu.age);
printf("电话:%s\n", stu.tel);
printf("分数:%.1f %.1f %.1f\n", stu.scores[0], stu.scores[1], stu.scores[2]);
printf("性别:%s\n", stu.sex == 'M' ? "男" : "女");
system("pause");
return EXIT_SUCCESS;
}
结构体大小和内存存储结构
结构体在程序中别的文件中也可以使用,也可以把结构体写在.h文件中
内存结构模型图
示例
//结构体需要根据数据类型进行内存对齐;
struct stus
{
//成员列表
char name[20];
unsigned int age;
char tel[15];
float scores[3];
char sex; //占56字节
} stu;// = { "尼古拉斯",500,"13012341234",100.0f,200,300,'M' };
struct stus1
{
//成员列表
char name[20];
unsigned int age;
char tel[15];
char sex;
float scores[3];//占52字节;会跟成员列表中占据内存最长的进行对齐;
} stu1;//在结构体构建中合理调整成员列表可以减少占用的内存空间;
//一般情况下结构体里排列数据类型的时候,从上到下按照数据类型从大到小排列即可;
//要找到利于阅读和节省空间的平衡点;
int main(void)
{
printf("结构体stu大小%d\n", sizeof(stu));
printf("结构体stu1大小%d\n", sizeof(stu1));
system("pause");
return EXIT_SUCCESS;
}
结构体数组
正常按照数组定义就可以,如果有输入的话要注意格式问题。
示例
struct stus1
{
//成员列表
char name[20];
unsigned int age;
char tel[15];
char sex;
float scores[3];
};
int main(void)
{
struct stus1 s[2];
for (size_t i = 0; i < 2; i++)
{
printf("请您输入 姓名 年龄 电话 成绩 性别:\n");
scanf("%s%d%s%f%f%f,%c", s[i].name, &s[i].age, s[i].tel, &s[i].scores[0],
&s[i].scores[1], &s[i].scores[2], &s[i].sex);
}
for (size_t i = 0; i < 2; i++)
{
printf("姓名:%s\n", s[i].name);
printf("年龄:%u\n", s[i].age);
printf("电话:%s\n", s[i].tel);
printf("分数:%.1f %.1f %.1f\n", s[i].scores[0], s[i].scores[1], s[i].scores[2]);
printf("性别:%s\n", s[i].sex == 'M' ? "男" : "女");
}
system("pause");
return EXIT_SUCCESS;
}
结构体排序
示例
struct students
{
//成员列表
char name[21];
float scores[3];
};
int main(void)
{
struct students s[3];
for (size_t i = 0; i < 3; i++)
{
printf("请输入学生姓名 成绩 : \n");
scanf("%s%f%f%f", s[i].name, &s[i].scores[0], &s[i].scores[1], &s[i].scores[2]);
}
//冒泡排序
for (size_t i = 0; i < 3-1; i++)
{
for (size_t j = 0; j < 3-i-1; j++)
{
int temp;
int sum1 = s[j].scores[0] + s[j].scores[1] + s[j].scores[2];
int sum2 = s[j+1].scores[0] + s[j+1].scores[1] + s[j+1].scores[2];
if (sum1>sum2)
{
//结构体交换,交换所有成员列表中的数据
//交换姓名
char temp[21] = { 0 };
strcpy( temp,s[j].name );
strcpy(s[j].name, s[j + 1].name);
strcpy(s[j + 1].name, temp);
//交换成绩
for (size_t k = 0; k < 3; k++)
{
float temp = s[j].scores[k];
s[j].scores[k] = s[j + 1].scores[k];
s[j + 1].scores[k] = temp;
}
}
}
}
for (size_t i = 0; i < 3; i++)
{
printf("姓名:%s\n", s[i].name);
printf("成绩:%.1f %.1f %.1f \n", s[i].scores[0], s[i].scores[1], s[i].scores[2]);
}
system("pause");
return EXIT_SUCCESS;
}
上述代码中结构体交换所有成员列表中的数据非常麻烦,也可以采取结构体变量交换的简单方式。
相当于交换了里边的地址。
示例2:结构体排序优化
struct students
{
//成员列表
char name[21];
float scores[3];
};
int main(void)
{
struct students s[3];
for (int i = 0; i < 3; i++)
{
printf("请输入学生姓名 成绩 : \n");
scanf("%s%f%f%f", s[i].name, &s[i].scores[0], &s[i].scores[1], &s[i].scores[2]);
}
//冒泡排序
for (int i = 0; i < 3 - 1; i++)
{
for (int j = 0; j < 3 - i - 1; j++)
{
int temp;
int sum1 = s[j].scores[0] + s[j].scores[1] + s[j].scores[2];
int sum2 = s[j + 1].scores[0] + s[j + 1].scores[1] + s[j + 1].scores[2];
if (sum1 > sum2)
{
//结构体交换,结构体变量交换
struct students temp = s[j];
s[j] = s[j + 1];
s[j + 1] = temp;
}
}
}
for (int i = 0; i < 3; i++)
{
printf("姓名:%s\n", s[i].name);
printf("成绩:%.1f %.1f %.1f \n", s[i].scores[0], s[i].scores[1], s[i].scores[2]);
}
system("pause");
return 0;
}
#结构体与指针
结构体成员为指针
示例1
struct stuinfo
{
char* name;
int age;
};
int main(void)
{
struct stuinfo si;
si.name = (char*)malloc(sizeof(char) * 21);//开辟堆空间
strcpy(si.name, "张三");//结构体内成员列表赋值
si.age = 18;
printf("%s %d\n", si.name, si.age);
free(si.name);
system("pause");
return EXIT_SUCCESS;
}
示例2:结构体排序的指针写法
struct students
{
//成员列表
char * name; //指针写法
float scores[3];
};
int main(void)
{
struct students s[3];
for (int i = 0; i < 3; i++)
{
//开辟堆空间;
s[i].name = (char*)malloc(sizeof(char) * 21);
printf("请输入学生姓名 成绩 : \n");
scanf("%s%f%f%f", s[i].name, &s[i].scores[0], &s[i].scores[1], &s[i].scores[2]);
}
//冒泡排序
for (int i = 0; i < 3 - 1; i++)
{
for (int j = 0; j < 3 - i - 1; j++)
{
int temp;
int sum1 = s[j].scores[0] + s[j].scores[1] + s[j].scores[2];
int sum2 = s[j + 1].scores[0] + s[j + 1].scores[1] + s[j + 1].scores[2];
if (sum1 > sum2)
{
//结构体交换,结构体变量交换
struct students temp = s[j];
s[j] = s[j + 1];
s[j + 1] = temp;
}
}
}
for (int i = 0; i < 3; i++)
{
printf("姓名:%s\n", s[i].name);
printf("成绩:%.1f %.1f %.1f \n", s[i].scores[0], s[i].scores[1], s[i].scores[2]);
}
for (size_t i = 0; i < 3; i++) //释放堆空间
{
free(s[i].name);
}
system("pause");
return 0;
}
结构体指针
示例
struct stuinfo
{
char* name;
int age;
} stu;
int main(void)
{
struct stuinfo* s = &stu;
s->name = (char *)malloc(sizeof(char) * 21);//->指向结构体指针地址运算符
strcpy(s->name, "李飞");
s->age = 50;
printf("%s %d\n", s->name, s->age);
free(s->name);
system("pause");
return EXIT_SUCCESS;
}
堆空间开辟结构体
示例
struct stuinfo
{
char* name;
int age;
} st;
int main(void)
{
struct stu;
struct stuinfo* stu = (struct stuinfo*)malloc(sizeof(st));
//此处上面的*stu不能和后面sizeof内的变量名重名会冲突;造成申请的堆空间不够;
stu->name = (char*)malloc(sizeof(char) * 21);
strcpy(stu->name, "张飞");
stu->age = 18;
printf("%s %d\n", stu->name, stu->age);
if (stu->name)
{
free(stu->name);
stu->name = NULL;
}
if (stu)
{
free(stu);
stu = NULL;
}
system("pause");
return EXIT_SUCCESS;
}
堆空间开辟结构体对学生成绩排序
示例
struct stuinfo
{
char* name; //char指针
float * scores; //浮点数指针
} st;
int main(void)
{
struct stuinfo* stu = (struct stuinfo*)malloc(sizeof(st) * 3);
for (int i = 0; i < 3; i++)
{
//开辟堆空间;两项成员列表都要开辟
stu[i].name = (char*)malloc(sizeof(char) * 21);
stu[i].scores = (float *)malloc(sizeof(float) * 3);
printf("请输入学生姓名 成绩 : \n");
scanf("%s%f%f%f", stu[i].name, &stu[i].scores[0], &stu[i].scores[1], &stu[i].scores[2]);
}
for (size_t i = 0; i < 3-1; i++)
{
for (size_t j = 0; j < 3-i-1; j++)
{
struct stuinfo temp;
int sum1 = stu[j].scores[0] + stu[j].scores[1] + stu[j].scores[2];
int sum2 = stu[j + 1].scores[0] + stu[j + 1].scores[1] + stu[j + 1].scores[2];
if (sum1 > sum2)
{
temp = stu[j];
stu[j] = stu[j + 1];
stu[j + 1] = temp;
}
}
}
for (int i = 0; i < 3; i++)
{
printf("姓名:%s\n", stu[i].name);
printf("成绩:%.1f %.1f %.1f \n", stu[i].scores[0], stu[i].scores[1], stu[i].scores[2]);
}
//释放空间,两项成员列表都要释放
for (size_t i = 0; i < 3; i++)
{
free(stu[i].name);
free(stu[i].scores);
}
free(stu);
system("pause");
return EXIT_SUCCESS;
}
结构体和函数
结构体做函数参数
示例
struct info
{
char name[21];
int age;
};
void fun01(struct info s)//结构体作为形参
{
strcpy(s.name, "李四");
s.age = 20;
}
void fun02(struct info *s)//结构体指针作为形参
//可以把结构体当成自己定义变量的数据类型存在
{
strcpy(s->name, "李四");
s->age = 20;
}
int main(void)
{
struct info s = { "张三",18 };
fun01(s);
printf("%s %d\n", s.name, s.age);
fun02(&s);
printf("%s %d\n", s.name, s.age);
system("pause");
return EXIT_SUCCESS;
}
结构体做函数返回值
注意:
结构体指针作为返回值地址已经被销毁,会报错。
示例
struct info fun03() //结构体作为返回值
{
struct info s;
strcpy(s.name, "李四");
s.age = 20;
return s;
}
struct info* fun04() //结构体指针作为返回值
{
struct info s;
strcpy(s.name, "李四");
s.age = 20;
return &s;
}
int main()
{
struct info s = fun03();
printf("%s %d\n", s.name, s.age);
struct info* s = fun04(); //结构体指针作为返回值打印会报错
printf("%s %d\n", s->name, s->age);
return 0;
}
结构体函数案例:学生成绩
struct stu
{
char* name;
float* scores;
}st; //此处要提前声明个st,方便后面申请空间;
void bubble(struct stu* stu1, int len)
{
for (size_t i = 0; i < len-1; i++)
{
for (size_t j = 0; j < len-i-1; j++)
{
int sum1 = stu1[j].scores[0] + stu1[j].scores[1] + stu1[j].scores[2];
int sum2 = stu1[j + 1].scores[0] + stu1[j + 1].scores[1] + stu1[j + 1].scores[2];
if (sum1 > sum2)
{
struct stu temp = stu1[j];
stu1[j] = stu1[j + 1];
stu1[j + 1] = temp;
}
}
}
}
int main(void)
{
struct stu* stu1 = (struct stu*)malloc(sizeof(st) * 3);
for (int i = 0; i < 3; i++)
{
//开辟堆空间;两项成员列表都要开辟
stu1[i].name = (char*)malloc(sizeof(char) * 21);
stu1[i].scores = (float*)malloc(sizeof(float) * 3);
printf("请输入学生姓名 成绩 : \n");
scanf("%s%f%f%f", stu1[i].name, &stu1[i].scores[0], &stu1[i].scores[1], &stu1[i].scores[2]);
}
bubble(stu1, 3);
for (int i = 0; i < 3; i++)
{
printf("姓名:%s\n", stu1[i].name);
printf("成绩:%.1f %.1f %.1f \n", stu1[i].scores[0], stu1[i].scores[1], stu1[i].scores[2]);
}
//释放空间,两项成员列表都要释放
for (size_t i = 0; i < 3; i++)
{
free(stu1[i].name);
free(stu1[i].scores);
}
free(stu1);
system("pause");
return EXIT_SUCCESS;
}
结构体嵌套
所占据空间的大小根据结构体中最长的成员对齐。
示例
struct stra
{
int a;
float b;
char c;
};
struct strb
{
double d;
char* e;
short f;
struct stra abc; //结构体里b里嵌套了a;
};
int main(void)
{
struct strb strbb;
strbb.d - 10.0f;
strbb.abc.a = 100;//给结构体b里嵌套的a赋值;
printf("%d\n", strbb.abc.a);//打印结构体b里的a;
printf("%d\n", sizeof(strbb));
system("pause");
return EXIT_SUCCESS;
}
共用体(联合体)
l 联合union是一个能在同一个存储空间存储不同类型数据的类型;
2 联合体所占的内存长度等于其最长成员的长度倍数,也有叫做共用体;
3 同一内存段可以用来存放几种不同类型的成员,但每一瞬时只有一种起作用;
4 共用体变量中起作用的成员是最后一次存放的成员,在存入一个新的成员后原有的成员的值会被覆盖;
5 共用体变量的地址和它的各成员的地址都是同一地址。
示例
//共用体 union 共用体名称 成员列表 共用体变量名;
//整个共用体里所有成员共用一块内存大小
union vars
{
double a;
float b;
int c;
short d;
char f;
} var;
int main(void)
{
printf("%d\n", sizeof(var)); //大小根据最大数据类型决定,但是会对齐(相当于整个公约数?)
var.a= 100;
var.b = 3.14;
var.c = 66;
printf("a= %d\n", var.a);
printf("b= %d\n", var.b);
printf("c= %d\n", var.c); //共用体中最后一次被赋值的是准确的,其他的值会发生变化;
system("pause");
return EXIT_SUCCESS;
}
枚举
枚举:将变量的值一一列举出来,变量的值只限于列举出来的值的范围内。
枚举类型定义:
enum weekday
{
sun = 2, mon, tue, wed, thu, fri, sat
};
l 在枚举值表中应列出所有可用值,也称为枚举元素。
2 枚举值是常量,不能在程序中用赋值语句再对它赋值。
3 举元素本身由系统定义了一个表示序号的数值从0开始顺序定义为0,1,2 …
示例
enum colors
{
red,blue,yellow,black,white,green
}clo;
/*
枚举可以用作过程的锁定,比如银行取钱:也可以用作流程控制;
插卡,输入密码,锁定,取款,查询,退卡等;
枚举可以赋值,未赋值的会自动根据前面的增加,如:下例中blue=11,black=21,可做区间分隔
enum colors
{
red =10,blue,yellow=20,black,white,green
}clo;
*/
int main(void)
{
int val;
scanf("%d", &val);
switch (val)
{
case red:
printf("red\n");
break;
case blue:
printf("blue\n");
break;
case yellow:
printf("yellow\n");
break;
case black:
break;
case white:
break;
case green:
break;
default:
break;
}
system("pause");
return EXIT_SUCCESS;
}
typedef
typedef为C语言的关键字,作用是为一种数据类型(基本类型或自定义数据类型)定义一个新名字,不能创建新类型。
l 与#define不同,typedef仅限于数据类型,而不是能是表达式或具体的值
2 #define发生在预处理,typedef发生在编译阶段
#include <stdio.h>
typedef int INT;
typedef char BYTE;
typedef BYTE T_BYTE;
typedef unsigned char UBYTE;
typedef struct type
{ UBYTE a;
INT b;
T_BYTE c;
}TYPE, *PTYPE;
int main()
{
TYPE t;
t.a = 254;
t.b = 10;
t.c = 'c';
PTYPE p = &t;
printf("%u, %d, %c\n", p->a, p->b, p->c);
return 0;
}
打字小游戏
void tips()
{
printf("==============打字游戏================\n");
printf("============按任意键退出===============\n");
printf("===========按ESC退出游戏==============\n");
char ch = _getch();
if (ch == 27)
{
exit(0);
}
}
void rand_ch(char* arr)
{
srand((unsigned int)time(NULL));
for (size_t i = 0; i < 50; i++)
{
arr[i] = rand() % 26 + 'a';
}
}
void print_ch(char* arr)
{
//变量 计时器 开始 结束时间;计数器 val
int start_time;
int end_time;
int val =0;
for (size_t i = 0; i < 50; i++)
{
char ch = _getch();
if (i == 0)
{
start_time = time(NULL);
}
if (ch == arr[i])
{
printf("%c", ch);
val++;
}
else
{
printf("-");
}
}
end_time = time(NULL);
printf("\n");
printf("用时:%d\n", end_time - start_time);
printf("正确率:%.1f%%\n", val * 1.0 / 50 * 100);
}
int main(void)
{
//字库
char arr[51];
memset(arr, 0, 51);
while (1)
{
//1.提示操作
tips();
//2.随机字符
rand_ch(arr);
printf("%s\n", arr);
//3.输入字符
print_ch(arr);
}
system("pause");
return EXIT_SUCCESS;
}