C语言基础之结构体

news2025/1/9 1:28:35

文章目录

  • 一、结构体
    • 1、结构体概述
    • 2、结构体类型的定义方式
      • (1)先定义结构体类型,再定义结构体变量
      • (2)结构体类型、变量同时定义
      • (3)一次性结构体
    • 3、结构体成员的初始化
      • (1)结构体初始化
      • (2)清空结构体
      • (3)键盘给结构体赋值
    • 4、结构体成员操作
    • 5、相同类型的结构体操作
    • 6、结构体嵌套
    • 7、结构体数组
    • 8、结构体指针变量
    • 9、结构体数组元素的指针
    • 10、结构体的指针指向堆区空间
    • 11、结构体深层拷贝
    • 12、结构体与结构体成员都在堆区
    • 13、结构体对齐
      • (1)结构体自动类型对齐
      • (2)结构体嵌套结构体 自动对齐规则
      • (3)结构体强制对齐
    • 14、位域
  • 二、共用体
  • 三、枚举enum

一、结构体

1、结构体概述

将多种数据结构封装在一起 形成新的结构叫结构体

每种数据结构 都有自己独立的空间

结构体的关键字 struct

2、结构体类型的定义方式

(1)先定义结构体类型,再定义结构体变量

struct str
{
    int num;//结构体成员
    char name;
};
struct str array;//定义结构体变量

(2)结构体类型、变量同时定义

struct str
{
    int num;//结构体成员
    char name;
}array;//定义结构体变量
struct str data;//定义结构体新变量

(3)一次性结构体

struct 
{
     int num;   
}asd;//定义变量

3、结构体成员的初始化

(1)结构体初始化

#include <stdio.h>

struct stu
{
    int num;
    char str[128];
    int data[32];
};
int main(int argc, char const *argv[])
{
    struct stu array = {100,"hello",{200,300}};
    printf("%d %s %d\n",array.num, array.str, array.data[1]);
    return 0;
}

(2)清空结构体

#include <stdio.h>
#include <string.h>
struct stu
{
    int num;
    char str[128];
    int data[32];
};
int main(int argc, char const *argv[])
{
    struct stu array;
    memset(&array,0,sizeof(array));
    printf("%d\n",sizeof(array));//260 = 1*4+128+32*4
    return 0;
}

(3)键盘给结构体赋值

#include <stdio.h>
#include <string.h>
struct stu
{
    int num;
    char str[128];
    int data[32];
};
int main(int argc, char const *argv[])
{
    struct stu array;
    memset(&array,0,sizeof(array));
    scanf("%d %s",&array.num, array.str);//键盘获取内容
    printf("%d  %s\n",array.num, array.str);
    return 0;
}
#include <stdio.h>
#include <string.h>
struct date
{
    int num;
    char str[128];
};
int main(int argc, char const *argv[])
{
    struct date arr[3];
    memset(arr,0,sizeof(arr));
    int n = sizeof(arr)/sizeof(arr[0]);

    //获取键盘数组
    printf("请输入%d个学生信息num str\n",n);
    int i = 0;
    for ( i = 0; i < n; i++)
    {
        scanf("%d %s",&arr[i].num,arr[i].str);
    }
    
    for ( i = 0; i < n; i++)
    {
        printf("%d %s\n",arr[i].num,arr[i].str);
    }   
}

4、结构体成员操作

int类型

zxc.num +=100;

char类型

strcpy(zxc.str,"name");

5、相同类型的结构体操作

#include <stdio.h>
#include <string.h>
struct stu
{
    int num;
    char str[128];
    int data[32];
};
int main(int argc, char const *argv[])
{
	struct stu array = {100,"hello",200};
    struct stu array2;
    #if 1
    //方式一;成员逐个赋值
        array2.num = array.num;
        *array2.data = *array.data;
        strcpy(array2.str,array.str);
    #elif 0
    //方式二;相同类型的结构体变量,可以直接赋值
        array2 = array;
    #else
    //方式三
    memcpy(&array2,&array,sizeof(array));

    #endif
    printf("%d %s %d\n",array2.num,array2.str, *array2.data);
    return 0;
}

6、结构体嵌套

#include <stdio.h>
#include <string.h>
struct stu
{
    int num;
    char str[128];
    int data[32];
};
struct date
{
    int year;
    int month;
    int day;
    struct stu ob;
};
int main(int argc, char const *argv[])
{
	struct date lucy = {2023,07,28,{666,"xixi",999}};
    printf("year=%d month=%d day=%d\n",lucy.year,lucy.month,lucy.day);
    printf("str = %s data = %d\n",lucy.ob.str,*lucy.ob.data);
    return 0;
}

结果:

year=2023 month=7 day=28
str = xixi data = 999

7、结构体数组

#include <stdio.h>
#include <string.h>
struct stu
{
    int num;
    char name[128];
};
int main(int argc, char const *argv[])
{
	struct date2 arr[3] = {{100,"qwe"},{232,"asdas"},{7897,"ksjs"}};
    int n = 0;
    n = sizeof(arr)/sizeof(arr[0]);
    
    int i = 0;
    for ( i = 0; i < n; i++)
    {
        printf("%d  %s\n",arr[i].num,arr[i].name);
    } 
    return 0;
}

8、结构体指针变量

结构体指针变量 本质是指针变量 保存的是结构体变量的地址

p->num 根据地址获取num

(*p).num

左边是 地址 使用 ->

左边是 变量 使用 .

#include <stdio.h>
#include <string.h>
struct stu
{
    int num;
    char str[128];
    int data[32];
};
int main(int argc, char const *argv[])
{
	struct stu ob = {100,"xixi",200};
    struct stu *p = &ob;
    printf("%d %s %d\n",p->num,p->str,*(*p).data);
    return 0;
}

9、结构体数组元素的指针

#include <stdio.h>
#include <string.h>
struct data
{
    int num;
    char str[128];
};
void input_stu_data(struct data *arr,int n)
{
    printf("请输入%d个学生信息num arr\n",n);
    int i = 0;
    for ( i = 0; i < n; i++)
    {
        printf("请输入第%d个学生信息:",i+1);
        scanf("%d %s",&(arr+i)->num,arr[i].str);
    }   
    return;
}
void sort_arr_array(struct data *arr ,int n)
{
    int i = 0;
    for ( i = 0; i < n-1; i++)
    {
        int min = i;
        int j = min +1;
        for ( ; j < n; j++)
        {
            if(arr[min].num>arr[j].num)
                min = j;
        }
        if(i != min)
        {
            struct data tmp = arr[min];
            arr[min] = arr[i];
            arr[i] = tmp;
        }
    }
    return;
}
int main(int argc, char const *argv[])
{
    struct data arr[5];
    memset(arr,0,sizeof(arr));

    int n = sizeof(arr)/sizeof(arr[0]);
    //键盘输入
    input_stu_data(arr,n);
    //对结构体数组排序
    sort_arr_array(arr , n);
    int i = 0;
    for ( i = 0; i < n; i++)
    {
        printf("%d %s\n",arr[i].num,arr[i].str);
    }
    return 0;
}

10、结构体的指针指向堆区空间

当结构体有指针成员时须为其申请指针空间

#include <stdio.h>
#include <string.h>
struct stu
{
    int num;
    char *name;
};
int main(int argc, char const *argv[])
{
    struct stu lucy;
    lucy.num = 100;
    lucy.name = (char *)calloc(1,128);//申请空间
    strcpy(lucy.name, "hellow world");
    printf("%d %s\n",lucy.num,lucy.name);
    printf("%c\n",lucy.name[1]);
    lucy.name[1] = 'D';
    printf("%d %s\n",lucy.num,lucy.name);
    //释放lucy.name指向的堆区空间
    if(lucy.name != NULL)
    {
        free(lucy.name);
        lucy.name = NULL;
    }
    return 0;
}

11、结构体深层拷贝

如果结构体中含有指针成员,尽量使用深拷贝

(如果使用浅拷贝,拷贝完成后需要对lucy、ob申请的空间进行释放,由于指向同一空间,就造成空间重复释放,所以使用深拷贝,为ob重新申请一个空间,使用完成后进行释放)

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct stu
{
    int num;
    char *name;
};


int main(int argc, char const *argv[])
{
    struct stu lucy;
    struct stu ob;
    lucy.num = 100;
    lucy.name = (char *)calloc(1,128);//申请空间
    ob.name = (char *)calloc(1,128);
    
    ob.num = lucy.num;
    strcpy(ob.name,lucy.name);
    strcpy(lucy.name, "hellow world");
    printf("%d %s\n",lucy.num,lucy.name);
    printf("%c\n",lucy.name[1]);
    
    lucy.name[1] = 'D';
    printf("%d %s\n",lucy.num,lucy.name);
    //释放lucy.name指向的堆区空间
    if(lucy.name != NULL)
    {
        free(lucy.name);
        lucy.name = NULL;
    }
    if(ob.name != NULL)
    {
        free(ob.name);
        ob.name = NULL;
    }
    return 0;
}

如果结构体中没有指针成员 赋值 不会出现浅拷贝。

如果结构体中有指针成员 赋值 容易造成浅拷贝

12、结构体与结构体成员都在堆区

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct stu
{
    int num;
    char *name;
};
int main(int argc, char const *argv[])
{
    //结构体本身在堆区
    struct stu *p = NULL;
    p = (struct stu *)calloc(1,sizeof(struct stu));

    //为结构体指针成员申请空间
    
    p->name = (char *)calloc(1,128);//(*p).name = (char *)calloc(1,128);
    p->num = 100;
    strcpy(p->name,"hello world");
    printf("%d %s\n",p->num,p->name);
    //先释放成员空间
    if(p->name != NULL)
    {
        free(p->name);
        p->name = NULL;
    }
    //在释放结构体空间
    if(p != NULL)
    {
        free(p);
        p = NULL;
    }
} 

13、结构体对齐

(1)结构体自动类型对齐

①确定分配单位(一行分配多少字节)

​ 结构体中最大的基本类型长度决定

②确定成员偏移量

​ 成员偏移量 = 成员本身类型的整数倍

③收尾工作

​ 结构体的总大小 = 分配单位整数倍

#include <stdio.h>
struct array
{
    char str;
    int num;
    char name;
};

int main(int argc, char const *argv[])
{
    struct array A;
    printf("%d\n",sizeof(A));
    printf("%p\n",&A.str);
    printf("%p\n",&A.num);
    printf("%p\n",&A.name);
    return 0;
}

结果:

12
000000000061FDE4
000000000061FDE8
000000000061FDEC

案例1:画出以下结构体的对齐

struct Data
{
    char a;
    short b;
    int c;
    char d;
    short e;
};

在这里插入图片描述

(2)结构体嵌套结构体 自动对齐规则

①确定分配单位(一行分配多少字节)

​ 所有结构体中最大的基本类型长度决定

②确定成员的偏移量

​ 普通成员偏移量 = 成员自身类型的整数倍

​ 结构体成员的偏移量 = 结构体中最大的基本类型整数倍

③收尾工作

​ 结构体成员大小 = 该结构体中最大的基本类型整数倍

​ 结构体的总大小 = 分配单位整倍数

#include <stdio.h>
struct data1
{  
    char str;
    char str2;
    int num;
};
struct data2
{ 
    char str1;
    struct data1 bob;
    short num1;
};

int main(int argc, char const *argv[])
{
    struct data2 bob2;
    printf("%d\n",sizeof(bob2));
    //结构体自动对齐
    printf("%p\n",&bob2.str1);
    printf("%p\n",&bob2.bob.str);
    printf("%p\n",&bob2.bob.str2);
    printf("%p\n",&bob2.bob.num);
    printf("%p\n",&bob2.num1); 
    return 0;
}

结果:

16
000000000061FDE0
000000000061FDE4
000000000061FDE5
000000000061FDE8
000000000061FDEC

(3)结构体强制对齐

​ #prangma pack(value)是指定对齐值

​ valu值为1,2,4,8,16

①确定分配单位(一行分配多少字节)

​ 分配单位 = min(结构体中最大的基本类型,value)

②确定成员的偏移量

​ 成员偏移量 = 成员自身类型的整数倍

③收尾工作

​ 结构体的总大小 = 分配单位整倍数

#include <stdio.h>
#pragma pack(2)
struct array
{
    char str;
    int num;
    char name;
};

int main(int argc, char const *argv[])
{
    struct array A;
    printf("%d\n",sizeof(A));
    printf("%p\n",&A.str);
    printf("%p\n",&A.num);
    printf("%p\n",&A.name);
    return 0;
}

结果:

8
000000000061FDE8
000000000061FDEA
000000000061FDEE

14、位域

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

struct A
{
    unsigned int a:2;
    unsigned int b:6;
    unsigned int c:4;
    unsigned int d:3;
    unsigned int e;
}data;

​ a为无符号整型,大小只占2位二进制位

​ 位域可以是unsigned int ,unsigned char

​ 没有非位域隔开的位域 叫相邻位域(a,c)

​ 相邻位域可以压缩

​ 位段的大小不能超过存储单元的大小

​ 不要对位域取地址。

如:a=9 == 1001 ,但a的存储单元只有两位所以只能存储01

​ b=9 == 1001,b的存储单元有6位可以存储1001

#include <stdio.h>

struct A
{
    unsigned int a:2;
    unsigned int b:6;
    unsigned int c:4;
    unsigned char :8;
    unsigned int d:3;
    unsigned int e;
}data;
int main(int argc, char const *argv[])
{
    printf("sizeof(struct A)=%lu\n",sizeof(struct A));
    return 0;
}

无意义位段

#include <stdio.h>
struct A
{
    unsigned char a : 2;
    unsigned char :2;  //两位无意义位段
    unsigned char b : 2;
    unsigned char c : 2;
    //int num;
};

int main(int argc, char const *argv[])
{
    printf("sizeof(struct A)=%lu\n",sizeof(struct A));
}

在这里插入图片描述

#include <stdio.h>
struct B
{
    unsigned char addr : 2;
    unsigned char : 1;
    unsigned char opt :2;
    unsigned char : 1;
    unsigned char data : 2;
};
int main(int argc, char const *argv[])
{
    struct B reg;
    reg.addr = 2;
    reg.opt = 1;
    reg.data = 1;
}

二、共用体

共用体:所有成员共享同一块空间

结构体:所有成员拥有独立空间

union C
{
    int a;
    short b;
    char c;
};

成员a b c共享同一块空间。空间大小 由最大的成员空间决定,即c

union C ob;
ob.a = 10;//空间内容为10
ob.b = 20;//空间内容为20
ob.c = 30;//空间内容为30
ob.a + ob.b + ob.c = 90;

三、枚举enum

枚举:将枚举变量要赋的值一一列举出来

#include <stdio.h>
#include <string.h>

enum ha{data1,data2,data3=14,data4};
int main(int argc, char const *argv[])
{
    enum ha num = data2;
    printf("%d\n",num);
}

枚举默认从0开始依次递增即,data1 = 0 ; data2 = 1 ; data3 = 14 ; data4 = 15 ;

四、如有错误欢迎指正
如要转发请告知

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1520505.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

linux用git拉取我云端以及git处理冲突

拉取后切换一个跟云端分支(dev)一样的 git branch --set-upstream-toorigin/dev dev 之后就同步了 A在dev分支写了iii,提交 B在dev分支写了hhh,提交,冲突 怎么修改,B把云端的拉下来,随便改改就行

找准方向选CRM客户管理系统!2023年排行榜推荐

本文将为大家带来2023有哪些好用CRM客户管理系统&#xff1f;CRM系统排行榜基于品牌知名度、功能、产品实力、系统稳定性、用户体量等多重因素考量。其中Zoho CRM、红圈CRM等产品市场表现优异入选此次榜单。 1.Zoho CRM 公司成立时间&#xff1a;1996年 Zoho&#xff08;卓豪…

你为什么是你,而不是别人?认识人格的力量

你为什么是你&#xff0c;而不是别人&#xff1f;让你做自我介绍&#xff0c;你会怎么描述自己呢&#xff1f; 人格心理学是心理学的一门重要分支学科。探求、描述和揭示个体思想、情绪及行为的独特模式&#xff0c;综合个人与环境诸多影响因素&#xff0c;对现实社会中的个人作…

jenkins部署go应用 基于docker-compose

丢弃旧的的构建 github 拉取代码 指定go的编译版本 安装插件 拉取代码是排除指定的配置文件 比如 conf/config.yaml 文件 填写配置文件内容 比如测试环境一些主机信息 等 可以配置里面 构建的时候选择此文件替换开发提交的配置文件。。。。 编写docker-compose 文件 docker…

【PythonCode】力扣Leetcode6~10题Python版

【PythonCode】力扣Leetcode6~10题Python版 前言 力扣Leetcode是一个集学习、刷题、竞赛等功能于一体的编程学习平台&#xff0c;很多计算机相关专业的学生、编程自学者、IT从业者在上面学习和刷题。 在Leetcode上刷题&#xff0c;可以选择各种主流的编程语言&#xff0c;如C、…

渐开线花键不是齿轮?

在和一位小伙伴交流时&#xff0c;他认为齿轮和花键不一样&#xff0c;那花键是不是齿轮呢&#xff1f;老师傅们可以绕开了&#xff0c;我觉得对于一些平时接刚刚接触齿轮&#xff0c;或者很少接触的朋友来说&#xff0c;还是有必要聊一聊这个话题。 首先这个问题并不严谨&…

包冲突解决之-invalid constant type: 18

背景 现象一&#xff1a;引入了一个包A&#xff0c;服务突然起不来了&#xff0c;后台有报错信息&#xff0c;Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type xxx available: expected at least 1 bean which quali…

CSS扩展选择器

文章目录 1. 并集选择器2. 交集选择器3. 后代选择器4. 子代选择器5. 兄弟选择器5.1. 相邻兄弟选择器5.2. 通用兄弟选择器 6. 属性选择器7. 伪类选择器7.1. 动态伪类7.2. 结构伪类7.3. 否定伪类 8. 伪元素选择器9. Google 改进案例 1. 并集选择器 选中多个选择器对应的元素。一…

Day44-sersync企业实时复制实战

Day44-sersync企业实时复制实战 1. sersync实时复制工具介绍1.1 sersync工具简介1.2 sersync特点1.3 sersync图解原理1.4 sersyncrsync实时复制方案项目实践1.4.1 图解项目方案架构及实现原理1.4.2 确保远程数据传输服务部署完成1.4.3 检查当前系统nfs01是否支持inotify实时监控…

智慧城市:提升城市治理能力的关键

目录 一、智慧城市的概念及特点 二、智慧城市在提升城市治理能力中的应用实践 1、智慧交通&#xff1a;提高交通治理效率 2、智慧政务&#xff1a;提升政府服务水平 3、智慧环保&#xff1a;加强环境监测与治理 4、智慧安防&#xff1a;提高城市安全水平 三、智慧城市在…

基于springboot的七彩云南文化旅游网站的设计与实现(论文+源码)_kaic

摘 要 传统办法管理信息首先需要花费的时间比较多&#xff0c;其次数据出错率比较高&#xff0c;而且对错误的数据进行更改也比较困难&#xff0c;最后&#xff0c;检索数据费事费力。因此&#xff0c;在计算机上安装七彩云南文化旅游网站软件来发挥其高效地信息处理的作用&am…

sqllab第二十三关通关笔记

知识点&#xff1a; mysqli_query() 返回值为资源型或布尔型如果内容为查询语句则返回资源型数据&#xff1b;如果内容为插入、更新、删除等语句则返回布尔类型结果mysql_fetch_array() 从结果集中取出一行作为关联数组或数字数组输入内容为指定查询的结果集单引号闭合绕过联…

【测试开发学习历程】Docker入门

前言&#xff1a; Linux命令到上一篇博文就可以告一个段落了哦 ~ ~ 今天初步学习在测试中很重要的东西&#xff1a;Docker 目录 1 Docker概述 1.1 Docker产生的背景&#xff1f; 1.2 Docker的理念&#xff1f; 1.3 Docker的优势 1.3.1 传统的虚拟机 1.3.2 容器化虚拟技…

异次元发卡源码系统/荔枝发卡V3.0二次元风格发卡网全开源源码

– 支付系统&#xff0c;已经接入易支付及Z支付免签接口。 – 云更新&#xff0c;如果系统升级新版本&#xff0c;你无需进行繁琐操作&#xff0c;只需要在你的店铺后台就可以无缝完成升级。 – 商品销售&#xff0c;支持商品配图、会员价、游客价、邮件通知、卡密预选&#…

数据库 | MYSQL这个复杂系统如何上手?

当你不知道从何入手研究或解决一个复杂系统的问题时&#xff0c;通常意味着你没有找到合适的切入点或者缺乏对系统整体和细节之间联系的理解。在这种情况下&#xff0c;一个有用的策略是寻找系统的基本原理或构成要素。 小时候&#xff0c;你可能也玩过玩具四驱车。有的四驱车…

Github 2024-03-16 Rust开源项目日报 Top10

根据Github Trendings的统计,今日(2024-03-16统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Rust项目10TypeScript项目2Go项目1RustDesk: 用Rust编写的开源远程桌面软件 创建周期:1218 天开发语言:Rust, Dart协议类型:GNU Affero Gene…

OCP NVME SSD规范解读-12.Telemetry日志要求

以NVME SSD为例&#xff0c;通常大家想到的是观察SMAR-log定位异常&#xff0c;但是这个信息在多数情况下无法只能支撑完整的定位链路。 定位能力的缺失和低效是数据中心问题解决最大的障碍。 为了解决这个问题&#xff0c;Meta的做法是推进OCP组织加入延迟记录页面。同时NVME协…

经典机器学习模型(一)感知机模型

经典机器学习模型(一)感知机模型 感知机可以说是一个相当重要的机器学习基础模型&#xff0c;是神经网络和支持向量机的基础。 感知机是一个二分类的线性分类模型&#xff0c;之所以说是线性&#xff0c;是因为它的模型是线性形式的。 从《统计学习方法》中&#xff0c;我们…

如何搭建“Docker Registry私有仓库,在CentOS7”?

1、下载镜像Docker Registry docker pull registry:2.7.1 2、运行私有库Registry docker run -d -p 5000:5000 -v ${PWD}/registry:/var/lib/registry --restartalways --name registry registry:2.7.1 3、拉取镜像 docker pull busybox 4、打标签&#xff0c;修改IP&#x…

基于直方图均衡化的图像去雾算法,Matlab实现

博主简介&#xff1a; 专注、专一于Matlab图像处理学习、交流&#xff0c;matlab图像代码/项目合作可以联系&#xff08;QQ:3249726188&#xff09; 个人主页&#xff1a;Matlab_ImagePro-CSDN博客 原则&#xff1a;代码均由本人编写完成&#xff0c;非中介&#xff0c;提供有偿…