10- c语言复合数据类型 (C语言)

news2024/12/24 2:07:11

一 结构体

1.1 引入

1、在自然界中 任何一个物体都有多个属性,如果用计算机语言来描述的话,一个属性也许可以用某一个基本数据类型来表示,但是当有多个属性的时候,一个基本数据类型就不能表示了。例如:学生:姓名 性别 年龄 电话号码 家庭住址 。。。

char name[32];
char gender;
int age;
char tel[12];
char addr[100];

2、如何才能将学生的所有的属性存储到一个数据类型中呢?

struct student{
    char name[32];
    char sex;
    int age;
    char tel[12];
    char addr[100];
};

struct: 结构体
struct student:类型名称
定义一个变量:struct student s;

1.2 结构体的定义

1、结构体类型定义:
struct 结构体 名称
{
        成员变量1;
        成员变量2;
        ...
        成员变量n;
};
注意:在结构体中不能定义函数

2、结构体变量的定义

  • struct 结构体名称 变量名;  struct student s;
  • struct 结构体名称 *变量名;  struct student *p;
  • struct 结构体名称 变量名[长度];  struct student s[10];

不常用的结构体变量的定义:

struct
{
        成员变量1;
        成员变量2;
        ...
        成员变量n;
}结构体变量1,结构体变量2,结构体变量3;
举例:
struct
{
        int age;
} A, B, C;
A,B,C是结构体变量

1.3 结构体中成员变量的初始化

1、该方法在初始化的时候初始化的值必须和定义结构体的时候成员变量的 定义顺序一致

strcut student s = {
        "zhangsan",
        18,
        'm'
};

2、成员变量名前面的 句点符号

struct student s = {
        .name = "zhangsan",
        .age = 18,
        .sex = 'm',
        .f1 = func;
};

1.4 结构体中成员变量的访问

1、. :域操作
前提:结构体变量是个普通变量/数组

struct student s;
s.age = 18;
s.sex = 'f';

2、-> : 指向操作
前提:结构体变量是个指针变量

struct student *p;
p = &s1;

3、如果结构体 指针变量p 指向了 某块内存空间,通过指针p操作指向的内存空间的方法有三种:
方法1:下标法
p[i].成员变量
方法2:指针法 , 不常用
(*(p+i)).成员变量
方法3:用过指向操作符
(p+i) == &p[i]
(p+i)-> 成员变量

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

struct Stu{
    int age;
};

int main() {
    struct Stu *s;
    s = (struct Stu *)malloc(3*sizeof(struct Stu));
    s[0].age = 10;
    
    (s+1)->age = 12;
    (*(s+1)).age = 15;
    return 0;
}

4、练习:
设计一个结构体,存储学生的姓名、性别、年龄。
定义一个结构体指针变量,存储3个学生的信息,通过该指针对每个结构体中的成员变量行赋值。

1.5 函数指针在结构体中的应用

思考:
假如学生的兴趣爱好为球类运动,可以定义多个函数对每一个球类运动进行描述,例如:

void play_basketball();
void play_pingpong();
void play_football();

思考:在结构体中如何设计一个变量保存该学生的兴趣爱好?
函数指针
思考:如何让该学生进行该爱好呢?
函数指针指向对应的函数,并且通过函数指针调用该函数

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

typedef void(*FUNC)(char *);

//定义结构体类型
struct student1{
    char name[32];
    char sex;
    int age;
    FUNC
    f;   //函数指针
};

void play_basketball(char *name){
    printf("%s play basketball\n", name);
}

void play_pingpong(char *name){
    printf("%s play pingpong\n", name);
}

void play_football(char *name){
    printf("%s play football\n", name);
}

//操作结构体中的成员变量为函数指针变量
void test2(){
    struct student1 s;
    memset(s.name, 0, sizeof(s.name));
    strcpy(s.name, "zhangsan");
    //zhangsan的爱好是 play football
    //将s.f 指向 play_football函数
    s.f = play_football;
    //zhangsan 开始踢足球了
    s.f(s.name);
}

int main(){
    test2();
    return 0;
}

1.6 typedef对结构体类型进行重新定义

1、使用 typedef 重定义类型
typedef struct 结构体名称
{
        成员变量1;
        成员变量2;
        ...
        成员变量n;
}新类型1, *新类型2;

  • 新类型1 变量名1;
  • 新类型2 变量名2;   //变量名2的数据类型是指针类型

2、笔试题

#define struct stu* stu;
typedef struct stu* p_stu;

stu a,b;     //struct stu *a, b;
p_stu a, b;  //struct stu *a, *b;

请问这几个a,b之间有何区别,最好用哪种方式(#define  /typedef)

1.7 结构体中的成员变量为其他结构体变量/指针

1、假设如下场景:用一个结构体描述某一本书,书的属性:名字、价格、作者、出版社

定义结构体描述作者

struct author{
    char name[32];  //名字
    int age;   //年龄
};

定义结构体描述出版社:

struct publish{
    char name[32];   //名字
    char addr[32];   //地址
};

定义结构体描述

struct book{
    char name[32];   //名字
    unsigned int price;   //价格
    struct author ath;    //作者
    struct publish *publish;   //出版社
};

2、访问结构体中的结构体成员变量

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

struct author{
    char name[32];  //名字
    int age;   //年龄
};

struct publish{
    char name[32];   //名字
    char addr[32];   //地址
};

struct book{
    char name[32];   //名字
    unsigned int price;   //价格
    struct author ath;    //作者
    struct publish *publish;   //出版社
};

int main(){
    struct book book;
    struct book book2;

    //初始化作者
    memset(book.ath.name, 0, sizeof(book.ath.name));
    strcpy(book.name, "zhangsan");
    book.ath.age = 30;

    //为指针变量pblish 分配空间     //书籍有两个出版社
    book.publish = (struct publish *)malloc(2*sizeof(struct publish));
    strcpy(book.publish[0].name, "hunan");
    strcpy(book.publish[1].name, "renming");

    printf("view the book name: %s\n", book.name);  //zhangsan
    printf("view the book publish: %s\n", book.publish);   //hunan
    return 0;
}

1.8 结构体的直接赋值

1、通过=将一个结构体中的内容赋值给另外一个结构体

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

struct A {
    int x;
    int y;
};

struct author{
    char name[32];  //名字
    int age;   //年龄
};

struct publish{
    char name[32];   //名字
    char addr[32];   //地址
};

struct book{
    char name[32];   //名字
    unsigned int price;   //价格
    struct author ath;    //作者
    struct publish *publish;   //出版社
};

int main(){
    struct A a, b;
    a.x = 100;
    a.y = 1000;
    b = a;
    printf("view the data b.x: %d, b.y: %d\n", b.x, b.y);

    struct book b1, b2;
    memset(b1.name, 0, sizeof(b1.name));
    strcpy(b1.name, "aiot");
    b1.price = 100;

    //对书的作者进行赋值
    strcpy(b1.ath.name, "lisi");
    b1.ath.age = 30;

    //对出版社进行赋值
    //在堆上分配了一个struct publish大小的空间
    b1.publish = (struct publish *)malloc(sizeof(struct publish));
    strcpy(b1.publish[0].name, "renmin");
    strcpy(b1.publish[0].name, "renmin");

    b2 = b1;
    printf("name: %s\n", b2.name);  //aiot
    printf("price:%d\n", b2.name);  //6421872
    printf("ath.name:%s\n", b2.ath.name);  //lisi
    printf("ath.age: %d\n", b2.ath.age);   //30
    printf("pbl.name: %s\n", b2.publish[0].name);  //renmin
    printf("pbl.addr: %p\n", b2.publish[0].addr);  //
    printf("pbl: %p  %p\n", b1.publish, b2.publish);

    printf("view line --------------------------------------\n");

    //strcpy(b2.publish -> name, "jixie");
    free(b2.publish);   //释放堆上的空间
    printf("pbl.name:%s\n", b1.publish[0].name);

    strcpy(b2.name, b1.name);
    b2.price = b1.price;
    b2.ath = b1.ath;
    //为 b2.publish 单独分配空间
    b2.publish = (struct publish *)malloc(sizeof(struct publish));
    //将 b1.publish 这个指针所指向的空间中的内容拷贝 b2.publish 这个指针所指向的空间中
    memcpy(b2.publish, b1.publish, sizeof(struct publish));

    return 0;
}

从上面程序的运行结果来看,一个结构体变量是可以通过=赋值给另外一个结构体变量的,并且两个结构体变量中的内容是一摸一样的。
如果结构体中有指针变量,那么导致两个结构体中的指针变量指向了同一块内存空间(两个指针会互相影响):
因为book2.pblish和book.pblish指向的是同一块内存空间,其中任意一个变量将pblish指向的空间free释放调,都会影响另外一个结构体变量操作pulish,如果执行 free(book.pblish);

printf("%s %s\n", book2.pblish[0].name, book2.pblish[1].name);  //这条语句可能会执行失败。

二 联合体/共用体

2.1 共用体的定义

union 名称
{
        成员变量1;
        成员变量2;
        ...
        成员变量n;
};

2.2 共用体的内存布局

  • 共用体的成员变量的存储:所有的成员变量共用一块内存空间
  • 共用体的大小:成员变量中占用内存空间最大的变量的大小
union un {
    char ch[2];
    int x;
};

union un2{
    char ch[2];
    short x;
};

union un u1;
union un2 u2;
sizeof(u1) == 4;
sizeof(u2) == 2;

2.3 共用体的实际使用

1、在实际工作中如果已知一个 整型变量(int a) 的值需要求出这个变量的每一个字节值的时候可以使用联合体。

union un{
    char ch[4];
    int x;
};

union un u;

只需要将u.x = a; 那么组成a的没一个字节的值就已经保存在u.ch数组中了
反之,如果已知组成a的每一个字节的值,需要求a的值,只需要将u.ch的每一个元素赋值为组成a的每一个字节的值,那么u.x 就是a的值。
2、传感器GY39,功能可以测量出温度、湿度、大气压强、海拔,假如我们自己开发一个设备,将该设备连接GY39模块,GY39回复的数据格式如下:
0x5a 0x5a 0x01 0x02 0x03 0x02 0x00 0x01 0x02 0x03 0x00 0x02 0x03 0x04 0x5a 0x5a
假设我们定义一个字符数组char ch[16] 用来保存GY39传输的数据
温度:ch[2]<<8 | ch[3]
湿度:ch[4]<<8 | ch[5]
大气压强:ch[6]<<24 | ch[7]<<16 | ch[8]<<8 | ch[9]
海拔:ch[10]<<24 | ch[11]<<16 | ch[12]<<8 | ch[13]
假如使用联合体求温度或者湿度

union un{
    char ch[2];
    unsigned short x;
};

union un u; 
u.ch[0] = ch[3], u.ch[1] = ch[2];

u.x 就是温度的值!!

2.4 小端模式和大端模式

1、数据在内存中的存储是以二进制的形式存储的,但是如果数据占用的内存空间超过1Byte,我们也可以理解为该数据在内存中是一个字节一个字节的存储。
例如 int x = 100; x占用4个字节,x在内存中被拆分成了4个字节分开存储的。

这四个字节中存储的值分别是多少呢?我们可以通过共用体获取。 

union un{
    char ch[4];
    int x;
};

int main(){
    union un un;
    un.x = 0x01020304;
    printf("0x%x 0x%x 0x%x 0x%x\n", un.ch[0], un.ch[1], un.ch[2], un.ch[3]);
    // 0x4 0x3 0x2 0x1
}

该共用体的内存布局如下:

根据程序的运行结果,我们发现因为我们可以得出结论:低字节的数据是存储在低地址,高字节的数据存储在高地址。这种存储模式我们称之为:小端模式
2、如果低字节的数据是存储在高地址,高字节的数据存储在低地址。这种存储模式我们称之为:大端模式
因为我们的计算机是小端模式,所以无法演示大段模式,大端模式的内存布局如下: 

3、注意:大端模式和小端模式和操作系统没关系! 和处理器(CPU)有关系
目前绝大多数的处理器都是小端模式,但是有一些嵌入式处理器是大端模式,甚至有些嵌入式处理器是可以设置为大端模式还是小端模式(两种都支持)。
4、笔试题
请编写代码测试某个处理器是大端模式还是小端模式。

三 枚举

3.1 枚举的定义

enum 类型名{
        成员1,
        成员2,
        ...
        成员n
};
注意:成员的前面是不需要声明数据类型的,只需要写成员名称即可

3.2 枚举成员的初始化

枚举是将所以的成员一一列举!,如果第一个成员没有初始化,则第一个成员的值为0,往后的每一个成员的值依次+1,直到列举完成或者遇到某个成员使用了赋值语句进行赋值,+1停止,被赋值的成员的值就是被赋值的值,该成员往后的每一个成员的值则在该成员的值的基础上依次+1。

3.3 枚举的实际用途

假如用一个数组存储每个月的天数,二月默认是28天
int mon[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
假如需要获取某个月的天数,比如5月份的天数,下标法对mon数组进行访问:mon[4],但是这样写代码的可读性不强,mon[4]读者是不一定知道代表的是5月份的天数,如果写成这样子:mon [May]  可读性就强!
按照此思路:一月份:Jan, 二月:Feb 三月:March .... 

 

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

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

相关文章

ML算法——线代预备知识随笔【机器学习】

文章目录 数学预备知识3、线性代数3.1、矩阵奇异值分解&#xff08;SVD&#xff09;3.2、广义逆矩阵&#xff08;Moore-Penrose &#xff09;3.3、数据白化&#xff08;Data Whitening&#xff09;3.4、向量导数 4、其它 数学预备知识 3、线性代数 3.1、矩阵奇异值分解&#…

最小化暗数据风险的 5 个步骤

超过一半的公司数据存储库包含哪些内容&#xff0c;但大多数人甚至不知道自己拥有什么&#xff1f;这是暗数据&#xff0c;是公司在不知不觉中收集的信息&#xff0c;它们不是日常业务交互的组成部分&#xff0c;因此通常位于后台。 虽然这些数据对于大多数公司来说似乎是不必…

C语言——数据的输入输出

数据的输入输出 前言&#xff1a;一、格式输入输出函数1.格式输出函数printf&#xff08;&#xff09;2.格式输入函数scanf&#xff08;&#xff09; 二、字符输入输出函数1.字符输出函数putchar&#xff08;&#xff09;2.字符输入函数getchar&#xff08;&#xff09; 三、字…

JUC并发工具类--阻塞队列BlockingQueue

JUC并发工具类--阻塞队列BlockingQueue 队列队列&#xff08;Queue接口&#xff09;提供的方法 阻塞队列阻塞队列&#xff08;BlockingQueue接口&#xff09;提供的方法应用场景JUC包下的阻塞队列如何选择适合的阻塞队列选择策略线程池对于阻塞队列的选择 队列 是限定在一端进…

Servlet技术实现服务端,Android平台作为客户端,实现一个个人店铺

背景&#xff1a; 使用Servlet技术实现服务端&#xff0c;使用Android平台作为客户端&#xff0c;实现一个个人店铺&#xff0c;店铺商品不限。功能要求如下&#xff1a; 1. 提供登录、注册功能&#xff1b;&#xff08;10分&#xff09; 2. 首页面包括“商品列表”子页面、“…

ATA-8000系列射频功率放大器——在生物医学中的应用

ATA-8000系列射频功率放大器——在生物医学研究中的应用 ATA-8000系列是一款射频功率放大器。其P1dB输出功率500W&#xff0c;饱和输出功率最大1000W。增益数控可调&#xff0c;一键保存设置&#xff0c;提供了方便简洁的操作选择&#xff0c;可与主流的信号发生器配套使用&…

VulnHub靶机渗透:SKYTOWER: 1

SKYTOWER: 1 靶机环境介绍nmap扫描端口扫描服务扫描漏洞扫描总结 80端口目录爆破 3128端口获取立足点获取立足点2提权总结 靶机环境介绍 https://www.vulnhub.com/entry/skytower-1,96/ 靶机IP&#xff1a;192.168.56.101 kali IP&#xff1a;192.168.56.102 nmap扫描 端口扫…

h5手写签名示例

前言 业务中需要用户进行签字&#xff0c;如何让用户在手机端进行签字&#xff1f; 示例如下 代码已分享至Gitee: https://gitee.com/lengcz/qianming 原示例&#xff1a; https://www.jq22.com/jquery-info13488 H5实现手写签字 创建一个html页面 <!DOCTYPE html> …

<Oracle>《Linux 下安装Oracle数据库 - Oracle 19C By CentOS 8 》(第一部分)

《Linux 下安装Oracle数据库 - Oracle 19C By CentOS 8 》&#xff08;第一部分&#xff09; 1 说明1.1 前言1.2 资源下载 2 安装步骤2.1 上传安装包2.2 下载数据库预安装包2.3 安装数据库预安装包 1 说明 1.1 前言 本文是Linux系统命令行模式安装Oracle数据库的学习实验记录…

【American English】实验室常用口语对话

不懂不丢人&#xff0c;不懂装懂才丢人。最近有点犯这毛病&#xff0c;多写一些东西消除一下。 无论什么知识都是多了才能成体系&#xff0c;更多自己在美国的小总结可见专栏&#xff1a;English。 文章目录 初次见面日常问候找寻某个东西找寻某个人 初次见面 Nice to meet you…

Linux之tar安装

目录 Linux之tar安装 定义 工作过程 语法格式 参数及用法 使用源代码安装软件的优点 注意&#xff1a;源代码编译环境 操作流程 解包 —— tar 配置 —— ./configure 编译 —— make 安装 —— make install 案例 --- 安装Apache服务 1.获取安装包地址并下载 2…

衣服面料相关基础

总结自 BiliBili视频&#xff1a;原来衣服的面料还能这么选&#xff0c;几个方法教你买到优质的短袖&#xff0c;再也不怕买衣服踩坑了 面子里子 既不能皱巴巴 又不能不透气 混纺 涤纶 粘纤 氨纶 涤纶 不变性 挺阔感 氨纶 弹性 粘纤 吸水透气40-50% 怕热 真丝与亚麻 …

Python 进阶(三):Python使用ORM框架SQLAlchemy操作Oracle数据库

Python使用ORM框架SQLAlchemy操作Oracle数据库 前言1. 安装Oracle Instant Client2. 安装依赖库3. 导入模块并创建引擎4. 操作oracle数据库4.1 新增数据4.2 查询数据4.3 更新数据4.4 删除数据 前言 要详细连接Oracle数据库并使用SQLAlchemy进行操作&#xff0c;按照以下步骤进…

云计算与OpenStack简介

文章目录 云计算与OpenStack简介什么是云服务模式部署模型 Openstac概述Openstack服务组件 云计算与OpenStack简介 什么是云 云是一种服务&#xff0c;就像我们去餐厅吃饭一样&#xff0c;只需要点菜&#xff0c;不需要知道厨师怎样烹饪食物。在云中&#xff0c;用户也只需要…

chatgpt赋能python:Python数据预处理:优化数据分析的重要步骤

Python数据预处理&#xff1a;优化数据分析的重要步骤 在数据分析过程中&#xff0c;数据预处理是非常重要的步骤。在这个阶段&#xff0c;我们可以清洗、转换和整理数据&#xff0c;以便更好地进行数据分析和建模。Python是一个强大的工具&#xff0c;可以帮助我们优化数据预…

Neural network-based clustering using pairwise constraints (ICLR-workshop 2016)

Neural network-based clustering using pairwise constraints (ICLR-workshop 2016) 源代码 摘要 这篇论文提出了一个基于神经网络的端到端的聚类框架。我们设计了一种新策略&#xff0c;除了学习适用于聚类的特征嵌入&#xff0c;还直接在源数据利用对比方法来推动数据形成…

计算机科学与技术报考指南【河南农业大学】

文章目录 前言环境介绍龙子湖校区文化路校区许昌校区 学院专业介绍计算机学习方面思维上态度上 最后 前言 这几年计算机分数虚高已经成为了不争的事实&#xff0c;加上计算机技术发展日新月异、大多数高校学习课程落后&#xff0c;转换思维另辟蹊径的报考农林类高校的计算机专…

WebSocket:基于 Spring Cloud 配置注解实现 WebSocket 集群方案

上一篇&#xff1a;WebSocket 的具体介绍与内部执行原理 文章目录 介绍用法抽象思路转发思路连接流程获取服务实例信息连接区分和管理 消息发送连接选择给指定用户发送消息给指定路径发送消息 结束源码地址声明 介绍 WebSocket大家应该是再熟悉不过了&#xff0c;如果是单体应…

Debezium系列之:发布Debezium 2.3.0.Final

Debezium系列之&#xff1a;发布Debezium 2.3.0.Final 一、重大变化1.PostgreSQL / MySQL 安全连接更改2.JDBC 存储编码更改 二、新功能和改进1.Debezium Server支持K8s2.新的通知子系统3.新的可扩展信号子系统4.JMX 信号和通知集成5.新的 JDBC 存储子系统6.PostgreSQL 流式传输…

优化伊通河漂流旅行方案的模型——JLU数学学院2020级数学模型期末大作业

文章目录 题目描述背景介绍模型假设问题一的模型决策树模型游客安全最大化与旅行次数最大化模型统筹考虑游客安全与旅行次数的模型模型对比 第二问的模型每天下水的脚踏游船与电动游船的比率的敏感性分析全是电动游船的情形全是脚踏游船的情形每天下水的脚踏游船与电动游船成比…