十章——1 结构体笔记自存

结构体概念;

结构体是一种构造数据类型,像数组也是构造数据类型,但是数组是处理大量相同类型的数据运算,而结构体是一种或者多种构造类型的数据的集合。

结构体类型定义;

定义方法:在使用结构体前必须现有类型,然后用类型定义数据结构

方法一:先定义结构体类型,再去定义结构体变量

     struct 结构体类型名{

                    成员列表

};//记得加分号

struct stu {

     int num;

    char name[20];

     char sex;

};

有了结构体类型后,就可以用类型定义变量了;

struct stu lucy,bob,liel;//lucy,bob,liel这三个人你分别有了num,name,sex 这三个属性

方法二:在定义结构体类型的时候顺便定义结构体变量,以后还可以定义结构体变量

     struct 结构体类型名{

                    成员列表

};结构变量1,结构变量2;

struct 结构体类型名 变量3,变量4;

struct stu {

     int num;

    char name[20];

     char sex;

};lucy,bob,liel;

struct stu xiaohong,xiaoming ;

 方法三:在定义结构体类型的时候,没有结构体类型名,顺便定义结构体变量,因为没有类型名,所以以后不能再定义相关类型的数据了

struct  {

     int num;

    char name[20];

     char sex;

};lucy,bob,liel;

 方法四:最常用的方法

通常我们将一个结构体类型冲刺拿起一个类型名,用新的类型名替代原先的类型

步骤1:先用结构体类型定义变量

struct stu {

     int num;

    char name[20];

     char sex;

};bob;

 步骤二:新的类型名替代变量名

struct stu {

     int num;

    char name[20];

     char sex;

}STU;

 步骤三:在最前面加typedef

typedef struct stu{

     int num;

    char name[20];

     char sex;

}STU;

注意:步骤一和步骤二,在草稿上做的,步骤三是程序中我们需要的代码 

结构体变量的定义初始化及使用;

1结构体变脸的定义和初始化

结构体变量,是个变量,这个变量使若干个相同的或者不同的  数据构成的集合

注:

1:在定义结构体变量之前首先得有结构体类型,然后再定义变量

2:在定义变量的时候,可以顺便给结构体变量赋初值,称为结构体的初始化

3:结构体变量初始化的时候,各个成员顺序初始化

#include<stdio.h>
struct stu {
    int sum;
    char name[20];
    char sex;
};
int main()
{
    struct stu boy = {
        100,
        ,
        'm'//这样中间不赋值是不可以的,但是在最后(sex不赋值)不赋值是可以的
    }
    struct stu lucy = {
        101,
        "lucy",
        'm'//没有逗号
    };
    return 0;
}

2结构体变量的使用 

1:变量引用方法:结构体变量.成员名

#include<stdio.h>
#include<string>
struct stu {
    int sum;
    char name[20];
    char sex;
};
int main()
{
    struct stu bob;
    bob.num = 100;
    printf("bob.num=%d/n", bob.num);
     //bob.name='bob';错误,因为bob,name是个数组的名字,是个常量
    strcpy(bob.name, "bob");
    printf("bob.name=%s\n", bob.name);
    return 0;
}

   3结构体变量大小:变量大小是其所有成员之和

4结构体成员多级引用 

#include<stdio.h>
struct date {
    int year;
    int month;
    int day;
};
struct stu {
    int num;
    char name[20];
    char sex;
    struct date birthday;
};
int main()
{
    struct stu boy = {
        101,
        "lilei",
        'm'
    };
    boy.birthday. year = 2000;
    boy.birthday.month = 3;
    boy.birthday.day = 1;
    printf("%d %s %c\n", boy.num, boy.name, boy.sex);
    printf("%d %d %d\n", boy.birthday.year, boy.birthday.month, boy.birthday.day);
    return 0;
}

运行结果: 

101 lilei m
2000 3 1

C:\Users\86152\source\repos\实验四\x64\Debug\实验四.exe (进程 25936)已退出,代码为 0。
按任意键关闭此窗口. . .

5结构体变量的相互赋值:

相同类型的结构体变量才可以赋值

 

结构体数组;

结构体数组是一个数组,有若干个相同类型的结构体变量构成的集合;

1定义方法:

struct 结构体类型名 数组名【元素个数】

 struct stu {
    int num;
    char name[20];
    char sex;
};

struct stu edu[3];//定义了 struct stu类型的结构体数组edu,这个数组有三个元素,分别是edu[0],edu[1],edu[2].

2数组元素的使用 

edu[0].num=101;//把101赋值给edu[0];

strcpy(edu[1].name,"lucy");

#include<stdio.h>
typedef struct student {
    int num;
    char name[20];
    float score;
} STU;
int main()
{
    STU edu[3] = {
        {101,"lucy",78},
        {102,"bob",59.5},
        {103,"tom",85}
    };
    float sum = 0;
    int i;
    for (i = 0; i < 3; i++) {
        sum += edu[i].score;
    }
    printf("平均成绩为:%f\n", (float)(sum / 3));
        return 0;
}

结构体指针;

即结构体的地址,结构体变量存放在内存中,也有起始地址。咱们定义一个变量来存放这个地址,那么这个变量就是结构体指针变量。结构体指针变量是一个指针,指针变量占四个字节。

1定义方法

struct 结构体类型名 *结构体指针变量;

例:struct stu *p;//定义了一个struct stu*类型的指针变量

struct stu boy;

p=&boy;

2访问结构体变量的成员方法 

A:boy.num=101;//可以

B:(*p).num=101;//可以*p相当于p指向的变量boy

   C:p->num=101;//可以,指针->成员名//前提是指针必须先指向一个结构体变量

 

 3指针应用场景1:保存结构体变量的地址

  

4指针应用场景2:传 结构体变量的地址

#include<stdio.h>
#include<string>
typedef struct student {
    int num;
    char name[20];
    float score;
} STU;
void fun(STU* p) {//因为没有返回值所以用void
    p->num = 101;
    strcpy(p->name, "lucy");
    p->score = 88.6;//(*p.score=88.6);
}
int main()
{
    STU girl;
    fun(&girl);//把girl的地址传给fun函数
    printf("%d %s %f\n", girl.num, girl.name, girl.score);
    return 0;
}

 5指针应用场景3:传结构体数组的地址

结构体数组的地址就是第零个结构体的地址,

#include<stdio.h>
#include<string.h>
typedef struct student {
    int num;
    char name[20];
    float score;
} STU;
void fun(STU* p,int n) {//因为没有返回值所以用void
    int i;
    for (i = 0; i < n; i++) {
        printf("%d %s %f\n", p[i].num, p[i].name, p[i].score);
    }
}
int main()
{
    STU edu[3] = {
        {101,"lucy",88.3f},//f的作用是把double 型转化为float型
        {102,"bob",78.6f},
        {103,"lilei",93.7f}
    };
    fun(edu,3);
    return 0;
}

 6注意

A:结构体变量的地址编号和结构体第一个成员的地址编号相同,但指针的类型不同(STU*类型与int*类型)

B: 结构体数组的地址就是结构体数组中第零个元素的地址

 结构体内存分配;

结构体内存分配概述

结构体变量大小是它所有成员的大小之和

结构体内存分配规则1 以多少个字节为单位开辟内存

给结构体变量分配内存时,回去结构体变量中找基本类型的成员,那个类型的成员站的字节多就以他为大小开辟内存,但在gcc中出现double时例外   

1:成员中只有char 类型的,一个字节

2:最大short int ,以两个字节为单位开辟内存

3:in或者float最大,四个字节

4:出现了double类型的数据 

   A 在vc.6.0和VS中,以八个字节为单位开辟内存

   B在Linux环境gcc里,以四个字节为单位开辟

无论在那种环境double型变量占八个字节

如果在结构体中出现了数组,数组可以看成多个变量的集合

如果出现指针的话,没有占字节数更大的类型的,以四个字节为单位开辟内存

在内存中存储结构体成员的时候,按定义的结构体成员的顺序存储

结构体内存分配规则2 字节对齐

 1:char  1字节对齐,即存放char型的变量,内存单元的编号是一的倍数

 2:short int ,2字节对齐

 3:int 4字节对齐

 4:long int,4字节对齐

 5:float四字节对齐

 6:double

      A 在vc.6.0和VS中,以八个字节为对齐

      B gcc里,四个字节对齐

注意:1当结构体成员中出现数组时,可以看作多个变量

2开辟内存是从上向下一次按成员在结构体中的位置顺序开辟空间

 

 四个四个字节的开辟

字节对齐的目的

 用空间来换时间,提高cpu读取数据的效率

指定对齐原则

使用#pragme pack改变默认对齐原则,每一个编译器都有其默认的对齐原则,使用#pragme pack可以改变默认原则

格式:#pragme pack(value)时指定对齐值value

注意:1 value只能是1,2,4,8等2的指数

2:指定对齐值与数据类型对齐值相比取较小值

(1):以多少字节为单位开辟内存

           结构体成员中,占字节数最大的类型长度和value比较,取较小值,为单位开辟内存

#pragme pack(2)

       struct stu {

            char a;

            int b;

  };//以两字节位单位开辟内存                                                                   

位段

在结构体之中,以位为单位的成员,称之为位段

关于这个图,int类型以四字节开辟内存,而a,b,c,d加起来才占了十六位两个字节,所以有两个字节十六位被剩下 ,注意不能对位段成员取地址

 #include<stdio.h>
struct stu {
    unsigned int a : 2;//意思是a只占了两位,一个字节是八位
    unsigned int b : 6;
    unsigned int c : 4;
    unsigned int d : 4;
    unsigned int i ;
};
int main() {
    struct stu data;
    printf("sizeof(data)=%d\n", sizeof(data));

    printf("&data=%p\n", &data);
    printf("&(data.i)=%p\n", &(data.i));
    return 0;
}//验证上图

位段注意:

1、对于位段成员的引用如下:

     data.a=2

  赋值时,不要超出位段定义的范围;如段成员a定义为2位(二进制的两位),最大值为3,即(11)2

  所以data.a=5,就会取5的低二位进行赋值101,101就变成了01也就是1;

2、位段成员的类型必须指定为整形或字符型

3、一个位段必须存放在一个存储单元中,不能跨两个单元,第一个单元空间不能容纳下一个位段,则该空间不用,而从下一个单元起存放该位段


位段的存储单元

1、char类型位段,存储单元是一个字节

2、short int        2个字节

3、int    4个字节

4、long int 4个字节

struct stu{

      char a:7;

      char b:7;

      char c:2;

}temp;//七加七加二等于十六是两个字节,但是实际是占3个字节,因为b不能跨存储单元存储只能从下一个开辟的字节存放

结果为:3、证明位段不能跨其存储单元存储

注意:不能取temp.b(位段)的地址,因为b可能不够一个字节,不能取地址

4、位段的长度不能大于存储单元的长度

    (1):char型位段不能大于8为

    (2):short int 型 不能大于16位

    (3):int 的位段,不能大于32位

     (4):long int 的位段,位段不能大于32位

5、如一个段要从另一个存储单元开始,可以定义:

   unsighed char a:1;

   unsighed char b:2;

   unsighed char :0;

   unsighed char c:3;(另一个单元)

由于用了长度为0的位段,其作用是使下一个位段从下一个存储单元开始存放

将a,b存储在一个存储单元中,c另存在下一个单元中

6、可以定义无意义的位段,如

 unsighed a:1;

 unsighed :2;//这里指在a之后要浪费两位

 unsighed b:3;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值