C语言程序与设计——复杂结构

结构体

结构体在C语言中是一种重要的数据类型,或者说是一种用户自定义的相同或不同数据类型的集合。可以帮助我们封装一组相关数据,使其数据呈现更直观。例如我们想要统计一个学校学生的基本信息。可以将一个同学的信息按照如下存储。

typedef struct student{
    int grade;
    int age;
    char *name;
    char score;
}student;

这样我们输入和查询数据的时候都可以更快的定位到每个学生的具体信息。

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

typedef struct student{
    int grade;
    int age;
    char *name;
    char score;
}student;

student edit(int grade, int age, char* name, char score){
    student stu;
    stu.grade = grade;
    stu.age = age;
    stu.name = name;
    stu.score = score;
    return stu;
}

void search(student stu){
    printf("[stu.name] = %s\n", stu.name);
    printf("[stu.grade] = %d\n", stu.grade);
    printf("[stu.age] = %d\n", stu.age);
    printf("[stu.score] = %c\n", stu.score);
}

int main(){
    student nic;
    char nicname[] = "Nicholas";
    nic = edit(4, 13, nicname, 'A');
    search(nic);

}
输出结果:
>>[stu.name] = Nicholas
[stu.grade] = 4
[stu.age] = 13
[stu.score] = A

直接引用和间接引用

在访问结构体内部数据时,根据访问形式的不同,分为直接引用和间接引用

  1. 直接引用:通过结构体实例访问内部数据 访问形式如上代码示例(object.data)
  2. 间接引用:通过指针访问结构体内部数据,访问形式为->(pointer->data)

匿名结构体
匿名结构体,在声明的时没有定义结构体名称,所以匿名结构体只有在声明的时候可以被访问。匿名结构体我们会在下文共用体中演示。

结构体的大小
结构体作为很多数据类型的集合,所以其结构体本身的大小与集合内部的数据类型数量以及大小相关。但是它开辟空间的大小也有遵循一定的原则。如下两段代码

#include<stdio.h>

typedef struct stu_a{
    int age;
    char score;
    char gender;
}stu_a;

typedef struct stu_b{
    char score;
    int age;
    char gender;
}stu_b;

int main(){
    printf("sizeof(stu_a) = %lu\n", sizeof(stu_a));
    printf("sizeof(stu_b) = %lu", sizeof(stu_b));
}
运行结果
>>sizeof(stu_a) = 8
sizeof(stu_b) = 12 

结构体开辟空间会根据内部最大的数据类型大小为单位开辟。上述示例中int 占4字节而char占1字节,所以每次开辟空间都是会加4字节。如上述示例结构体stu_a,先申请4个字节,age刚好占满,而后继续申请四个字节,下面的score占一个字节,还剩三个,所以gender还可以占一个不需要额外申请。所以总共是8字节但是,使用的字节数只有6。
但是看到结构体stu_b同样的数据类型,只是位置不一样了,但是空间也略有不同。刚开始申请4个字节,score占一个字节,剩下三个字节,下面的age是int类型需要四个字节,那么他就会重新申请一块空间,这里需要注意的是,申请空间是以4字节为单位的,所以此时为8个字节,score占新申请的四个字节,因为数据是往后排放的,所以age后没有空间,则需要再申请4个字节,将gender放入。所以说结构体中数据的声明位置也很重要,应尽量让相同类型的变量相邻,以免造成空间浪费。

共用体

共用体同结构一样也是一种可以自定义的数据结构,在共用体中可以定义结构体,但是与结构体不同的是,我们可以再内存上的相同位置存储和访问不同的数据。

#include<stdio.h>
union node{
    struct{
        unsigned char a1;
        unsigned char a2;
        unsigned char a3;
        unsigned char a4;
    }a;
    int num;
};
int main(){
    union node node1;
    printf("sizeof(node1) = %lu", sizeof(node1));
}
运行结果:
>>sizeof(node1) = 4%

可以看到我们在共用体中定义了两个变量,一个含四个字符的结构体a,一个整型num。两种数据类型各占四个字节,但是该联合体大小也只有四字节,也就是说a与num存储在一块内存上。那么我们容易想到,存储在一块内存上,一组数据变动是不是会影响到另一组?下面通过一个ip转整数的示例来验证一下我们的想法。


#include<stdio.h>

union ip{
    struct{
        unsigned char a1;
        unsigned char a2;
        unsigned char a3;
        unsigned char a4;
    }n;
    int num;
};

int main(){
    char str[20];
    int arr[4];
    union ip test;
    while(~scanf("%s", str)){
        sscanf(str,"%d.%d.%d.%d",arr, arr + 1 , arr + 2, arr + 3);
        test.n.a1 = arr[0];
        test.n.a2 = arr[1];
        test.n.a3 = arr[2];
        test.n.a4 = arr[3];

        printf("ip = %d.%d.%d.%d\n", arr[0], arr[1], arr[2], arr[3]);
        printf("num = %d\n",test.num);
        printf("---------------------------------------------\n");
    }
}

在这里插入图片描述
这里我们当我们分别存入不同的数据时,共用体中的num也在不断的发生变化。当时在这我们发现了一个问题,就是我们在输入后面两个样例的时候,按道理来讲因为二者存储IP的值只相差1,所以在我们访问num的时候,应该是相邻的两个整型才对,但是这里可以看到值相差很多,这就涉及到了另外一部分知识。

大端机和小端机

大端机:数字的低位存储在地址的高位
小端机:数字的低位存储在地址的低位

上面这两个概念只需要清楚数字低位与地址高位的含义即可,如下图:
在这里插入图片描述
那么我们可以很清楚的看到如果是大端机的话,就会是我们预期的那样两次num的结果是相邻的两个数字,但是我们现在使用的计算机普遍是小端机,所以在计算机中存储顺序是反过来的即1 .0 168 192。也就是如果我们倒着输入存储的话,那么就会出现我们预期的结果了。
在这里插入图片描述
检验自己的计算机是大端机还是小端机
我们知道一个int类型大小为4个字节,char类型为一个字节,那么我们通过类型转换,打印出这四个字节所在地址的信息便可知道我们的机器是不是小端机了。

#include<stdio.h>

//测试是否为小端机
void is_little(){
    int num = 1;
    printf("int[0] =  %d\n", ((char *)(&num))[0]);
    printf("int[1] =  %d\n", ((char *)(&num))[1]);
    printf("int[2] =  %d\n", ((char *)(&num))[2]);
    printf("int[3] =  %d\n", ((char *)(&num))[3]);
}
int main(){
    is_little();
}

在这里插入图片描述
可以看到存储的1应该是个位,但是现在在地址的地位上。
或者我们用更清晰的例子来看一下

在这里插入图片描述
在这里插入图片描述
这里的205只是进制的转换,没有涉及到符号位,我们手算一下
11001101 = − ( 1001101 ) 对 括 号 里 面 取 反 码 后 加 一 − ( 0110010 + 1 ) = − ( 32 + 16 + 2 + 1 ) = − 51 11001101 = -(1001101)\\对括号里面取反码后加一\\-(0110010 + 1) = -(32+16+2+1) = -51 11001101=(1001101)(0110010+1)=(32+16+2+1)=51
由此可以验证我们的计算机是小端机

由该部分我们可以拓展出字节序的概念。这里不过多深入,字节序分为本地字节序(主机字节序)网络字节序,本地字节序描述的内容即为我们使用的计算机为大端机还是小端机。当我们使用网络编程的时候,就需要把本地字节序转换成网络字节序,网络字节序会根据对端的自动转换成主机字节序。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

结构化绑定optional(C++基础)

结构化绑定 处理多个返回值的操作&#xff1a;C17提出 之前多返回值喜欢用struct来返回。现在会做成元组&#xff0c;下图中设置C17的版本&#xff0c;不要设置错为C语言标准。 #include<iostream> #include<string> #include<tuple> std::pair<std::st…

【跟着CHATGPT学习硬件外设 | 02】GPIO

文章目录 &#x1f680; 概念揭秘快速入门关键精华 &#x1f31f; 秒懂案例生活类比实战演练步骤1&#xff1a;硬件配置步骤2&#xff1a;软件配置步骤3&#xff1a;发送和接收数据步骤4&#xff1a;处理异常步骤5&#xff1a;优化操作手册硬件设计注意事项配置攻略准备阶段配置…

Docker配置Mysql

1.首页搜索mysql镜像 2.选择对应版本的MySQL&#xff0c;点击pull 3.pull完成以后&#xff0c;点击images&#xff0c;这里可以看到刚刚pull完成的mysql版本 4.打开命令界面&#xff0c;运行命令 docker images ,查看当前已经pull的images 5.运行命令设置mysql docker run -it…

OSCP靶场--Kyoto

OSCP靶场–Kyoto 考点(缓冲区溢出GPO滥用提权) 1.nmap扫描 ## ┌──(root㉿kali)-[~/Desktop] └─# nmap 192.168.216.31 -sV -sC -Pn --min-rate 2500 -p- Starting Nmap 7.92 ( https://nmap.org ) at 2024-03-31 08:08 EDT Nmap scan report for 192.168.216.31 Host …

14 - grace数据处理 - 泄露误差改正 - 空域滤波法(Mascon法)

@[TOC](grace数据处理 - 泄露误差改正 - 空域滤波法(Mascon法)) 空域法的基本思想是假设地面某区域的质量变化是由一系列位置已知、质量未知的质量块(小范围区域)引起的,那么将GRACE反演的结果归算到n个质量块上的过程就是泄露信号恢复的过程。个人理解是这样的:假定已知研…

Multi-task Lung Nodule Detection in Chest Radiographs with a Dual Head Network

全局头增强真的有用吗&#xff1f; 辅助信息 作者未提供代码

【跟小嘉学 Linux 系统架构与开发】二、Linux发型版介绍与基础常用命令介绍

系列文章目录 【跟小嘉学 Linux 系统架构与开发】一、学习环境的准备与Linux系统介绍 【跟小嘉学 Linux 系统架构与开发】二、Linux发型版介绍与基础常用命令介绍 文章目录 系列文章目录[TOC](文章目录) 前言一、 Linux 发行版(Linux distribution)介绍二、Centos 虚拟机初始化…

【Linux】socket套接字

欢迎来到Cefler的博客&#x1f601; &#x1f54c;博客主页&#xff1a;折纸花满衣 &#x1f3e0;个人专栏&#xff1a;题目解析 目录 &#x1f449;&#x1f3fb;IP地址和端口号pid和port的关系 &#x1f449;&#x1f3fb;TCP和UDP&#x1f449;&#x1f3fb;网络字节序&…

数据分析之Tebleau 的度量名称和度量值

度量名称 包含所有的维度 度量值 包含所有的度量 度量名称包含上面所有的维度&#xff0c;度量值包含上面所有的度量 当同时创建两个或两个以上度量或维度时&#xff0c;会自动创建度量名称和度量值 拖入省份为行(这会是还没有值的) 可以直接将销售金额拖到数值这里 或者将销售…

C++11 shared_from_this学习

最近学习网络变成发现一些C源码库中封装对象时会公有继承enable_shared_from_this&#xff1b; 用一个案例进行说明&#xff0c;案例代码如下&#xff1a; #include <iostream> #include <memory> #include <stdio.h>using namespace std;class C : public…

ComfyUI一直提示transformers需要升级,怎么解决?

&#x1f3a1;背景 最近通过秋叶的启动器使用Comfyui的时候&#xff0c;总是会有个弹窗提示transformers需要升级&#xff0c;你会发现&#xff0c;就算是更新了ComfyUI版本&#xff0c;升级了所有插件&#xff0c;升级了transformers库&#xff0c;这个提示仍然存在&#xff…

【Spring Security】 快速入门

文章目录 一、 身份认证Demo1、创建工程2、代码编写2.1、Controller2.2、Html2.3、application.properties配置 3、启动项目并访问 二、Spring Security 默认做了什么二、底层原理1.概述2.FiltersDelegatingFilterProxyFilterChainProxySecurityFilterChainSecurity Filters 三…

【docker】搭建Nexus私服

1、拉取镜像 docker pull sonatype/nexus3 2、运行镜像 docker run -d -p 10002:8081 -e NEXUS_CONTEXTnexus --name nexus-quick sonatype/nexus3 3、访问地址&#xff1a; http://localhost:10002/nexus &#xff01;&#xff01;&#xff01;注意我的端口号是…

数据结构--循环链表(C语言实现)

一.循环链表的设计 typedef struct CNode{ int data; struct CNode* next; }CNode ,*CList; 2.循环链表的示意图: 3.循环链表和单链表的区别: 唯一区别,没有空指针,尾节点的后继为头,为循环之意. 二.循环链表的实现 //初始化return true; }//返回key的前驱地址&#xff0c;如果…

查找--二分查找(Binary Search)

二分查找属于静态查找表&#xff0c;当以有序表表示静态查找表时&#xff0c;查找函数可用折半查找来实现。 查找过程&#xff1a;先确定待查记录所在的范围&#xff08;区间&#xff09;&#xff0c;然后逐步缩小范围直到找到或找不到该记录为止。 以处于区间中间位置记录的…

【Chiplet】技术总结

Chiplet基本知识点汇总 1. Wafer, die, chip, cell的区分2. MCM, SiP, SoC, Chiplet的区别4. Chiplets的先进封装5. Chiplet发展阶段 Chiplet基本知识点汇总 1. Wafer, die, chip, cell的区分 Wafer: 晶圆&#xff0c;指一整个晶圆硅片。 Die: 从晶圆上切分下来的小方格&a…

本地GPU调用失败问题解决3重新配置anaconda环境(成功)

1、右键“以管理员身份”打开anaconda prompt conda create -n python 3.9 2、使用官方下载源的配置 3、修改conda下载超时 conda config --set remote_connect_timeout_secs 60 conda config --set remote_read_timeout_secs 100 查看配置结果conda config --show 配置内…

HarmonyOS实战开发-slider组件的使用

介绍 本篇Codelab主要介绍slider滑动条组件的使用。如图所示拖动对应滑动条调节风车的旋转速度以及缩放比例。 相关概念 slider组件&#xff1a;滑动条组件&#xff0c;通常用于快速调节设置值&#xff0c;如音量调节、亮度调节等应用场景。 环境搭建 软件要求 DevEco Stu…

xftp突然无法连接虚拟机

问题描述 使用xftp连接虚拟机的时候一直显示 连接xxx.xxx.xx.xx失败 问题原因查找 首先打开本地cmd命令提示符 ping 你的虚拟机ip地址 我的是 ping 192.168.xx.xx 显示请求超时 解决方案&#xff1a; 点击打开更改适配器选项 右键vmnet 8——属性 如图前四个选项必选 单…

Linux:ip协议

文章目录 ip协议基本认识ip协议的报头 ip协议基本认识 前面对于TCP的内容已经基本结束了&#xff0c;那么这也就意味着在传输层也已经结束了&#xff0c;那么下一步要进入的是的是网络层&#xff0c;网络层中也有很多种协议&#xff0c;这里主要进行解析的是ip协议 前面的TCP…