C学习--数据类型--构造类型--结构体解析/总结

  1. 结构体
  1. 意义

整数用int类型,浮点型用double,字符用char,多个同类型用数组...那么假设我要一个装学生信息的类型(姓名,年龄,学号...),也就是集多种类型于一身的类型,这就是结构体(可以类比是一个函数)

可以装数组、整型,字符串,浮点型等数据类型。

数组只能装同种类型的数据。

在实际项目中,结构体是大量存在的。研发人员常使用结构体来封装一些属性来组成新的类型。由于C语言内部程序比较简单,研发人员通常使用结构体创造新的“属性”,其目的是简化运算

封装的好处就是可以再次利用。

结构体的本质是数组,只是元素类型不同。

  1. 声明一个结构体类型
  1. 结构体组成

struct Stu

{

  char name[10];//名字4个字才8字节+\0,所以够

  int age;//年龄

  double high;//身高

  char Num[20];//学号

};

声明位置:在主函数外,所有函数都能使用;在函数内,在哪个函数,就只能在此函数使用,对外不可见

关键字:struct

结构题的名字:Stu不同的结构体 都是以名字区分,并且定义结构题变量 要用这个名字,唯一

花括号:结构体实体

结构体成员:name  age num等,类型个数不限制,以及同种类型重复次数不限制。定义方式跟普通变量一样

分号结尾:结构体不加报错。结构体不加结构体成员报错。

  1. 不加名字结构体

struct

{

    char name[10];

    int age;

    char Num[20];

};

不加名字使用比较受限制

就不能用名字正常定义变量了

  1. 声明、定义结构体变量
  1. 声明两种形式
  1. 在声明结构体类型的时候顺便声明变量
  1. 方式一:struct Stu

{

    char name[10];

    int age;

    char Num[20];

} stu1, stu2;//在结尾处声明变量

多个变量用逗号隔开

  1. 方式二:struct

{

    char name[10];

    int age;

    char Num[20];

}stu1 ,stu2;

这一种声明方式是不用写名字的

  1. 利用结构体名字声明变量

struct Stu stu3, stu4;

  1. strcut Stu == int
  2. 关键字struct和结构体名组合成一种类型标识符,其地位如同通常的int、char等类型标识符
  1. 定义

即声明的时候初始化

struct Stu//声明结构体

{

    char name[10];//名字4个字才8字节+\0,所以够

    int age;//年龄

    double high;//身高

    char Num[20];//学号

};

int main(void)

{

    struct Stu stu1 = {"王豪",25,1.73,"201921202094"};//声明、定义(初始化)变量

    system("pause");

    return 0;

}

  1. 原理跟数组初始化一样
  2. 依次初始化给对应的成员
  3. 初始化部分元素,其他的都给0
  4. 全局变量默认初始化0,局部变量随机
  1. 访问成员
  1. 结构体实例变量

实例变量:有空间的就是实例 struct Stu stu7;(类比:int  a)

取成员运算符:“.“,成员变量不能直接使用

取数据:stu1.name ,stu1.age, stu1.Num

char str[10];

stu7.name 跟 str是一样一样的,只不过不能直接使用name,需要用stu7.name

struct Stu//声明结构体

{

    char name[10];//名字4个字才8字节+\0,所以够

    int age;//年龄

    double high;//身高

    char xuehao[20];//学号

};

int main(void)

{

    struct Stu stu1 = { "王豪", 25, 1.73, "201921202094" };//声明、定义(初始化)变量

//结构体输出

    printf("%s %d %lf %s",stu1.name,stu1.age,stu1.high,stu1.xuehao);

    system("pause");

    return 0;

}

  1. 结构体指针变量

指针变量:就是指针struct Stu *p(类比:int *p)

取成员运算符:->

int main(void)

{

    struct Stu stu1 = { "王豪", 25, 1.73, "201921202094" };//声明、定义(初始化)变量

    printf("%s %d %lf %s\n",stu1.name,stu1.age,stu1.high,stu1.xuehao);

    struct Stu *p = &stu1;

    printf("%s %d %lf %s\n", p->name,p->age,p->high,p->xuehao);//p操作的是指向的这块空间

    system("pause");

    return 0;

}

  1. 指针2种使用方式

方式一: ->   p->name  p->age  p->Num 或者【(&stu7)->name;】都是地址访问。

方式二:.   (*p).name (*p).age  (*p).Num

     struct Stu stu1 = { "王豪", 25, 1.73, "201921202094" };//声明、定义(初始化)变量

     printf("%s %d %lf %s\n",stu1.name,stu1.age,stu1.high,stu1.xuehao);

     struct Stu *p = &stu1;

     printf("%s %d %lf %s\n", p->name,p->age,p->high,p->xuehao);

     printf("%s %d %lf %s\n", (*p).name, (*p).age, (*p).high, (*p).xuehao);

结果都是一样的!

地址访问用箭头;空间本身(实例)访问用点.

  1. 赋值
  1. 成员单个赋值

strcpy(stu7.name, "hello C3~")//字符                                                                                 数组 必须用 strcpy  / 循环

stu7.age = 18;

strcpy(stu7.Num, "20180101")

  1. 复合文字结构

赋值和初始化不同,赋值是后期,初始化是最开始的赋值。

c99 // 2013 2015 2017 支持

  1. 全部元素赋值:stu7 = (strcut stu){"小华", 12, "123456"}//类似结构体变量初始化

struct Stu stu = { .age = 27 };

struct Stu stu1 = { "王豪", 25, 1.73, "201921202094" };//声明、定义(初始化)变量

     stu1 = (struct Stu){ "小华", 12, 1.73,"201244155" };

     printf("%s %d %lf %s\n",stu1.name,stu1.age,stu1.high,stu1.xuehao);//结果:小华 12 1.730000 201244155

  1. 初始化指定元素

struct Stu stu = { .age = 27 };

  1. 其他类型成员
  1. 指针成员

struct Stu//声明结构体

{

                                                                              int *p;

};

                               int main(void)

{

                       int a [6] = {1,2,3,4,5};

                                                                                        struct Stu stu1 = { a };

      printf("%d   %d\n",stu1.p[0],stu1.p[2]);//stu1.p[]和a[]使用一样

                        syst            em("pause");

      return 0;

}

  1. 函数成员

           函   数不能  放在结构体中,所以想法:把函数地址(函数指针)放在其中,间接使用。

例子一:void fun(void)

{

     printf("i am  fun");

     }

struct Stu//声明结构体

{

     void(*p)(void);

     //int *p;

};

int main(void)

{

     struct Stu stu1 = { fun};//&fun或者fun是一样的,就是函数的地址

     (stu1.p)();//函数调用=地址+参数

system("pause");

     return 0;

system("pause");

     return 0;

 }

例子二:

void fun()

{

    printf ("hello c3");

}

strcut Teach

{

    void (*p)();

};

初始化:Struct teach  te = {fun};

调用:(te.p)();

  1. 结构体嵌套
  1. 嵌套结构体名字

取嵌套成员:tea.stu9.b

初始化:struct Teach tea = {12,{b}};里面用花括号进行初始化

赋值:Teach tea;

tea.stu9.b = 12;

struct Stu//声明结构体

{                                                                               

     char  name[10];

     int  age;

};

     struct teach

{

     char name[100];

     struct Stu  st;

     int age;

 

};

int main(void)

{

     struct teach  te = { "包老师", { "王豪", 27 }, 25 };//不加花括号也行 因为顺序已经确                                                     定了  加的话:比较清晰

     printf("%s,%s\n", te.st.name, te.name);

     //struct Stu stu1 = {};

     system("pause");

     return 0;

}

  1. 嵌套结构体结构体

也可以定义在结构体中

这种跟主函数的那种有些差别,这个在外边也可以直接使用

struct teach

{

     struct Stu//声明结构体

     {

           char  name[10];

           int  age;

     };

     char name[100];

     struct Stu  te1;

     int age;

};

int main(void)

{

     struct teach  te0 = { "包老师", { "王豪", 27 }, 25 };//不加花括号也行 因为顺序已经确定了  加的话:比较清晰

     printf("%s,%s\n", te0.te1.name, te0.name);

     //struct Stu stu1 = {};

     system("pause");

     return 0;

}

这个没有第一个清晰明白!

  1. 结构体数组

每一个元素都是结构体

struct teach

{

     char name[100];

     int age;

};

int main(void)

{

     struct teach  te0[3] = { { "包老师", 200 }, { "王豪", 27 }, { "豪", 29 }, };

     //不加花括号也行 因为顺序自动确定,会出错,加的话:比较清晰,且每个花括号里面可以自由初始化

     printf("%d,%s\n", te0[0].age ,te0[1].name);

     system("pause");

     return 0;

}

  1. 声明及初始化

struct Stu stu[3] = {{"小李",12,“1234”},{“小黄”,13, “1235”},{“小刘”, 25, “1236”}};

  1. 调用

stu[0].name  //类似数组调用

  1. 赋值

法一、strcpy(stu[0].name, "asd");//利用strcpy函数

法二、stu[0] = (struct Stu){"qqq", 34, "1237"};

  1. 结构体大小
  1. 字节对齐/内存对齐
  1. cpu处理数据
  1. CPU取数据是固定的方式:4/8字节的取读
  2. 32位cpu一次能处理的数据是32bit位  4字节
  3. 64位cpu一次能处理的数据是64bit位  8字节
  4. 起始地址是偶数:因为从0开始,+4 +4 /+8+8
  1. 对齐方式
  1. 跨段存储

假设数据挨着存储,char c, int a;就会出现:跨字节段存储

因此:cpu要读两次,把两次的组成一个数据,这样的跨段效率就低了

因此就出现了内存对齐方式

  1. 对齐存储

数据存储规则,假设我的数据按字节段存储 char c, int a;分别存在各自的字节段,每个数据cpu只需要读一次,就得到了

这种存储方式叫内存对齐

执行效率大大提高,但是会浪费一点儿空间

以上两种方式对比总结:空间换时间,时间换空间。二者不可兼得

  1. 结构
  1. sizeof()求大小

不是简单的所有成员大小之和

要涉及到内存对齐

  1. 计算规则

变量排列不同,大小字节数也不同,因为对齐顺序不同了。

1、以最大类型为字节对齐宽度

2、依次填补各个成员字节

3、偶地址开始,4字节对齐

4、结尾补齐(每个类型的结尾)

矩形对齐格!

struct teach

{

     double d;//8字节

     int age;//4

     short a;//2

     char k;//1

     char name[10];//这个是1字节,连续10个

};

  1. 上面的是最大类型8字节为模板
  1. 当然也可以手动设置模板

#pragma pack(1)

可以往小设置,不能设置比最大的大

但是我们一般不做设置,编译器会自动帮我们选择合适的对齐策略,了解即可。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值