嵌入式初学-C语言-二四
Void与void*的区别
定义:
Void:空类型,是数据类型的一种
Void*:是指针类型,是指针类型的一种,可以匹配任何类型的指针,类似于通配符
Void
说明:void作为返回值类型使用,表示没有返回值,作为参数,表示形参列表为空,在调用函数时不能给实参
// 函数声明
void fun(void); // 等效于 void fun();
// 函数调用
fun();
Void*
说明:
- void*是一个指针类型,但是该指针的数据类型是不明确的,无法通过解引用获取内存中的数据,因为void*不知道访问几个内存单元
- void*是一种数据类型,可以作为函数返回值类型,也可以作为形参类型
- void*类型的变量在使用之前必须强制类型转换
int *p = (int*)malloc(4);
double *p2 = (double*)malloc(8);
举例:
#include <stdio.h>
#include <stdlib.h>
// 函数定义
void* fun(void* p) // 指针函数(返回值类型是指针的函数,此时返回的是不明确类型,需要外部强转)
{
int *p;
// double *p;
// long *p;
// char *p;
return p;
}
// 函数调用
void main()
{
int *p;
void* a = fun(p);// 这种接收方式,实际上没有意义
printf("%p\n",a);// 可以正常打印,打印出一个地址
*a = 10;// 编译报错,void*变量不能解引用访问数据
int *w = (int*)a;
*w = 10;// 编译和运行正常,void*变量a在使用前已经强制类型转换了,数据类型明确了,访问的内存
单元明确了。
}
说明:
- void*作为返回值类型:这个函数可以返回任何类型(char* int* double*)的指针
- void*作为形参的类型:这个函数在调用时,可以给任意类型的指针
总结:
- void*类似于通配符,不能对void*类型的变量解引用(因为不明确内存单元的大小)
- void*在间接访问(解引用)前要强制类型转换,但不能太随意,否则存和取的数据类型不一致
内存操作
我们对于内存的操作借助于string.h这个库提供的内存操作函数。
内存填充
头文件:#include<string.h>
函数原型:void*memset(void*s,int c,size_t n);
函数功能:填充s开始的堆内存前n个字节,使得每个字节值为c
函数参数:
- void*s:待操作内存的首地址
- int c:填充的字节数据
- size_t n:被填充的字节数
返回值:返回s
注意:c常常设置为0,用于动态内存初始化
/**
* 内存操作函数-memset
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void test1()
{
// 在堆内存申请了一块存储空间
int *p = (int*)malloc(4 * sizeof(int));
if(!p)
{
puts("内存分配失败!");
return;// 后续代码不需要执行
}
// 给这块内存进行初始化操作(填充)
memset(p,0, 4 * sizeof(int));
printf("%d\n",*(p+1));
// 内存使用完毕,进行回收
free(p);
p = NULL;
}
int main()
{
test1();
return 0;
}
内存拷贝
头文件:#include<string.h>
函数原型:
- void*memcpy(void*dest,const void*src,size_t n);适合目标地址与源地址内存无重叠的情况
- void*memmove(void*dest,const void*src,size_t n);
函数功能:拷贝src开始的堆内存空间前n个字节到dest对应的内存中
函数参数:
- void*dest:目标内存的首地址
- void* src:源内存首地址
- size_t n:被拷贝的字节数
返回值:返回dest
注意:内存申请了几个内存空间就访问几个内存空间,否则数据不安全
注意:memcpy与memmove一般情况下是一样的,更建议使用memmove进行内存拷贝因为mememove函数是从自适应(从后往前,从前往后)拷贝,当我们被拷贝的内存和目的地的内存有重叠时数据不会出现拷贝错误,而memecpy函数是从前往后拷贝,当被拷贝的内存和目的地有重叠时数据会出现拷贝错误
/**
* 内存操作函数-memcpy|memmove
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void test1()
{
// 申请内存
// int *p1 = (int*)malloc(4 * sizeof(int));
// int *p2 = (int*)malloc(6 * sizeof(int));
// 给p1,p2填充数据,可以使用for循环..
// for(int i = 0; i < 4; i++)
// p1[i] = 10 + i;
// memset(p2,0,6 * sizeof(int));
// 创建数组
int p1[4] = {11,12,13,14};
int p2[6] = {21,22,23,24,25,26};
// 将p1中的数据通过内存拷贝函数,拷贝到p2
// memcpy(p2+2,p1+1,2*sizeof(int)) // int p2[6] = {21,22,12,13,25,26}
memmove(p2+2,p1+1,2*sizeof(int));
// 测试输出数组
for(int i = 0; i < 4; i++)
printf("%4d",p1[i]);
printf("\n");
for(int j = 0; j < 6; j++)
printf("%4d",p2[j]);
printf("\n");
// 如果使用手动分配的指针,一定要记得释放内存
// free(p1);
// free(p2);
// p1 = NULL;
// p2 = NULL;
}
int main()
{
test1();
return 0;
}
内存比较
头文件:#include<string.h>
函数原型:int memcmp(void*dest,const void*src,size_t n)
函数功能:比较src和dest所代表的内存前n个字节数据
函数参数:
- void*dest:目标内存首地址
- const void*src:源内存首地址
- size_t n:比较的字节数
返回值:
- 0:数据相同
- >0:dest中的数据大于src(目标大于源)
- <0:dest中的数据小于src
注意:n一般和src,dest的总容量一样,如果不一样内存比较的结果就不确定
案例:
/**
* 内存操作-memcmp
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void test1()
{
// 申请内存
int *p1 = (int*)malloc(3*sizeof(int));
int *p2 = (int*)malloc(4*sizeof(int));
// int p1[4] = {1,0,3,6};
// int p2[4] = {1,2,3,4};
// int result = memcmp(p1,p2,4*sizeof(int));
*p1 = 65;
*p2 = 70;
char *a = (char*)p1;// 类型转换
char *b = (char*)p2;
printf("%c,%c\n",*a,*b);
int result = memcmp(a+1,b+1,1*sizeof(char));
printf("%d\n",result);
}
int main()
{
test1();
}
内存查找
头文件:#include<string.h>
函数原型:void *memrchr | *memchr(const void *s, int c, size_t n);
函数功能:在s开始的堆内存空间前n个字节中查找字节数据c
函数参数:
- const void *s:待操作内存首地址;
- int c:待查找的字节数据
- size_t n:查找的字节数
返回值:返回查找到的字节数据地址
注意:如果内存中没有重复数据,memchr和memrchr结果是一样的,若果有重复数据memchr和memrchr结果就不一样
案例:
/**
* 内存操作-memchr | memrchr
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// 声明外部函数
extern void *memrchr(const void *s,int c,size_t n);
void test1()
{
// 申请内存
int *p = (int*)malloc(4*sizeof(int));
if(!p)
{
puts("内存分配失败!");
return;
}
// 给变量赋值
for(int i = 0; i < 4; i++)
{
p[i] = i * 2;
}
p[3] = 4;
// 输出
for(int i = 0; i < 4; i++)
{
printf("%d,",p[i]);
}
printf("\n");
// 内存查找 memchr
int *x = (int*)memchr(p,4,4*sizeof(int));
printf("%p--%p--%d\n",x,p,*x);
// 内存查找 memrchr
int *y = (int*)memrchr(p,4,4*sizeof(int));
printf("%p--%p--%d\n",y,p,*y);
// 回收内存
free(p);
p = NULL;
}
int main()
{
test1();
}
本章小结
1. 指针就是地址。变量的指针就是变量的地址。指针变量就是地址变量。
指针是地址本身,指针变量是用来存放地址的变量。
2. 指向 把谁的地址存放在指针变量中,该指针变量就指向谁
3. 深入掌握对数组操作中怎样正确使用指针。
4. 有关指针变量的定义形式归纳比较,见表8-4。
5. 指针运算小结
① 指针变量加(减)一个整数
p++、p--、p+i、p-i、p+=i、p-+i 等均使指针变量p加(减)一个整数。改变了指向的地址值。
② 指针变量赋值
不要把一个整型数赋给指针变量
③ 指针变量可以赋空值
p=NULL 即不指向任何变量
④ 两个指针变量可以相减
两个指向同一数组的指针变量可以相减,得到两个指针之间元素的个数,但相加无意义
⑤ 两个指针变量比较
两个指向同一数组的指针变量可以比较,指向前面元素的指针“小于”指向后面元素的指针变量
相关文章:
嵌入式初学-C语言-二四
Void与void*的区别 定义: Void:空类型,是数据类型的一种 Void*:是指针类型,是指针类型的一种,可以匹配任何类型的指针,类似于通配符 Void 说明:void作为返回值类型使用…...
tcpdump入门——每种flag分别表示什么意思
在 tcpdump 的输出中,TCP 标志位(Flags)通常用简写字符表示。以下是每种 TCP 标志位的含义及其对应的简写字符: TCP 标志位及其简写 SYN (Synchronize) 作用:用于初始化连接。简写字符:S ACK (Acknowledgm…...
Qt如何封装工具
在Qt中封装工具类或库是一种常见的开发模式,通过封装可以提高代码的可重用性、可维护性和模块化。以下是封装工具类的一些步骤和最佳实践: ### 1. 创建工具类 首先,创建一个新的C类作为你的工具类。在Qt Creator中,可以通过右键点…...
vue3进阶用法之通过调用函数动态加载组件用法及示例
业务场景 假设现在有一个可能在全局任何地方调用的vue组件你会怎么办?非常简单,在app.vue下的router-view同级写上这个组件,在全局中加一个变量v-if判断这个变量就解决了! tempalte中 <div><router-view /><You…...
线程和进程的关系
计算机是如何运行的?CPU 操作系统 进程管理 CPU 多核心 充分利用-> 并发编程,并发执行就算分时复用, 包括多进程编程。 多进程编程进程太重,创建进程,销毁进程开销比较大 ,不利于频繁创建销毁进程&…...
《AI视频类工具之十二—— EbSynth》
一.简介 官网:https://ebsynth.com/?ref=ai-bot.cn EbSynth是一款功能强大的视频风格转换工具,它利用先进的图像处理和计算机视觉技术,将静态艺术风格应用到视频中的每一帧,为视频创作者提供了全新的创作方式。 二.功能介绍 主要功能 视频转换:EbSynth 可以将视频转换…...
Facebook国内企业户、海外户、国内二不限户以及三不限户区别何在?
Facebook广告账户的类型和设置对于企业在不同市场中的广告活动至关重要。了解国内企业户、海外企业户,以及国内二不限户和三不限户的区别,可以帮助你更好地选择和管理广告账户。以下是对这些账户类型的详细解析。 一、Facebook海外企业广告账户 海外企业…...
修改 ASP.NET Core 应用程序运行后的默认端口
可以通过以下几种方法来实现。具体选择哪种方法取决于项目需求和环境设置。 方法 1:使用 appsettings.json 配置文件 你可以在 appsettings.json 中设置 Kestrel 的配置来更改默认端口。 打开 appsettings.json 文件,添加 Kestrel 配置: { …...
维基知识库系统Wiki.js本地Linux环境部署并配置公网地址远程访问
💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…...
010集——按值传递、按引用传递等方法——C#学习笔记
按值传递参数 这是参数传递的默认方式。在这种方式下,当调用一个方法时,会为每个值参数创建一个新的存储位置。 实际参数的值会复制给形参,实参和形参使用的是两个不同内存中的值。所以,当形参的值发生改变时,不会影…...
Linux系统调优技巧
Linux系统调优技巧 Linux 性能调优技巧的深度分析及场景案例目录 1. Linux 性能调优的基础概念1.1 性能调优的目标1.2 常见的性能瓶颈 2. 系统监控与性能分析工具2.1 常用工具介绍2.2 实战案例:如何通过工具定位性能问题 3. CPU 性能调优3.1 CPU 负载分析3.2 CPU 调…...
计算机学习
不要只盯着计算机语言学习,你现在已经学习了C语言和Java,暑假又规划学习Python,最后你掌握的就是计算机语言包而已。 2. 建议你找一门想要深挖的语言,沿着这个方向继续往后学习知识就行。计算机语言是学不完的,而未来就…...
数字医学影像系统PACS源码,三甲以下医院都能满足,C#语言开发,C/S架构系统成熟稳定,支持二次开发项目使用。
数字医学影像系统(RIS/PACS)源码,三甲以下的医院都能满足。开发技术:C/S架构,C#开发语言,数据库服务器采用Oracle数据库。 PACS系统模块组成 : 工作站: 分诊工作站、超声工作站、放…...
C++语言基础|循环结构
C语言基础|循环结构 循环1. for语句2. while循环3. do…while语句 循环 在程序中,常常需要重复地执行某些操作。C提供了3种循环语句:for语句、while语句和do-while语句。在循环语句中,重复执行的操作叫做循环体。循环体可以是单条语句、块语…...
【学习笔记】解决在声音输出中找不到蓝牙耳机设备的问题
【学习笔记】在声音输出中找不到蓝牙耳机设备 在使用蓝牙耳机的时候,遇见一个问题,就是在电脑在连接蓝牙耳机之后,在声音输出中找不到蓝牙耳机设备,只能使用扬声器播放声音。电脑使用的是Windows 11系统。后来在网上寻找解决方案…...
PPPoE基础笔记
一、拨号原理 1.Discovery(发现阶段) PADI Client 发送广播的PADI报文,报文中包含Client想要的服务信息。 PADO Server收到PADI后,会向Client回复一个单播的PADO报文。 PADR Client 收到最先收到的PADO…...
开发组日志记录SPEC_v0.1.0
文章目录 开发组日志记录SPEC_v0.1.0目的设计逻辑1. User日志记录器1.1 记录器标签内容介绍1.2 程序打印User日志规则 2. Dev日志记录器2.1 记录器标签内容介绍2.2 程序打印Dev日志规则 3.代码说明3.1 代码详情3.2 使用说明 更新记录 时间版本内容修订者备注2024/08/150.1.0创…...
MySQL8 innoDB引擎的精髓
[client] port 3306 socket /var/lib/mysql/mysql.sock [mysql] #prompt"\umysqldb \R:\m:\s [\d]> " #关闭自动补全sql命令功能 no-auto-rehash ########################################################################### ##服务端参数配置 ######…...
【C语言实现花屏效果并打包程序为exe可执行文件】
说明:该程序为临摹改良(😀)作品,源地址C/C屏幕恶搞程序 效果展示 上代码 #include <windows.h>#define NUM 11451LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);int main() // Renamed WinMain to main {static int iKeep[NU…...
数据结构——排序(2):选择排序+交换排序
目录 一、选择排序 (1)直接选择排序 ①思路 ②过程图示 ③代码实现 ④代码解释 ⑤优化 1.代码实现 2.过程图示 3.代码解释 4.注意 ⑥直接选择排序的复杂度 (2)堆排序 ①注意 ②代码实现 二、交换排序 (…...
TDengine 快速体验(Docker 镜像方式)
简介 TDengine 可以通过安装包、Docker 镜像 及云服务快速体验 TDengine 的功能,本节首先介绍如何通过 Docker 快速体验 TDengine,然后介绍如何在 Docker 环境下体验 TDengine 的写入和查询功能。如果你不熟悉 Docker,请使用 安装包的方式快…...
Spark 之 入门讲解详细版(1)
1、简介 1.1 Spark简介 Spark是加州大学伯克利分校AMP实验室(Algorithms, Machines, and People Lab)开发通用内存并行计算框架。Spark在2013年6月进入Apache成为孵化项目,8个月后成为Apache顶级项目,速度之快足见过人之处&…...
OPENCV形态学基础之二腐蚀
一.腐蚀的原理 (图1) 数学表达式:dst(x,y) erode(src(x,y)) min(x,y)src(xx,yy) 腐蚀也是图像形态学的基本功能之一,腐蚀跟膨胀属于反向操作,膨胀是把图像图像变大,而腐蚀就是把图像变小。腐蚀后的图像变小变暗淡。 腐蚀…...
JVM虚拟机:内存结构、垃圾回收、性能优化
1、JVM虚拟机的简介 Java 虚拟机(Java Virtual Machine 简称:JVM)是运行所有 Java 程序的抽象计算机,是 Java 语言的运行环境,实现了 Java 程序的跨平台特性。JVM 屏蔽了与具体操作系统平台相关的信息,使得 Java 程序只需生成在 JVM 上运行的目标代码(字节码),就可以…...
使用Spring AI和MCP协议构建图片搜索服务
目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式(本地调用) SSE模式(远程调用) 4. 注册工具提…...
Webpack性能优化:构建速度与体积优化策略
一、构建速度优化 1、升级Webpack和Node.js 优化效果:Webpack 4比Webpack 3构建时间降低60%-98%。原因: V8引擎优化(for of替代forEach、Map/Set替代Object)。默认使用更快的md4哈希算法。AST直接从Loa…...
永磁同步电机无速度算法--基于卡尔曼滤波器的滑模观测器
一、原理介绍 传统滑模观测器采用如下结构: 传统SMO中LPF会带来相位延迟和幅值衰减,并且需要额外的相位补偿。 采用扩展卡尔曼滤波器代替常用低通滤波器(LPF),可以去除高次谐波,并且不用相位补偿就可以获得一个误差较小的转子位…...
第一篇:Liunx环境下搭建PaddlePaddle 3.0基础环境(Liunx Centos8.5安装Python3.10+pip3.10)
第一篇:Liunx环境下搭建PaddlePaddle 3.0基础环境(Liunx Centos8.5安装Python3.10pip3.10) 一:前言二:安装编译依赖二:安装Python3.10三:安装PIP3.10四:安装Paddlepaddle基础框架4.1…...
WebRTC调研
WebRTC是什么,为什么,如何使用 WebRTC有什么优势 WebRTC Architecture Amazon KVS WebRTC 其它厂商WebRTC 海康门禁WebRTC 海康门禁其他界面整理 威视通WebRTC 局域网 Google浏览器 Microsoft Edge 公网 RTSP RTMP NVR ONVIF SIP SRT WebRTC协…...
大数据驱动企业决策智能化的路径与实践
📝个人主页🌹:慌ZHANG-CSDN博客 🌹🌹期待您的关注 🌹🌹 一、引言:数据驱动的企业竞争力重构 在这个瞬息万变的商业时代,“快者胜”的竞争逻辑愈发明显。企业如何在复杂环…...
