0809结构体与共用体

 

结构体


背景:

如果我们要描述一个学生的成绩,学号,体重还有名字等,就应该定义以下的数据类型等来储存数据。

float score[30];
int sno[30];
float height[30];
char name[30][30];

那为了方便引用和使用一些复杂数据,于是便定义了结构体类型。
结构体类型 ---- 用来描述复杂数据的一种数据类型
 

一般语法:


struct 结构体名
{
   成员列表;
} ;

解释:

        (1) struct 关键字 
            表示 是在构造一个结构体的类型 
        (2) 结构体名    
            用来 描述 结构体这个类型 一个名称 
        (3) 成员列表 
            表示 要描述的复杂数据 中用到的 具体的成员变量
            定义的方式,与定义变量的方式相同,以字母,下划线,数字组成。
            多个成员变量之间,用分号隔开。
        (4) 最后 有一个 分号 表示 结束 

结构体类型的定义形式:


//形式1 先定义类型,然后定义变量 
struct demo
{}; 
struct demo d;

//形式2 定义类型的同时,定义变量 
struct demo
{
}d; //

//形式3 定义类型的同时,定义变量,可以省略 结构体名  
struct 
{
}d; //如果,结构体类型只用一次 

    

eg:
struct student 
{
    char name[30]; // 
    int sno;
    float score;
    char sex;  
}; //表示 定义出 一个 数据类型 


注意:
  1.结构体类型的使用的过程 
    a.先定义出类型
    b.定义变量
     struct 结构体名  变量名;
   


结构体初始化:


struct student s = {};

初始化
  看每个成员变量,具体是什么数据类型。
  根据 各个成员变量 自身的数据类型,进行初始化。
  初始化的顺序,按照定义的顺序,依次初始化

结构体变量的引用:
  //结构体数据 引用时,一般是引用到具体的成员数据 
  引用到成员 
  运算符 
     .   //结构体成员运算符 
     
使用:
   结构体变量名.成员名    //表示 访问 某个结构体 的成员 
练习:
   描述一个学生类型 

#include <stdio.h>

// 定义学生信息的结构体
typedef struct {
    char name[50];  // 学生姓名,假设最大长度为50个字符
    float weight;   // 学生体重,使用浮点数表示
    float score;    // 学生分数,使用浮点数表示
    int studentID;  // 学生学号,使用整数表示
} Student;

int main() {
    // 创建一个学生信息的实例
    Student stu = {
        .name = "张三",
        .weight = 60.5,  // 单位:千克
        .score = 89.5,   // 假设分数范围是0到100
        .studentID = 202401
    };

    // 打印学生信息
    printf("学生姓名: %s\n", stu.name);
    printf("学生体重: %.2f kg\n", stu.weight);
    printf("学生分数: %.2f\n", stu.score);
    printf("学生学号: %d\n", stu.studentID);

    return 0;
}

   
练习:


    准备3个学生的信息,
    求他们平均分 
 
   提示:

用 struct student s[3]; //结构体类型的数组 

           ->  指向结构体成员 运算符 
   
           结构体指针->成员名   
   
           结构体变量名.成员名   

 

#include <stdio.h>

// 定义学生信息的结构体
typedef struct {
    char name[50];
    float weight;
    float score;
    int studentID;
} Student;

int main() {
    // 创建三个学生信息的数组
    Student students[3] = {
        {"张三", 60.5, 89.5, 202401},
        {"李四", 55.0, 92.0, 202402},
        {"王五", 65.0, 88.0, 202403}
    };

    // 计算平均分
    float totalScore = 0.0;
    for (int i = 0; i < 3; i++) {
        totalScore += students[i].score;
    }
    float averageScore = totalScore / 3;

    // 打印平均分
    printf("三个学生的平均分是: %.2f\n", averageScore);

    return 0;
}


练习:
     打印出 成绩最高的学生的信息 
     

void IpStu(struct student *s[],int len)
{
    int i=0;
    
    for(i=0;i<len;i++)
    {
    printf("Input a Sno : ");
    scanf("%d",&s[i]->sno);
    printf("Input a sname: ");
    scanf("%s",s[i]->name);
    printf("Input a sex: ");
    scanf("%d",&s[i]->sex);
    printf("Input a score: ");
    scanf("%d",&s[i]->score);
    }

}
void printfTopOne(struct student *s,int len)
{
    int i;
    float temp=s->score;
    for(int j=1;j<len;j++)
    {
        if((s[j]->score) >temp)
        {
            i=j;
            temp=(s+j)->score;
        }
    }
    printf("sno= %d\n",s[i].sno);
    printf("sname= %s\n",s[i].name);
    printf("sex= %d\n",s[i].sex);
    printf("score= %d\n",s[i].score);
}
                                            
 int main()
 {
     int x;
 
     struct student s[3];
     IpStu(s,3);
     printfTopOne(s,3);          
     return 0;
 }
 #endif

怎么算结构体类型的大小

        成员大小:结构体的总大小是其所有成员大小的总和。

        内存对齐:编译器可能会在结构体的成员之间插入填充字节(padding),以确保每个成员都位于特定的内存地址边界上。这称为内存对齐,它通常取决于平台和编译器的设置。例如,如果一个成员需要4字节对齐,那么在它之前可能会插入1到3个字节的填充,以确保它的地址是4的倍数。

        结构体的对齐:结构体的总大小也受最大成员对齐要求的影响。编译器会选择结构体中最大成员的对齐要求作为整个结构体的对齐要求,并可能在最后一个成员之后插入填充,以确保结构体的总大小是该对齐要求的倍数。


        1.在32位的平台上,默认都是按4字节对齐的。 
        2.对于成员变量,
           各自在自己的自然边界上对齐。
           char  -- 1字节 
           short -- 2字节 
           int   -- 4字节 
        3.如果 成员变量中有比4字节大。      
          此时 整个结构体 按照4字节对齐。 //32位的平台 
        4.如果 成员变量中没有有比4字节大。  
          此时 整个结构体 按照最大的那个成员对齐。   
          //32位的平台   
          //如果有超过4字节 ,按照4字节对齐
          //如果没有超过4字节的,则按成员变量中最大对齐 
         ----------------------------------------------
          //64位的平台
          //如果超过4字节的,按超过的最大的成员变量对齐 
          //如果没有超过4字节的,则按成员变量中最大对齐

举例:

struct student
{
    int a;
    char s;
    short b;
};

//a占四个字节,char s 占一个,short占两个;但是最后的内存大小要是4的倍数(在32位下),所以是8个字节;

eg:
struct student
{
    int a;//4个
    char s;//1个
    long long b;//16
};
 //32位的平台 ,如果有超过4字节 ,按照4字节对齐。所以结果为24
 //64位的平台,如果超过4字节的,按超过的最大的成员变量对齐 ,所以结果为32;
       

注意:同类型的结构体变量之间 ,可以相互赋值 
struct student s1;
struct student s2;
s2 = s1; 


qsort()  

void qsort(
           void *base,    //要排序的数组的首地址 
           size_t nmemb,  //数组元素的个数 
           size_t size,   //单个元素的大小 
           int (*compar)(const void *, const void *) //比较函数 --- 提供比较依据
           );
功能:
    排序数组

 
    举例:对三个学生的分数进行排序;

struct student
 {
     int sno;
     char name[20];
     int sex;
     int score;

 };

int compar(const void *a,const void *b)
{
      const struct student *p=a;
      const struct student *q=b;
      return p->score*100 - q->score*100;
}

int main()
{

    struct student s[3]={{110,"li",1,87},{111,"hua",1,59},{112,"k",1,99}};
    qsort(s,3,sizeof(s[0]),compar);

    for (int i = 0; i < 3; i++)                                                                              
    {
          printf("sno: %d, name: %s, sex: %d, score: %d\n", s[i].sno, s[i].name, s[i].sex, s[i].score);
    }
    puts("\n");
    return 0;
}


    
  
        
 
共用体

共用体(Union)是一种特殊的数据类型
它允许在同一个内存位置存储不同的数据类型。
共用体的所有成员共享同一块内存空间,
因此同一时间只能存储其中一个成员的值。

共用体的定义和结构体类似,使用关键字union,后面跟着成员列表。
每个成员可以是不同的数据类型,

但共用体的所有成员都共享同一块内存空间,大小取决于最大的成员


   
语法:


  union 共用体名
  {
     成员变量;
  };
   
   

eg:
  union demo
  {
     char a;
     short b;
     int c;
  };


  
  共用体:
       共用了一块内存空间 
       公用了最大成员的空间 
       
  注意:
  1.共用体初始化时,只能给一个值,默认时给到第一个成员的。
  2.共用体变量中的值,取决与最后一次给到的值,还要看能影响几个字节。
  
  对比 结构体
  1.结构体中各个成员 拥有自己独立空间
  2.共用体中,成员共用一块空间
  

 
  
考点:
   用共用体 判断大小端
  
#include <stdio.h>


// 定义一个共用体,
typedef union {
    int i;
    char c;  
} EndianUnion;

// 函数用于判断大小端
int is_big_endian() {
    EndianUnion u;
    u.i = 1; // 将共用体的i成员设置为1
    return u.c == 1; // 如果c的值是1,则是大端
}

int main() {
    if (is_big_endian()) {
        printf("大端字节序 (Big-endian)\n");
    } else {
        printf("小端字节序 (Little-endian)\n");
    }
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值