当前位置: 首页 > news >正文

嵌入式学习---在 Linux 下的 C 语言学习 Day10

Day10

共用体(Union)

也称为联合体,和结构体类似,也是由多个相同或不同类型的数据成员构成的集合。但和结构体不同的是它的所有数据成员都是共享同一块内存空间,并没有独立的内存空间

共用体的用法和结构体是一样的,只是使用的是 union 关键字

共用体的总大小就是其数据成员

一定要弄清楚共用体的内存布局(即内存存储形态)

#include <stdio.h>// 声明共用体类型 demo,类型名是 demo
union demo
{int i;char c;short s;long l;char a[5];};typedef union
{float f;int i;short s;} money;int main()
{// 使用上面声明的共用体类型定义变量或常量union demo d1;money m1;printf("%lu\n",sizeof(d1));printf("%lu\n",sizeof(m1));d1.i = 6513249;printf("%c\n",d1.c); // aprintf("%hd\n",d1.s); // 25185printf("%s\n",d1.a); // abcd1.a[1] = 0;printf("%c\n",d1.c); // aprintf("%hd\n",d1.s); // 97printf("%s\n",d1.a); // aprintf("%d\n",d1.i); // 6488161d1.l = 0x10064636261;printf("%c\n",d1.c); // aprintf("%hd\n",d1.s); // 25185printf("%s\n",d1.a); // abcdprintf("%x\n",d1.i); // 64636261union demo* p1 = &d1;printf("%hd\n",p1->s);return 0;
}

在这里插入图片描述

枚举(Enum)

用来表示取值个数有限的数据,比如性别、学历等。

枚举类型其实就是整数类型,只不过使用一些更有意义的名字来代表整数值

枚举也是一种自定义数据类型,需要先声明再使用,使用 enum 关键字

枚举元素就是一个整数常量,在所有枚举类型中都不能同名

如果不显示指定枚举元素的具体值,第一个枚举元素的值就是 0,后面枚举元素的值就是它前面的枚举元素的值加一后的值,也支持我们显式指定枚举

enum sex_t
{// 枚举元素female,male,unknow
};typedef enum
{// 枚举元素dazhuan,benke,yanjiusheng,boshi
} degree;int main()
{// 使用上面声明的枚举类型定义变量或常量enum sex_t s1 = male;s1 = female;s1 = unknow;degree d1 = boshi;d1 = benke;if(s1 == male){printf("男\n");}else if(s1 ==female){printf("女\n");}else{printf("未知\n");}printf("%lu\n",sizeof(s1));printf("%lu\n",sizeof(d1));printf("%d\n",s1);printf("%d\n",d1);printf("%d\n",male);printf("%d\n",boshi);
}

内存管理(Memory Management)

每个进程都拥有自己独立的私有地址空间,每个进程的地址空间都分为下面的区域:

  • 栈区(Stack):可读可写,存放形参变量,非静态局部变量,函数返回地址等,系统自动管理分配和释放,我们无法干预。容量很小(通常只有若干 MB),不适合处理大量数据。
  • 静态存储区:可读可写,存放静态局部变量、全局变量等,容量大,系统自动管理分配和释放,我们无法干预。
  • 常量区:只读,存放常量数据,容量大,系统自动管理分配和释放,我们无法干预。
  • 堆区:可读可写,容量大,由我们自己管理分配和释放,很灵活,可以实现动态内存管理。
  • 代码段:只读,存放程序指令(即代码),系统自动管理,我们无法干预。

进程(Process):正在运行的程序

程序(Program):可执行文件,存放在硬盘、U 盘面等外存设备上

动态内存管理相关的标准 C 库函数:

  • malloc:在堆区申请一块指定大小的内存空间,未初始化
  • calloc:在堆区申请一块指定大小的内存空间,全部清零初始化
  • realloc:调整一块已分配的堆区空间的大小(会保留原来的数据,调大时会尽可能进行原地扩充内存,如果尾部没有足够的空闲空间,就会直接申请一块新的空间,将旧空间的所有数据都拷贝过去,然后释放掉旧空间)
  • free:释放一块已分配的堆区空间(PS:释放后就不要再访问那块堆区空间了)

malloc 函数如果执行成功,返回值为分配的堆区空间的首地址,否则返回 NULL。

calloc 函数内部首先调用 malloc 函数申请指定大小的空间

在各个进程频繁进行申请和释放后,堆区肯定会产生很多内存碎片

关于 main 函数返回值的意义,规范的做法是程序执行成功(正常结束)返回 0,执行失败(异常结束)返回非零值,操作系统或其他程序可以通过获取我们的程序的返回值判断是否执行成功

进程结束后,系统会释放它占用的所有资源,包括未释放的堆区空间等

#include <stdio.h>
#include <stdlib.h> // standard library
#include <string.h>struct book
{int isbn;char name[51];float price;
};int main()
{/*// 栈溢出(Stack Overflow)崩溃double nums[10000000] = {1,2,3,4};;nums[1000] = 3.14;printf("%g\n",nums[1000]);*/// 在堆区中申请空间存放10000000个浮点数double* nums= malloc(10000000 * sizeof(double));if(nums == NULL){printf("malloc fail\n");return 1;}int* i = malloc(sizeof(int));if(i == NULL){printf("malloc fail\n");return 1;}*i = 3;(*i)++;printf("%d\n",*i);free(i);nums[1000] = 3.14;printf("%g\n",nums[1000]);free(nums); // 释放 nums 指向的堆区空间/*// 堆区释放了就不要再访问了nums[3] = 5.8;printf("%g\n",nums[3]);*/// 单个堆区结构体struct book* b1 = malloc(sizeof(struct book));if(b1 == NULL){printf("malloc fail\n");return 1;}b1->isbn = 10001;strcpy(b1->name,"操作系统");b1->price = 35.5;//(*b1).price = 35.5;                  printf("%d %s %g\n",b1->isbn,b1->name,b1->price);free(b1);// 堆区结构体数组struct book* bs = malloc(1000 * sizeof(struct book));if(bs == NULL){printf("malloc fail\n");return 1;}bs[3].isbn = 10001;strcpy(bs[3].name,"操作系统");(bs + 3)->price = 35.5;printf("%d %s %g\n",bs[3].isbn,bs[3].name,(bs + 3)->price);free(bs);// calloc 的用法// calloc 函数内部实现/*int* datas = malloc(100 * sizeof(int));// 全部清零char* p = (char*)datas;for(int i = 0;i < 100 * sizeof(int);i++){p[i] = 0;}*/int* datas = calloc(100,sizeof(int));if(datas == NULL){;}printf("%d\n",datas[90]);datas[3] = 100;printf("%d\n",datas[3]);free(datas);// realloc 用法char* s = malloc(5);if(s == NULL){;}//s = "qzp"; // 会导致内存泄漏strcpy(s,"qzp");s = realloc(s, 10);printf("%s\n", s);strcat(s,"666");printf("%s\n",s);free(s); // 段错误return 0;
}

常用内存操作相关的标准 C 库函数(所有内存区域都可以使用):

  • memset:memory set,将一块内存空间中的每个字节都设置为指定的值
  • memcpy:memory copy,内存空间拷贝,源内存空间和目标内存空间不能存在重叠
  • memmove:memory move,内存空间拷贝,源内存空间和目标内存空间可以存在重叠
  • memcmp:memory compare,比较两块内存空间中的数据是否相同
#include <stdio.h>
#include <stdlib.h>
#include <string.h>int main()
{int i;memset(&i, 0, sizeof(int));printf("%d\n",i);memset(&i, 1, sizeof(int));printf("%d\n",i);memset(&i, 0xFF, sizeof(int));printf("%d\n",i);// 栈区数组int nums1[100] = {5,4,3,1,2};//memset(nums1, 0, sizeof(nums1)); // 数组清零// 堆区数组int* nums2 = malloc(100 * sizeof(int));memcpy(nums2,nums1,100 * sizeof(int));for(int i = 0;i < 5;i++){printf("%d ",nums2[i]);}printf("\n");free(nums2);char s[] = "hello,qzp";memmove(s,s + 2,7); // llo,qzpzp
//      memmove(s + 2,s,7); // hehello,qprintf("%s\n",s);return 0;
}
http://www.dtcms.com/a/319689.html

相关文章:

  • 可执行文件的生成与加载执行
  • 超高车辆如何影响城市立交隧道安全?预警系统如何应对?
  • [论文阅读] 软件工程 | 软件工程中的同理心:表现、动机与影响因素解析
  • oracle 11G安装大概率遇到问题
  • 大文件断点续传(vue+springboot+mysql)
  • Failed to restart docker.service: Unit docker.service is masked.
  • PostgreSQL 数据库 设置90天密码过期时间的完整方案
  • 读取了错误数据导致STM32 单片机Hard Fault
  • 智能升级革命:Deepoc具身模型开发板如何让传统除草机器人拥有“认知大脑”
  • 分布式微服务--GateWay(过滤器及使用Gateway注意点)
  • 翻译模型(TM):基于短语的统计翻译模型(PBSMT)的构建
  • C++语法与面向对象特性(2)
  • PyTorch如何实现婴儿哭声检测和识别
  • 目标检测数据集 - 自动驾驶场景道路异常检测数据集下载「包含VOC、COCO、YOLO三种格式」
  • 接口自动化-pytest
  • OpenAI 开源模型 gpt-oss 正式上线微软 Foundry 平台
  • 网络可视,运维无忧:分钟级定位,告别盲目扩容
  • 从零开始构建情绪可视化日记平台 - React + TypeScript + Vite
  • CPTS Remote 复现
  • Redisson中的分布式锁
  • 自动化办公革命:3小时完成8小时工作量
  • 钢卷矫平机科普:把“弯曲的记忆”清零
  • 人工智能与能源:AI 驱动的能源产业变革
  • MCU-基于TC397的双BootLoader设计方案
  • 关于vue2中对接海康摄像头以及直播流rtsp或rtmp,后台ffmpeg转码后通过ws实现
  • 【linux】vmware中ubuntu无法上网
  • 关于 cadence导入原理图出现ERROR(ORCAP-1192)错误 的解决方法
  • 蓝桥杯算法之搜索章 - 3
  • HarmonyOS分布式开发实战:打造跨设备协同应用
  • C 语言主控开发与显控开发能力体系及技术栈详解,STM32、QT、嵌入式、边缘系统显示