C语言 - 结构体struct

结构体:struct,用户自己设计的 不同类型组合的 组合数据类型
        格式

        调用结构体
        结构体的打印
                指针与结构体的结合
                引用与结构体结合
        结构体的套接
        结构体:内存对齐
共用体:union,共用内存,达到对不同的类型进行解析的目的
        共用体的用法

//quesiton:如何实现CSDN博客间的跳转

格式:

    struct Student{
        char name[20];  //姓名
        int num[20];  //学号
        int age;  //年龄
        char group;  //所在学习小组
        float score;  //成绩
    };

调用结构体:

int main(){
    Student student; //定义结构体变量 
	
    student.s_age=22;//给结构体内部赋值

    student.s_name[20]="xiaoxuxu";  //×
    //结构体内若是一个数组或者字符串,不能直接赋值
    //需要用拷贝函数  
    strcpy(s1.s_name,"string");

    //可以整体打印? 答案:不可以
    //除了整体初始化外,其余的都是分开操作,一个一个打印出来
}
									

访问并修改结构体内部数据:

    1.逐个赋值: 使用 . (成员访问符)

    2.整体赋值: Student s1 = {"LU","201901",18,"A",80}; // 利用花括号整体一一对应初始化

                           //注意:结构体内部为int num[20];  赋值的时候是201901

                               //当结构体内部为char num[20]; 赋值的时候是"201901"

                           //注意:初始化时,不能跳着初始化(略过其中属性)

                        Student s2 = s1; //整体赋值 本质是调用内存拷贝函数 my_memmove(&s3,&s1,sizeof(Student));

 结构体的打印:

//值传递:直接开辟了一个Student类用来打印
void Print_Student(Student stu){printf: stu.s_name , stu.s_num....}
main:Print_Student1(stu1);

//指针:指针只开辟4个字节,相对节省空间,
    //缺点:为了防止不小心改变pstud的指向的内容 需要在前面加const 防止指向的内容被修改
    //缺点:使用指针 一定要判空,防止空指针的存在
void Print_Student1(Student const *pstud)
{
    if(NULL == pstud) return ; 
    printf: pstud->s_name , pstud->s_num....
}
main:Print_Student2(&stu1); //指针传递的是地址

//引用(起小名):避免开辟空间造成的空间浪费
void Print_Student1(Student const &stu){printf: stu.s_name , stu.s_num....}
main:Print_Student1(stu1);

              指针与结构体的结合:(指向作用  -> )

 ps ->s_age = 10; //ps指针指向s1
(*ps).s_age = 10; //等价
    //.和*的优先级  =>  .的优先级first

              引用与结构体结合:

//引用与结构体的结合:
    Student &s = s2;//定义了一个Student类的变量s2,给s2起小名叫s

结构体的套接:

          结构体可以套接结构体,但是函数不可以套接函数

                                                               (函数内部可以申明函数,不可以新定义一个函数)

//定义函数    //×
int Add(int x int y){ 
    return x+y;
}

//申明函数    //√
int Add(int x int y);
int fun(int ,int );

//结构体套接结构体:
struct Date
{
    int year;
    int month;
};
struct Student
{
    char s_id[20];
    struct Date birthday; //定义一个Date型的结构体变量 birthday 
};

//=========等价=========

struct Student
{
    char s_id[20];
    struct Date
    {
    int year;
    int month;
    }; 
    struct Date birthday; //struct 在.cpp文件中可以省略
};

结构体:内存对齐(存疑)

内存对齐遵循原则:

  1.当前成员所在的地址 能够整除 成员本身的字节大小 (不包括数组)
  2.结构体的整体大小能够能整除除成员最大基本类型 大小(不包括数组)         
  3.从零地址开始

另一种理解:
偏移量
:结构体中的偏移量就是结构体成员结构体变量地址之差
计算结构体大小的规则:
  1.每一个成员的偏移量都必须是该成员的倍数。
  2.结构体的大小必须是该结构体字节数最大成员的倍数。

例如下面的结构体:
struct A
 {
     char a;
     short b;
     int c;
 };
/*第一个成员的偏移量都是0;一般可以不看,a的大小为1,所以成员b的偏移量为1,b的大小
为2,1不是2的倍数,所以应该将1+1,成为2的倍数,成员c的偏移量就为1+1+2,是成员c的
倍数,现在就符合计算结构体大小的第一条:改成员的偏移量是该成员大小
的倍数,还有第二条规则:结构体大小是结构体最大成员的倍数,结构体的大小就是各个成员
之和,a;2,b:2,c:4加起来就是8,该结构最大成员为c大小为4,满足第二个条件,所以该结
构体的倍数就是8*/

参考博客:https://www.cnblogs.com/smile-812/p/7897187.html 

struct AA 
{ 
    char a;   // 1 + 3 
    short b; //  4
    int c;   // 4
    double d;  // 8
};  //16
 
struct A
{
    char a;   // 1 + 3   [0,1,2,3] (1,2,3浪费)
    int b;    // 4  [4,5,6,7]
}; //[0-7]  大小为8,向前对齐
 
struct A1
{
    char a;   //1
    char c;   //1 
    int b;    //4  
}s; // 大小为8
 
struct B
{
    char a;   //1 + 1  [0,1]
    short b;  //2  [2,3]
    int c;    // 4  [4,5,6,7]
}; //   [0-7]大小为8,向前对齐
 
struct C
{
    char a;   // 1 + 3  [0,1,2,3]
    int b;    // 4  [4,5,6,7]
    short c;  // 2 + 6  [8-15]
    double d; // 8  [16-23]
}; // [0-23]大小为24,向前对齐
 
struct D
{
    char a;   // 1 [0]
    char b;   // 1 [1]
    short c;  // 2 [2,3]
    int d;    // 4 [4,5,6,7]
}; // [0-7]大小为8,向前对齐
 
struct E
{
    char a;   // 1 + 1 [0,1]
    short c;   // 2 [2,3]
    char b;  // 1 + 3 [4,5,6,7]
    int d;  // 4 [8,9,10,11]
}; // [0-11]大小为12,向前对齐
 
struct F
{
    int a;  // 4 [0,1,2,3]
    char c; // 1 + 3  [4,5,6,7]
}; //[0-7]大小为8,向后对齐,一般只有两个数据成员
 
struct G
{
    char ch[17];  //17 + 3  20能被4整除
    int i; // 4
    float f; //4
}su;  // 大小为28
 
struct H
{
    char  a;  //1 +1
    short b;   //2
    char  c;  //1 +3
    int   d;  //4
    char  e[3]; //3 +1
};   // 大小为16

干预内存对齐:
#pragma pack(n)  // n = 1,2,4,8,16
                             //n = 1;强制要求内存按照1字节对齐;

共用体:

共用体:共用内存 ;; 最主要的用途 : 对不同的类型进行解析
结构体:自己独占内存,所占内存是各成员占用内存长度之和(存在内存对齐)

union A{
    char a;
    short b;
    int c;
};
struct B{ 
    char a;
    short b;
    int c;
};

int main(){
    A x1;
  //x1.a = 'a'; //这里内存互相侵占了 
  //x1.b = 12;
		
    B x2;
    x2.a = 'a'; //自己用自己的 不影响 
    x2.b = 12;
} 

共用体的用法:

 共用体的用法:对同一个空间按不同类型去识别
    //共用体可以套用结构体
    //结构体可以套用联合体

//直接使用共用体
union Node{
    unsigned int addr;
    unsigned char s1,s2,s3,s4; 
    //对于联合体而言s1,s2,s3,s4都用的是同一个字节  
};

//共用体套用结构体 
union Node{
    unsigned int addr;
    sruct{
    unsigned char s1,s2,s3,s4; //分布于四个字节了 
    };
}

//结构体套用共用体
struct Node{
    char ch;
    union{ //无名共用体:哑元结构 
        int a; //a和f共享同一个内存 
        float f;
        };//1+4 =6 凑/4 =>8个字节 
};

//这里还需深一步理解,为何要这么做! 每种结构都有什么好处

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值