当前位置: 首页 > 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.lryc.cn/news/613244.html

相关文章:

  • 指针——练习
  • OLMo 2 架构深度解析:开放语言模型的技术革命
  • A Logical Calculus of the Ideas Immanent in Nervous Activity(神经网络早期的M-P模型)
  • 【数字图像处理系列笔记】Ch05:傅里叶变换与频率域滤波
  • 【实时Linux实战系列】实时分布式计算架构的实现
  • Mongodb常用命令简介
  • MongoDB学习专题(六)复制集和分片集群
  • 02电气设计-安全继电器电路设计(让电路等级达到P4的安全等级)
  • 内存泄漏系列专题分析之三十二:高通相机CamX ION/dmabuf内存管理机制CmdBuffer
  • VC6800智能相机:赋能智能制造,开启AI视觉新纪元
  • vue2+elementui select框可以选择可以回车添加新的option
  • Godot ------ 中级人物血条制作01
  • ElementUI之表格
  • Oracle 19C In-Memory 列存储技术测试
  • Renesas Electronics RA8M1语音套件(VK-RA8M1)
  • 深入解析Go设计模式:责任链模式实战
  • Electron 中 license-keys 的完整集成方案
  • 网络虚拟化是啥啊?
  • 自然语言处理×第四卷:文本特征与数据——她开始准备:每一次输入,都是为了更像你地说话
  • 拥抱云原生:从传统架构到云原生架构的演进与实践
  • python题目练习 无重叠区间
  • 京东关键字搜索商品列表接口开发实战:从参数优化到分布式调用
  • yolo目标检测技术:基础概念(一)
  • 【洛谷题单】--分支结构(一)
  • 脱机部署k3s
  • Python 常用内置高阶函数
  • OO SALV的栏位功能
  • 大屏数据展示页面,数据可视化可以用到的框架和插件
  • 阿里云部署若依后,浏览器能正常访问,但是apifox和小程序访问后报错链接被重置
  • day27 同步互斥