C语言基础之结构体

文章目录

  • 一、结构体
    • 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*4return 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));#endifprintf("%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.mzph.cn/news/748244.shtml

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

相关文章

RISC-V Optimization Guide(笔记)

官网发表的文章地址&#xff1a;RISC-V Optimization Guide B站有人做过解读视频&#xff0c;这篇文章也是看视频时做的笔记&#xff1a;视频地址 一、标量整数优化 1.1 常量的具体化 使用lui/addiw将立即数加载至寄存器&#xff0c;当立即数低12位的最高位为1时&#xff0c…

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

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

从零开始利用MATLAB进行FPGA设计(三)将Simulink模型转化为定点数据类型

文章灵感来源于MATLAB官方免费教程&#xff1a;HDL Coder Self-Guided Tutorial 考虑到MATLAB官网的英文看着慢&#xff0c;再加上视频讲解老印浓浓的咖喱味&#xff0c;我决定记录利用MATLAB&Simulink&SystemGenerator进行FPGA数字信号处理的学习过程。 往期回顾&am…

什么是响应式设计?响应式设计的基本原理是什么?如何做?

文章目录 一、是什么二、实现方式媒体查询百分比vw/vhrem小结 三、总结参考文献 一、是什么 响应式网站设计&#xff08;Responsive Web design&#xff09;是一种网络页面设计布局&#xff0c;页面的设计与开发应当根据用户行为以及设备环境(系统平台、屏幕尺寸、屏幕定向等)…

软考高级:BPR 和 BPM概念和例题

作者&#xff1a;明明如月学长&#xff0c; CSDN 博客专家&#xff0c;大厂高级 Java 工程师&#xff0c;《性能优化方法论》作者、《解锁大厂思维&#xff1a;剖析《阿里巴巴Java开发手册》》、《再学经典&#xff1a;《Effective Java》独家解析》专栏作者。 热门文章推荐&am…

【四 (1)数据可视化之如何选用正确的图表】

目录 文章导航一、数据分析中可视化的作用1、揭示数据关联和模式2、支持数据分析和决策3、提升沟通和共享效果4、强调关键信息和发现5、增强故事叙述和记忆效果6、有效增强数据交互性数据7、复杂信息易理解8、数据多维度显示 二、如何选用合适的图表1、简洁性避免使用过于复杂或…

软考高级:企业应用集成概念和例题

作者&#xff1a;明明如月学长&#xff0c; CSDN 博客专家&#xff0c;大厂高级 Java 工程师&#xff0c;《性能优化方法论》作者、《解锁大厂思维&#xff1a;剖析《阿里巴巴Java开发手册》》、《再学经典&#xff1a;《Effective Java》独家解析》专栏作者。 热门文章推荐&am…

八 超级数据查看器   讲解稿   详情3  分享和外观

八 超级数据查看器 讲解稿 详情3 分享和外观 app下载地址 下载地址4 ​ 讲解稿全文&#xff1a; 第3讲 分享 顶栏颜色 外观设置 现在讲解分享功能。点击&#xff0c;会打开分享对话框&#xff0c;我们这里演示2个&#xff0c;可以按照标题做出分享&#xff0c;在第一组…

鸿蒙Harmony应用开发—ArkTS声明式开发(容器组件:Badge)

可以附加在单个组件上用于信息标记的容器组件。 说明&#xff1a; 该组件从API Version 7开始支持。后续版本如有新增内容&#xff0c;则采用上角标单独标记该内容的起始版本。 子组件 支持单个子组件。 说明&#xff1a; 子组件类型&#xff1a;系统组件和自定义组件&#xf…

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

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

腾讯在线文档下载文档html格式

腾讯在线文档下载文档html格式 步骤 chrome 浏览器打开该文档&#xff08;edge不行&#xff09; 同时按住ctrlp快捷键调出腾讯文档内置的打印页面&#xff0c;打印范围要选择整个工作薄&#xff0c;纸张建议调大一点&#xff0c;边距建议较窄&#xff0c;缩放要选择宽度撑满&…

“风口”上的量化大厂“绣球”抛向中低频人才

量化人才这几年是人才舞台上的“香饽饽”。 遵循着低频不如高频、小厂不如大厂的薪资逻辑&#xff0c;各路人才被各路机构“哄抢”&#xff0c;薪资一路走高。 但2024年的“信号”再强烈不过——量化大厂们到了改变的时候了。 而量化大厂们显然对此已“心知肚明”....... “…

空气源热泵、地源热泵和水源热泵三种热泵的优缺点和选型比较

空气源热泵 空气源热泵是由电动机驱动的,利用空气中的热量作为低温热源,经过空调冷凝器或蒸发器进行热交换,然后通过循环系统,提取或释放热能,利用机组循环系统将能量转移到建筑物内用户需求。 1、适用范围广:适用温度范围在-7至40℃,并且一年四季全天候使用,不受阴、…

软件测试 —— 案例系统缺陷报告

知识&#xff1a; 1、缺陷等级&#xff1a; 1-Urgent(致命错误)&#xff1a;影响全局的死机、通信中断、重要业务不能完成 2-Very High(严重错误)&#xff1a;规定的功能没有实现或不完整或产生错误结果&#xff1b;使系统不稳定、或破坏数据等 3-High(一般错误)&#xff1a;…

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

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

NCDA大赛中哪些HTML5设计作品展现出色?

与传统的HTML网页设计相比&#xff0c;HTML5网页设计主要是对网页内容的加强。HTML5已成为目前最流行的标记语言&#xff0c;拥有成熟的社区和广泛的浏览器支持&#xff0c;HTML5完整的功能和强大的扩展性使设计师和开发者能够点铁成金。HTML5可以一手控制更多可控元素&#xf…

【AI+应用】一步步搭建聊天机器人搭配多种国内外大模型以及api接口调用

如果你看过我之前写的一篇文章 【AI应用】怎么快速制作一个类chatGPT套壳网站&#xff0c; 你可能顺利地使用chatGPT、Gemini&#xff0c; 用得很happy。 突然有一天&#xff0c;你发现一些网站&#xff0c;除了chatGPT、Gemini &#xff0c;还可以切换使用国内外其他的大模型…

Pulsar 社区周报 | No.2024.03.15 LTS 3.0.3 新版发布

“ 各位热爱 Pulsar 的小伙伴们&#xff0c;Pulsar 社区周报更新啦&#xff01;这里将记录 Pulsar 社区每周的重要更新&#xff0c;周五发布。 ” 本期主题&#xff1a;LTS 3.0.3 发布 Apache Pulsar 新版发布&#xff1a; LTS&#xff08;稳定性长期支持版&#xff09;新版&am…

SpringMVC基础之工作流程

文章目录 SpringMVC 的工作流程1. 总图2. DispatcherServlet3. 必需的配置4. 加载配置文件的两个时机5. 定义控制器6. 创建 JSP 视图 SpringMVC 的工作流程 1. 总图 如上图&#xff0c;Spring MVC 程序的完整执行流程如下&#xff1a; 用户通过浏览器发送请求&#xff0c;请求…

Docker 系列2【docker安装mysql】【开启远程连接】

文章目录 前言开始步骤1.增加mysql挂载目录2.下载镜像2.启动容器具体步骤4.无法连接5.测试连接 总结 前言 本文开始&#xff0c;默认已经安装docker&#xff0c;如果你还没有完成这个步骤&#xff0c;请查看这一篇文章【docker安装与使用】 开始步骤 1.增加mysql挂载目录 m…