当前位置 博文首页 > CW_qian的博客:8月22日笔记C语言基础(补1)结构体2

    CW_qian的博客:8月22日笔记C语言基础(补1)结构体2

    作者:[db:作者] 时间:2021-08-25 21:44

    1.结构体概念的引入
    ?? ?c语言提供了众多的数据类型,但是这些数据类型远远达不到我们的需求
    ?? ?比如描述学生,学生信息 : 姓名,性别,年龄。。。。,那么我们通过
    ?? ?什么数据类型描述学生信息呢?答案是自定义数据类型,结构体。
    ?? ?
    ?? ?结构体其实是一种复合数据类型


    ?? ?什么是结构体?为什么要用结构体
    ?? ?结构体其实就是自定义数据类型,方便我们更好的管理数据


    2.结构体的定义
    ?? ?struct ?结构体名
    ?? ?{
    ?? ??? ?成员类型1 成员名1; int a;
    ?? ??? ?成员类型2 成员名2;
    ?? ??? ?成员类型3 成员名3;
    ?? ?};
    ?? ?语法:
    ?? ??? ?结构体名是用来区分不同的结构体
    ?? ??? ?成员,是包含在结构体内部的数据,只在这个结构体有效
    ?? ??? ??? ?可以是任意数据类型
    ?? ?demo:

    ?struct student
    ?? ?{
    ?? ??? ?char name[20]; // 姓名
    ?? ??? ?char sex; // 性别
    ?? ??? ?int age; // 年龄
    ?? ?};

    ? struct student 是我们定义的一个全新的数据类型,名为struct student
    ?? ?这个数据类型包含了姓名,性别,年龄

    ?// 使用方式
    ?? ?int main()
    ?? ?{
    ?? ??? ?struct student st;
    ?? ?}


    3.结构体初始化
    ?? ?1.普通初始化
    ?? ??? ?// 给结构体分配栈空间的同时初始化
    ?? ??? ?// 普通初始化,必须将结构体里面的内容全部初始化
    ?? ??? ?struct student st = {"Jack",'m',18};
    ?? ??? ?
    ?? ??? ?// 将结构体的里面的内容打印出来
    ?? ??? ?// 如果栈空间分配内存为普通变量,一般访问结构体里面的成员用符号(.)访问
    ?? ??? ?printf("%s,%c,%d\n",st.name,st.sex,st.age);
    ? ? //scanf("%s,%c,%d\n",st.name,&st.sex,&st.age);
    ?? ?2.指定成员初始化
    ?? ??? ?// 指定成员初始化

    ?? ??? ?struct student st1 = {
    ?? ??? ??? ?.name = "Rose",
    ?? ??? ??? ?//.sex = 'w', // 正确
    ?? ??? ??? ?.age = 18
    ?? ??? ?};
    ?? ??? ?printf("%s,%c,%d\n",st1.name,st1.sex,st1.age);? ??

    ? ?3.定义结构体的时候初始化

    ?????????struct student
    ?? ??? ?{
    ?? ??? ??? ?char name[20];
    ?? ??? ??? ?char sex;
    ?? ??? ??? ?int age;
    ?? ??? ?}st2 = {"xiaoming",'M',19};
    ?? ??? ?// 定义结构体的时候就初始化
    ?? ??? ?printf("%s,%c,%d\n",st2.name,st2.sex,st2.age);

    4.多结构体使用?

    // 定义struct date类型
    ?? ?struct date
    ?? ?{
    ?? ??? ?int y; // 年
    ?? ??? ?int m; // 月
    ?? ??? ?int d; // 日
    ?? ?};

    ?? ?struct student
    ?? ?{
    ?? ??? ?int age;
    ?? ??? ?// 使用struct date
    ?? ??? ?// 给struct date 分配栈空间
    ?? ??? ?struct date birthday;
    ?? ??? ?//struct student // 重复定义
    ?? ?};
    ?? ?// 普通初始化
    ?? ?int main()
    ?? ?{
    ?? ??? ?// 普通初始化
    ?? ??? ?struct student st = {18,2003,9,19};
    ?? ??? ?printf("%d---%d/%d/%d\n",
    ?? ??? ??? ?st.age,
    ?? ??? ??? ?st.birthday.y,
    ?? ??? ??? ?st.birthday.m,
    ?? ??? ??? ?st.birthday.d
    ?? ??? ??? ?);
    ?? ??? ?return 0;
    ?? ?}
    ?? ?
    ?? ?//-------------------------?? ?
    ?? ?// 指定成员初始化?? ?
    ?? ?int main()
    ?? ?{?? ?
    ?? ??? ?// 指定成员初始化?? ?
    ?? ??? ?struct student st1 = {
    ?? ??? ??? ?.age = 19,
    ?? ??? ??? ?.birthday.y = 2003,
    ?? ??? ??? ?.birthday.m = 10,
    ?? ??? ??? ?.birthday.d = 11,
    ?? ??? ?};
    ?? ??? ?printf("%d---%d/%d/%d\n", \
    ?? ??? ??? ?st1.age, \
    ?? ??? ??? ?st1.birthday.y, \
    ?? ??? ??? ?st1.birthday.m, \
    ?? ??? ??? ?st1.birthday.d
    ?? ??? ??? ?);?? ?
    ?? ??? ??? ?
    ?? ??? ?return 0;
    ?? ?}

    5.结构体成员引用
    ?? ?结构体成员的引用和普通变量使用没有任何区别

    ?struct student
    ?? ?{
    ?? ??? ?char name[20];
    ?? ??? ?int age;
    ?? ??? ?char sex;
    ?? ?};

    ?? ?int main()
    ?? ?{
    ?? ??? ?struct student st;
    ?? ??? ?// 错误,不能直接给数组赋值
    ?? ??? ?//st.name = "jack";
    ?? ??? ?strcpy(st.name,"jack");
    ?? ??? ?char buf[20];
    ?? ??? ?//buf = "Rose";// 错误的
    ?? ??? ?strcpy(buf,"Rose");
    ?? ??? ?st.age = 18;
    ?? ??? ?st.sex = 'm';
    ?? ??? ?
    ?? ??? ?printf("%d,%c,%s\n",st.age,st.sex,st.name);
    ?? ??? ?
    ?? ??? ?return 0;
    ?? ?}

    6.结构体指针,重点
    ?? ?和普通变量的指针没有任何区别
    ?? ?demo:? ?

    ?struct student
    ?? ?{
    ?? ??? ?char name[20];
    ?? ??? ?int age;
    ?? ??? ?char sex;
    ?? ?};

    ?? ?int main()
    ?? ?{
    ?? ??? ?// 需要分配堆空间,否则段错误
    ?? ??? ?struct student *st = malloc(sizeof(struct student));
    ?? ??? ?// 注意结构体指针访问成员的时候是用符号(箭头)表示
    ?? ??? ?strcpy(st->name,"jack");
    ?? ??? ?printf("%s\n",st->name);
    ?? ??? ?
    ?? ??? ?
    ?? ??? ?// 释放堆空间
    ?? ??? ?free(st);
    ?? ??? ?st = NULL;
    ?? ??? ?
    ?? ??? ?struct student a;
    ?? ??? ?struct student *q = &a;
    ?? ??? ?(*q).age = 18;// ==> a.age;
    ?? ??? ?int d = 10;
    ?? ??? ?int *p = &d; // *p = 10;d = 10
    ?? ??? ?q->age = 18;
    ?? ??? ?
    ?? ??? ?printf("%d\n",q->age); // 指针访问成员用箭头->
    ?? ??? ?printf("%d\n",(*q).age); // 普通变量访问成员用.
    ?? ??? ?
    ?? ??? ?return 0;
    ?? ?}


    7.结构数组

    ? ? ?int a[5]; a[0] = 1; a[1] = 2; a[2] = 3;
    ?? ?struct student class[5];
    ?? ?
    ?? ?// 结构体数组普通初始化
    ?? ?struct student
    ?? ?{
    ?? ??? ?char name[20];
    ?? ??? ?int age;
    ?? ??? ?int score;
    ?? ?}st[3] = {
    ?? ??? ?{"jack",18,80},
    ?? ??? ?{"Rose",17,85},
    ?? ??? ?{"xiaoming",19,60}
    ?? ?};
    ?? ?void main()
    ?? ?{
    ?? ??? ?printf("%s,%d,%d\n",st[0].name,st[0].age,st[0].score);
    ?? ??? ?printf("%s,%d,%d\n",st[1].name,st[1].age,st[1].score);
    ?? ??? ?printf("%s,%d,%d\n",st[2].name,st[2].age,st[2].score);
    ?? ?}
    ?? ??? ?
    ?? ?// 结构体数组指定成员初始化
    ?? ?struct student1
    ?? ?{
    ?? ??? ?char name[20];
    ?? ??? ?int age;
    ?? ??? ?int score;
    ?? ?};
    ?? ?
    ?? ?void main()
    ?? ?{
    ?? ??? ?// 指定成员初始化
    ?? ??? ?struct student class[3] = {
    ?? ??? ??? ?//class[0]
    ?? ??? ??? ?{
    ?? ??? ??? ??? ?.name = "jack",
    ?? ??? ??? ??? ?.age = 18,
    ?? ??? ??? ??? ?.score = 90
    ?? ??? ??? ?},
    ?? ??? ??? ?//class[1]
    ?? ??? ??? ?{
    ?? ??? ??? ??? ?.name = "jack",
    ?? ??? ??? ??? ?.age = 18,
    ?? ??? ??? ?},
    ?? ??? ??? ?//class[2]
    ?? ??? ??? ?{
    ?? ??? ??? ??? ?.name = "jack",
    ?? ??? ??? ??? ?.score = 18,
    ?? ??? ??? ?}
    ?? ??? ?};
    ?? ?
    ?? ??? ?printf("%s,%d,%d\n",class[0].name,class[0].age,class[0].score);
    ?? ??? ?printf("%s,%d,%d\n",class[1].name,class[1].age,class[1].score);
    ?? ??? ?printf("%s,%d,%d\n",class[2].name,class[2].age,class[2].score);
    ?? ?}
    ?? ?
    ?? ?// 引用结构体数组里面的成员
    ?? ??? ?struct student1
    ?? ??? ?{
    ?? ??? ??? ?char name[20];
    ?? ??? ??? ?int age;
    ?? ??? ??? ?int score;
    ?? ??? ?};
    ?? ??? ?void main()
    ?? ??? ?{
    ?? ??? ??? ?struct student class1[3];
    ?? ??? ??? ?strcpy(class1[0].name,"jack");
    ?? ??? ??? ?
    ?? ??? ??? ?class1[0].age = 18;
    ?? ??? ??? ?class1[0].score = 90;
    ?? ??? ??? ?printf("%s,%d,%d\n",class1[0].name,class1[0].age,class1[0].score);
    ?? ??? ??? ?
    ?? ??? ??? ?scanf("%s%d%d",(class1+1)->name,&class1[1].age,&class1[1].score);
    ?? ??? ??? ?scanf("%s%d%d",(*(class1+1)).name,&class1[1].age,&class1[1].score);
    ?? ??? ??? ?printf("%s,%d,%d\n",class1[1].name,class1[1].age,class1[1].score);
    ?? ??? ?
    ?? ??? ?}



    //练习2:
    //?? ?定义一个学生信息结构体数组(数组元素的个数由用户决定),依次从键盘输入每个学生
    //?? ?信息(姓名,成绩),按成绩的降序输出每个学生的信息,降序算法最好是自己封装函数
    //?? ?dmeo:
    ?? ?#include <stdio.h>
    ?? ?#include <string.h>
    
    ?? ?struct student
    ?? ?{
    ?? ??? ?char name[20];
    ?? ??? ?int score;
    ?? ?};
    
    ?? ?void sort(struct student *st,int len)
    ?? ?{
    ?? ??? ?int tmp;
    ?? ??? ?char tName[20] = {0};
    ?? ??? ?
    ?? ??? ?for(int i = 0; i < len-1;i++)
    ?? ??? ?{
    ?? ??? ??? ?for(int j = 0; j < len-i-1; j++)
    ?? ??? ??? ?{
    ?? ??? ??? ??? ?if(st[j].score < st[j+1].score)
    ?? ??? ??? ??? ?{
    ?? ??? ??? ??? ??? ?tmp = st[j].score;
    ?? ??? ??? ??? ??? ?strcpy(tName,st[j].name);
    ?? ??? ??? ??? ??? ?
    ?? ??? ??? ??? ??? ?st[j].score = st[j+1].score;
    ?? ??? ??? ??? ??? ?strcpy(st[j].name,st[j+1].name);
    ?? ??? ??? ??? ??? ?
    ?? ??? ??? ??? ??? ?st[j+1].score = tmp;
    ?? ??? ??? ??? ??? ?strcpy(st[j+1].name,tName);
    ?? ??? ??? ??? ??? ?
    ?? ??? ??? ??? ?}
    ?? ??? ??? ?}
    ?? ??? ?}
    ?? ??? ?
    ?? ??? ?
    ?? ?}
    
    ?? ?int main()
    ?? ?{
    ?? ??? ?struct student st[3];
    ?? ??? ?
    ?? ??? ?for(int i = 0;i < 3;i++)
    ?? ??? ??? ?scanf("%s%d",st[i].name,&st[i].score);
    ?? ??? ?
    ?? ??? ?int len = sizeof(st) / sizeof(struct student);
    ?? ??? ?
    ?? ??? ?sort(st,len);
    ?? ??? ?
    ?? ??? ?for(int i = 0; i < len; i++)
    ?? ??? ??? ?printf("%s,%d\t",st[i].name,st[i].score);
    ?? ??? ?
    ?? ??? ?printf("\n");
    ?? ??? ?
    ?? ??? ?return 0;
    ?? ?}


    8.结构体封装
    ?? ?结构体一般都是在头文件定义
    ?? ?demo:

    ?? ?#ifndef _MYHEAD_H
    ?? ?#define _MYHEAD_H

    ?? ?#include <stdio.h>
    ?? ?#include <stdlib.h>

    ?? ?typedef int dataType;
    ?? ?//typedef int * pdataType;

    ?? ?//int data;// == dataType data;

    ?? ?//int *p; // == pdataType p;


    ?? ?// 定义结构体类型
    ?? ?typedef struct node
    ?? ?{
    ?? ??? ?int age;
    ?? ??? ?char sex;
    ?? ??? ?dataType data;
    ?? ??? ?
    ?? ?}newNode,*pnewNode;// 等价于 typedef struct node newNode; ?typedef struct node *pnewNode

    ?? ?#endif
    //------------------------------------
    ?? ?#include "myhead.h"

    ?? ?int main()
    ?? ?{
    ?? ??? ?//struct node myNode;
    ?? ??? ?newNode myNode;
    ?? ??? ?myNode.age = 18;
    ?? ??? ?myNode.sex = 'M';
    ?? ??? ?myNode.data = 123;
    ?? ??? ?printf("%d,%c,%d\n",myNode.age,myNode.sex,myNode.data);


    ?? ??? ?//struct node *newNode;
    ?? ??? ?pnewNode newNode = NULL; // 指针变量
    ?? ??? ?newNode = malloc(sizeof(pnewNode));
    ?? ??? ?newNode->age = 18;
    ?? ??? ?newNode->sex = 'W';
    ?? ??? ?newNode->data = 456;
    ?? ??? ?printf("%d,%c,%d\n",newNode->age,newNode->sex,newNode->data);
    ?? ??? ?return 0;
    ?? ?}

    总结:
    ?? ?此处typedef如果用在结构体上,可以将这个结构体类型
    ?? ?改为普通变量类型,也可以改为指针变量类型,这样的
    ?? ?好处是第一可以增加代码的可读性,第二让结构体使用起来
    ?? ?比较方便


    9.字节对齐(笔试题考的较多)
    问题引入?
    ?? ?int a; // 4字节
    ?? ?char b; // 1字节
    ?? ?short c;// 2字节
    ?? ?
    ?? ?那么
    ?? ?struct node
    ?? ?{
    ?? ??? ?int a; // 4
    ?? ??? ?char b; // 1
    ?? ??? ?short c; // 2
    ?? ??? ?
    ?? ?};
    ?? ?sizeof(struct node)大小??
    ?? ?
    ?? ?struct node
    ?? ?{
    ?? ??? ?char a; // 1
    ?? ??? ?char b; // 1
    ?? ??? ?short c; // 2
    ?? ?};
    ?? ?
    ?? ?字节对齐概括:
    ?? ??? ?系统为了提高执行效率,计算机从内存中取数据是按照固定的长度取的,比如
    ?? ??? ?32位系统是最大4字节取数据(注意字节对齐方式是可以手动修改),如果是64位系统得看数据的最大长度(long double),如果数据
    ?? ?
    ?? ?结构体的存储数据的方式是以成员的最大值为参考值俗称M值
    ?? ??? ?结构体的M值是以对应成员的最大值决定,当然32位系统的M值最大为4
    ?? ??? ?例如:
    ?? ??? ?struct node
    ?? ??? ?{
    ?? ??? ??? ?short a; // 尺寸=2,M值为2
    ?? ??? ??? ?double b; // 尺寸=8;32位系统下M值为4,64位系统M值为8
    ?? ??? ??? ?char c; // 尺寸=1,M值为1
    ?? ??? ?};
    ?? ??? ?struct node n;
    ?? ??? ?32位系统 M值 = max{2,4,1} = 4?
    ?? ??? ??? ?4+8+4 = 16? ? ? ? 16/m=0
    ?? ??? ??? ?
    ?? ??? ?64位系统 M值 = max{2,8,1} = 8?
    ?? ??? ??? ?8+8+8 = 24????????24/m=0?? ?
    ?? ??? ??? ?
    ?? ??? ??? ?
    ?? ?字节对齐总结
    ?? ??? ?1.找结构体里面最大的M值
    ?? ?2.在将结构体里面的数据从上往下依次按照自己的M值方式存储,如果存的地址大于M值,就换行


    ? ? 将结构体的空间大小设置成实际成员空间之和
    ?? ?#pragma pack(1) // 将M值设置为1,将此文件下的所有结构体大小设置为实际成员的大小之和
    ?? ?struct node2
    ?? ?{
    ?? ??? ?short a;?
    ?? ??? ?
    ?? ??? ?char c;
    ?? ??? ?
    ?? ??? ?double b;

    ?? ?}__attribute__((packed));
    ?? ?
    ?? ?__attribute__((packed))的作用是将结构体大小设置为实际成员大小之和


    设置结构体成员的M值、

    ? ?#include <stdio.h>
    ?? ?#include <stdint.h>
    ?? ?struct node?
    ?? ?{
    ?? ??? ?int8_t a __attribute__((aligned(16))); // 其实就是char类型 ?1字节
    ?? ??? ?int64_t b __attribute__((aligned(8)));// 其实就是 long 类型 ?8字节
    ?? ??? ?int16_t c __attribute__((aligned(2)));// 其实就是short类型 ? 2字节
    ?? ??? ?
    ?? ?};

    ?? ?int main()
    ?? ?{
    ?? ??? ?struct node st;
    ?? ??? ?printf("%ld\n",sizeof(int8_t));
    ?? ??? ?printf("%ld\n",sizeof(int64_t));
    ?? ??? ?printf("%ld\n",sizeof(int16_t));
    ?? ??? ?
    ?? ??? ?printf("%ld\n",sizeof(st));
    ?? ??? ?
    ?? ??? ?
    ?? ??? ?return 0;
    ?? ?}
    ?



    ? ??

    cs