文章目录
2020.9.28 第12节 结构体初识
一、结构体初识
1.结构体是什么东西? 内存上的样子
1.1 是一种新的数据类型---->自定义类型
1.2 为什么有结构体
1.3 完整定义结构体的语法
struct 标识符
{
基本数据类型;
};
2. 如何定义结构体变量
int num;
struct 结构体名 变量名; //结构体变量
int *p;
struct 结构体名* 指针名; //结构体指针
int array[4]; //结构体数组
struct 结构体名 数组名[数组长度]
3.如何访问结构体中成员
3.1 变量去访问: 变量.成员
3.2 指针访问: 结构体指针->成员
(*结构体指针).成员 //变量.成员
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
//<1>最常见的定义方式
struct MM //struct MM : 类型
{
char name[20];
int age;
int num;
};
//全局的结构体变量
struct MM g_MM = { "g_MM",19,1003 };
//<2>.没有结构体名的结构体
struct //没有类型
{
char name[20];
int age;
int num;
}role = {"g_role",29,1004}; //role : 唯一 一个结构体变量
//role 等效上面
//类型 变量名
//struct MM object; //object: 结构体变量 struct MM : 自定义类型
struct boy
{
char name[20];
int age;
int num;
}bRole;
//bRole : struct boy bRole;
struct boy bRole2;
struct boy bRole3;
int main()
{
//1.结构体变量
struct MM myMM;
printf("请输入姓名,年龄,编号:");
scanf("%s%d%d", myMM.name, &myMM.age, &myMM.num);
printf("%s\t%d\t%d\n", myMM.name, myMM.age, myMM.num);
//1.1 定义变量去初始化 注意!!!
struct MM yourMM = {"Baby",18,1002};
//错误写法
//struct MM object;
//object = { "Baby",18,1002 };
role.age = 38;
role.num = 9999;
//2.结构体指针
struct MM* pMM;
//3.结构体数组
struct MM array[4];
return 0;
}
二、结构体数组的基础
多个事物具有相同的属性 抽象过程
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
struct MM
{
char name[20];
int age;
int num;
};
//多次使用多种不同的数据的时候,采用结构体去封装
struct Tar
{
int x;
int y;
char target;
int speed;
};
struct Tar array[10];
int main()
{
struct MM myMM[3]; //myMM[0] myMM[1] myMM[2]
printf("请输入三个学生的信息:\n");
for (int i = 0; i < 3; i++)
{
printf("请输入第 %d 位的信息:", i + 1);
//myMM[0]
//myMM[1]
scanf("%s%d%d", myMM[i].name, &myMM[i].age, &myMM[i].num);
//scanf("%s%d%d", (myMM+i)->name, & (myMM+i)->age, & (myMM+i)->num);
}
printf("姓名\t年龄\t编号\n");
for (int i = 0; i < 3; i++)
{
printf("%s\t%d\t%d\n", myMM[i].name, myMM[i].age, myMM[i].num);
}
char name[10][20]; //10个人的姓名
return 0;
}
三、结构体指针
指针要充当变量使用:变量存值
1.指向变量
2.动态内存申请
经典错误 指针当作指针变量使用时
0的内存不能修改 p本身是没有内存的
//不先定义结构体变量然后 再用结构体指针指向它
如果要一个动态申请的结构体数组,更多的是数组
#include <stdio.h>
#include <string.h>
struct MM
{
char name[20];
int age;
int num;
};
int main()
{ //把0 强制转换为一个地址
struct MM* p = NULL; //NULL:(void*)0
//经典错误
//指针要充当变量使用: 变量存值
//1. 指向变量 //避免对空指针做非法操作
struct MM myMM;
p = &myMM;
strcpy(p->name, "ILoveyou");
p->age = 18;
p->num = 1001;
printf("%s\t%d\t%d\n", myMM.name, myMM.age, myMM.num);
printf("%s\t%d\t%d\n", (*p).name, (*p).age, (*p).num);
printf("%s\t%d\t%d\n", p->name, p->age, p->num);
//2. 动态内存申请
struct MM* pMM = (struct MM*)malloc(sizeof(struct MM));
strcpy(pMM->name, "MM");
pMM->age = 18;
pMM->num = 1001;
//不先定义结构体变量然后 再用结构体指针指向它
//动态申请的结构体数组,结构体指针变结构体数组
//struct MM pArray[3];
struct MM* pArray = (struct MM*)malloc(sizeof(struct MM) * 3);
//错误
//int* p = NULL; //(void *)0 强制转换语法 (目标类型)变量
//*p = 100;
return 0;
}
四、typedef和结构体的定义
如何看别名,把中间的数据全部省略掉
#include <stdio.h>
#include <string.h>
#include <windows.h>
typedef struct student_score_info
{
char name[20];
int age;
int num;
}SSI,*LPSSI,SARRY[2]; //结构体 结构体指针 结构体数组 的别名
/*
//如何看别名,把中间的数据全部省略掉
typedef struct student_score_info SSI;
typedef int INT;
typedef struct student_score_info* LPSSI
typedef int * LPINT;
typedef struct student_score_info SARRY[2]
typedef int array[2];
*/
struct MM
{
char name[20];
int age;
int num;
};
typedef struct MM MMTYPE;
typedef struct MM* LPMM;
int main()
{
//正常写法
struct student_score_info mm;
SSI t_mm;
struct student_score_info* pMM = &mm;
LPSSI p = &mm; //结构体指针的别名一定要有标识前缀 LP代表指针
//LPVOID lpvoid = NULL; //void * windows里面LPVOID
struct student_score_info array[2];
SARRY myarray;
return 0;
}
五、结构体中指针
1.结构体中的字符数组只能用strcpy,只是首地址
2.如果是指针? 不能直接赋值
yourBoy.name = (char*)malloc(strlen(inputName) + 1);
strcpy(yourBoy.name, inputName);
#include <stdio.h>
#include <string.h>
struct MM
{
char name[20];
int age;
int num;
};
struct Boy
{
char* name; //如果是指针? 不能直接赋值
int age;
int num;
};
int main()
{
struct MM mm;
必须采用字符串拷贝操作
strcpy(mm.name, "MM");
//mm.name[0] = 'A';
//mm.name[1] = '1';
//错误: mm.name="MM";
struct Boy yourBoy;
char inputName[20]; 用户去输入,临时变量暂时存储 name为指针时
printf("inputName:");
scanf("%s", inputName); 充分利用内存,可见长度
//--------------------------------------------------
yourBoy.name = (char*)malloc(strlen(inputName) + 1);
strcpy(yourBoy.name, inputName);
//--------------------------------------------------
yourBoy.age = 10;
yourBoy.num = 1001;
free(yourBoy.name);
yourBoy.name = NULL;
return 0;
}
六、内存对齐
C语言中不允许空的结构体
内存问题: 不对齐 所有内存之和
对齐的方式: 地址总线 寻址这一快
节省内存的写法:
字符当一个字节处理
从小到大写
具体去算字节数:按最长的对齐 3+1 4 8 3+5 8 4+4
#include <stdio.h>
#include <string.h>
struct MM
{
char name[3]; //3
int inum; //4
double num; //8
int age; //4
};
int main()
{
占用多少内存只和内存申请有关系
struct MM* pMM = (struct MM*)malloc(sizeof(struct MM));
printf("%d\n", sizeof(struct MM));
return 0;
}
七、联合体和枚举型
1.联合体—>共用体 一个东西
所有变量的共用最长的内存.
struct 关键字改为union 不能同时初始化全部的变量
每一次只能用一个 一般用在开关
2.枚举类型: 整形常量
项目一些具有代表性的常量的符号替换
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
union MM
{
char name[30];
int age;
int num;
};
项目一些具有代表性的常量的符号替换
enum direction {UP=72,DOWN=80,LEFT=75,RIGHT=77};
//默认的值:0 1 2....
//enum weekdays{一,二,三,四,五,六,七};
enum weekdays{一,二,三,四,五,六,七};
//局部的默认: 是前者的+1
enum COLOR {RED=1,BLACK,YELLOW=9,BLUE};
int main()
{
union MM myMM = { "10"};
strcpy(myMM.name, "1001");
printf("%s\n", &myMM.age);
myMM.age = 99;
printf("%d\n", myMM.age);
printf("%s\n", &myMM.name);
printf("%d\n", myMM.num);
printf("BLACK:%d\t,BLUE=%d\n", BLACK, BLUE);
while (1)
{
char userKey = _getch();
switch (userKey)
{
case UP:
printf("%d\t", 一);
break;
case DOWN:
printf("%d\t", 二);
break;
case LEFT:
printf("%d\t", 三);
break;
case RIGHT:
printf("%d\t", 四);
break;
}
}
return 0;
}
八、位段结构体
对所有变量的内存使用精准到二进制位 二极管
#include <stdio.h>
#include <string.h>
struct flag
{
unsigned int a : 2; //32λ 11 //3
unsigned int b : 3; //111 //7
unsigned int c : 4; //1111 //15
unsigned int d : 4; //1111 //15
};
int main()
{
struct flag myFlag = { 3,8,17,15 }; 超过之后从0开始
printf("%d\t%d\t%d\t%d\n", myFlag.a, myFlag.b, myFlag.c, myFlag.d);
return 0;
}