20230809-深入浅出学习舞台灯光

agenda

different kinds of lighting

indoor lighting

studio lighting

film lighting

architecture lighting

theater lighting

stage lighting

golden rules of stage lighting

safety first

fixture location is the key

to hide not to show

golden rules

light sources

in which ways can we produce light?

what are the pros and cons?

incandescent 白炽灯

a wire filament heated to such a high temperature that it glows with visible light

efficiency low
heat high
cooling no
color 2700k-3500k
life 2000 hrs
power AC
dimmable yes

halogen 卤素灯

an incandescent lamp consisting of a tungsten filament sealed into a compact transparent envelope that is filled with a mixture of an inert gas and a small amount of a halogen

efficiency low
heat high
cooling no
color 2700k-3500k
life 3600 hrs
power AC
dimmable yes

Fluorescent 荧光灯

a slow pressure mercury-vapor gas-discharge lamp that uses fluorescence to produce visible light

efficiency high
heat low
cooling no
color 2700k-6500k
life 5000 hrs
power ballast 镇流器
warm up long
dimmable no

discharge 放电灯

a high-intensity discharge hid lamp is a type of electrical lamp which produces light by means of an electric arc between tungsten electrodes housed inside a translucent or transparent fused quartz of fused alumina arc tube

efficiency high
heat low
cooling yes
color 6500k-8000k
life 4000 hrs
power ballast 镇流器
warm up long
dimmable no

color temperature

the color temperature of a light source is the temperature of an ideal black-body radiator that radiates light of a color comparable to that of the light source

sources-LED 发光二极管

a light-emitting diode LED is a two-lead semiconductor light source

efficiency high
heat low
cooling yes
color mixing
life 50000 hrs
power DC
warm up short
dimmable yes

sources-Laser 激光

a laser is a device that emits light through a process of optical amplification based on the stimulated emission of electromagnetic radiation

fixture specification

wattage

beam angle / field angle 25 degree

beam type beam spot wash

color temperature kelvin

color mixing RGB CMY

fixture positions

front light 面光

to show the face not to create atmosphere

vertical angle 45 degree to 60 degree

use only white color

dont keep changing the brightness

back light 背光

a light source behind the actor helps to give depth to the stage by separating the action from the scenery

vertical angle 0 degree to 60 degree

strong colors can be used to create atmosphere

can also be used to spread beams into audience in order to extend the stage

down light 顶光

color wash

eliminate shadows

side light 侧光

hightlight the contour of the figure

can only have one side

fixture types

controller

lighting design process

demo

20230808-开关电源和普通电源有什么区别

什么叫开关电源

随着电力电子技术的发展和创新,使得开关电源技术也在不断得创新,目前,开关电源以小型、轻量和高效率的特点被广泛应用几乎所有的电子设备,是当今电子信息产业飞速发展的不可缺少的一种电源方式

开关电源是利用现代电力电子技术,控制开关管开通和关断的时间比率,维持稳定输出电压的一种电源,开关电源一般由脉冲宽度调制 PWM 控制ic 和mosfet 构成

开关电源是相对线性电源说的,其输入端直接将交流电整流变成直流电,再在高频震荡电路的作用下,用开关管控制电流的通断,形成高频脉冲电流。在电感(高频变压器)的帮助下,输出稳定的低压直流电。

由于变压器的磁芯大小与开关电源工作频率的平方成正比,频率越高铁心越小,这样就可以大大减小变压器,使电源减轻重量和体积,而且由于它直接控制直流,使这种电源的效率比线性电源高很多,这样就节省了能源,因此它受到人们的青睐。但它也有缺点,就是电路复杂,维修困难,对电路的污染严重。电源噪声大,不适合用于某些低噪声电路。  

开关电源的特点

开关电源一般由脉冲宽度调制(PWM)控制IC和MOSFET构成。随着随着电力电子技术的发展和创新,目前开关电源主要以小型、轻量和高效率的特点被广泛应用到几乎所有的电子设备,其重要性可见一斑。 

开关电源的分类
根据开关器件在电路中连接的方式,开关电源总的来说可分为串联式开关电源、并联式开关电源、变压器式开关电源等三大类。
其中,变压器式开关电源还可以进一步分成:推挽式、半桥式、全桥式等多种。根据变压器的激励和输出电压的相位,又可以分成:正激式、反激式、单激式和双激式等多种。

开关电源和普通电源的区别
普通的电源一般是线性电源,线性电源,是指调整管工作在线性状态下的电源。而在开关电源中则不一样,开关管(在开关电源中,我们一般把调整管叫做开关管)是工作在开、关两种状态下的:开 —— 电阻很小,关 —— 电阻很大。  开关电源是一种比较新型的电源。它具有效率高,重量轻,可升、降压、输出功率大等优点。但是由于电路工作在开关状态,所以噪声比较大。
举例说明:降压型开关电源

我们来简单的说说降压型开关电源的工作原理:电路由开关(实际电路中为三极管或者场效应管),续流二极管、储能电感、滤波电容等构成。

当开关闭合时,电源通过开关、电感给负载供电,并将部分电能储存在电感以及电容中。由于电感的自感,在开关接通后,电流增大得比较缓慢,即输出不能立刻达到电源电压值。
一定时间后,开关断开,由于电感的自感作用(可以比较形象的认为电感中的电流有惯性作用),将保持电路中的电流不变,即从左往右继续流。这电流流过负载,从地线返回,流到续流二极管的正极,经过二极管,返回电感的左端,从而形成了一个回路。
通过控制开关闭合跟断开的时间(即PWM——脉冲宽度调制),就可以控制输出电压。如果通过检测输出电压来控制开、关的时间,以保持输出电压不变,这就实现了稳压的目的。   普通电源和开关电源相同的是都有电压调整管,利用反馈原理来进行稳压的,不同的是开关电源利用开关管进行调整,普通电源一般利用三极管的线性放大区进行调整。比较而言,开关电源的能耗低,对交流电压适用范围要宽,输出直流的波纹系数要好,缺点是开关脉冲干扰。
  普通半桥开关电源的主要工作原理就是上桥和下桥的开关管(频率高时开关管为VMOS)轮流导通,首先电流通过上桥开关管流入,利用电感线圈的存储功能,将电能集聚在线圈中,最后关闭上桥开关管,打开下桥的开关管,电感线圈和电容持续给外部供电。然后又关闭下桥开关管,再打开上桥让电流进入,就这样重复进行,因为要轮流开关两开关管,所以称为开关电源。  而线性电源就不一样了,由于没有开关介入,使得上水管一直在放水,如果有多的,就会漏出来,这就是我们经常看到的某些线性电源的调整管发热量很大,用不完的电能,全部转换成了热能。从这个角度来看,线性电源的转换效率就非常低了,而且热量高的时候,元件的寿命势必要下降,影响最终的使用效果。

主要区别:工作方式
线性电源的功率调整管总是工作在放大区,流过的电流是连续的。由于调整管上损耗较大的功率,所以需要较大功率调整管并装有体积很大的散热器,发热严重,效率很低,一般在40%~60%(还得说是很好的线性电源)。
线性电源的工作方式,使从高压变低压必须有将压装置,一般的都是变压器,也有别的像KX电源,再经过整流输出直流电压。这样一来体积也就很大,比较笨重,效率低、发热量也大;但也有优点:纹波小、调整率好、对外干扰小、适合用与模拟电路/各类放大器等。  开关电源它的功率器件工作在开关状态,在电压调整时能量是通过电感线圈来临时贮存,这样他的损耗就小,效率也就高,对散热的要求低,但它对变压器和贮能电感也有了更高的要求,要用低损耗高磁导率的材料来做。它的变压器就是一个字小。总效率在80%~98%,开关电源的效率高但体积小,但是和线性电源比他的纹波,电压电流调整率就有一定的折扣了。

20230807-vMix教程合集

vMIx-为我所用 为所欲为

vMix是一款PC系统上功能丰富的现场视频制作软件,无论是简单的视频播放还是现场直播制作,vMix都能处理。对于很多首次接触vMix的用户可能会被软件众多按键迷惑,再加上软件自带的谷歌中文翻译,很多中文翻译的还不如英文好懂。为提高视频直播和录播从业人员的操作水平,共同促进行业发展,智合影音为大家制作了系列vMix的教学视频,欢迎大家一同学习交流。

vMIx 学习区

01、VMIX23正版下载地址,授权使用年限99年
02、打开VMIX第一步,界面那些事你该知道

03、vMix软件版本介绍

04、如何购买vmix软件和价格差异注意事项

05、vMix23用户指南汉化DOC版下载

06、如何添加素材?摄像机、视频、图片、PPT、NDI、虚拟背景等等

07、详解VMIX内置录制功能、这个功能能为你省几千块钱呢

08、意外导致VMIX录制文件受损,别急简单三步修复MP4文件

09、了解VMIX素材通道设置功能,能让你欲罢不能的爱上它

10、鼠标操作详解常用功能与事项,新手训练必经之路

11、2分钟部署VMIX录、推流直播,轻松上手

12、VMIX中角标设置功能的详解和运用,怎么开心怎么来

13、详解VMIX的内置调音台功能,你想了解的都给你说明白了!

14、VMIX竖屏推流直播,只需操作3步!附最新VMIX22.0.0.69下载地址

15、VMIX下使用高视T80推流器声音设置教程

16、解决vmix中音画不同步的问题!你只需一步。

17、详解VMIX推流教程,最多三路同时进行直播

18、VMIX拉流演示教程!简单粗暴一看就懂

19、详解VMIX拉流教程,拉流云导播与输出的运用技巧

20、VMIX拓展2屏3屏教程:想输出啥就输出啥

21、VMIX教程:详解本地(显卡)输出,最多可以输出3路不同画面

22、详解vmix的NDI输出功能教学,广电IP化你要学不?

23、新版vmix23:SRT功能使用教程,低延时更安全,更稳定!

24、专业旗舰版vmix锐隼v12导播切换控制面板(附使用教程)

25、vmix即时回放及对应回放键盘的使用说明

26、vmix call教程:远程互动不是事!何须东拼西凑惹麻烦

27、vMix颜色矫正,让你直播输出瞬间成大片!超实用

28、vMix汉化包下载:从此告别别扭的界面菜单了!

29、vMix常见推流错误诊断与处理办法,开启GPU+Cpu报警

30、vMix Call隆重升级,新增直接连接、低延迟模式。能不香?

31、如何在vMix中捕获另一台计算机的显示或屏幕

32、vMix开播之前的准备工作,养成好的习惯是一点要的

33、采购直播一体机只看参数?那得看你的道行够不够?不行就缴个学费呗

34、安全低延时的SRT应用,vMix远程互动连接设置教程

35、vMix技巧运用:白平衡

img

vMIx 技巧区

01、BmD和vmix等导播切换ZhiHe1.0安装使用教程

02、2分钟学会VMIX绿布抠像和虚拟演播室应用

03、4K摄像机+VMIX 4K一体机,2分钟轻松搞定4机位直播

04、midi导播切换键盘的vmix快捷键教程视频

05、BMDATEM系列切换台控制面板的快捷键映射教程

06、1分钟学会淘宝、快手、一直播、多平台多机位直播!

07、虚拟演播室的色彩键扣像及虚拟场景讲解

08、标题制作和叠加层使用介绍,原来这么简单

09、添加比赛比分字幕条和便捷管理比分,提高效率必不可少

10、VMIX画中画功能的详解和运用,想怎么变就怎么变

11、详解VMIX的特效转场及应用,高大上的特效说来就来

12、NDI技术介绍及与直播软件vMix的结合,广播级视频如何在IP空间高效传输

13、硬件|vmix系统硬件配置要求与采集卡选择讲解,新手少走弯路喔

14、vmix使用教程:让导播更轻松方便的多屏幕显示功能

15、收藏|vmix 快捷键代码(中文对照表)赠送:VMIX用户中文指南

16、字幕标题:Vmix GT编辑器快速入门指南,你的酷炫自己主张

17、关于vMix和NDI您需要了解的内容,附Windows与Mac工具下载地址

18、摄像师构图不好?导播控制面板来凑,强大到你没法想象

19、新手进阶|利用Excel表格批量管理字幕条,即省心又省力,赶紧收藏

20、vMix中文版:自行汉化不求人,提供中文语言包下载

21、VMIX 23 下Srt协议编码器推流设置教程,最低公网延时800毫秒

22、vMix拉流插件最新版:vLC3.0.8下载(推荐),各种流各种拉

23、vMix小技巧:专业的老司机都在用这两个功能!你用了吗?

24、vMix配合钉钉多机位直播教程:响应教育部“停课不停学”

25、如何用vMix实现多连线低延时互动?vMix Call另类应用

26、学习vMix竖屏直播:把时间抢回来,把损失补回来。

27、快手多机位竖屏实时抠像直播教程,同样适用于淘宝、抖音等APP直播

28、两种vMIx字幕标题批量管理,附快捷键设置教程,高效快捷管理字幕

29、微电影,电商,教育,异地连线类直播这样玩,酷到没有朋友!

30、vMix应用网红小视频拍摄,谁说除了直播才能赚钱!谁都行

31、vMix虚拟演播室制作教程:求人不如自己会

32、如何将Blackmagic Decklink Quad2映射为8个通道

33、vMix官方教程:从同一台计算机向vMix添加Zoom(会议系统)调用

34、vMix实时歌词显示实战方案,失败中寻找最安全的方式

35、体育赛事:如何使用键盘控制vMix中的记分板,多人协作更安全

36、如何将虚拟摄像机(vMix Video)输出发送到第三方应用程序和Web浏览器

37、允许Mac的vMix Desktop Capture权限访问您的屏幕

38、将MultiCorder与vMix Call一起使用时的多个录音文件

39、vMix中添加GIF动画,只要姿势正确,为什么不行呢?

40、vMix时钟和计时器选项,非常实用的功能设置

41、vMix如何设置音频延迟将音频和视频同步,切记切记

42、vMix多开?官方就支持何必去花9.9元?点一下就OK了

43、将iPhone或iPad与vMix Call一起使用时帧速率较低,附解决办法

44、诊断SRT连接vMix:有些细节你千万要注意

45、将PowerPoint幻灯片手动导入vMix,这个技能一般人不会

46、vMix4K直播:在4通道4K模式下使用DeckLink 8K Pro

47、vMix通话音频质量:需要传输高质量的看过来

48、vMix使用NDI虚拟输入时Zoom中没有音频:附解决方案

49、vMix工具:如何将视频转换为图像序列,不需要技术也能搞定

50、vMix不用输出卡如何使用Key / Fill输到导播台

51、如何将Excel,CSV,XML,RSS,JSON和文本与vMix数据源一起使用

52、新技能:如何为vMix Call设置按钮对讲

53、DIY虚拟演播室必备:vMix虚拟集规范1.0

54、高视T80接电脑拓展,竖屏推流直播VMIX设置教程

55、vMix官方推介:笔记本电脑最佳做法!

56、安全低延时的SRT应用,vMix远程互动连接设置教程

57、vMix增加输出卡设置,HDMI与SDI可以自由拓展

58、案例:vMix如何连接NDI和ZooM

59、抖音直播:竖屏、横屏、美颜没有推流地址就不播了?来我教你

60、淘宝直播:横屏、竖屏、滤镜、美颜没有推流地址也行,教程来了

61、储备:如何设计虚拟集(虚拟演播室),你的酷炫你主张

62、vMix虚拟演播室制作:从PSD到TriCaster虚拟集编辑器的演示

63、vMix教程:自定义虚拟集(虚拟演播室),附1080p UV Map文件的示例下载

64、直播调色:vMix中色彩校正使用指南,专业直播软件哪家强?

65、教程:vMix如何使用Vset3D虚拟集,3D虚拟演播室来了

66、vMix玩家分享:同时输出推流PVW和PGM画面,你会用了吗?

67、百度高清直播:vMix如何进行横屏竖屏推流,怎么获取推流地址

68、图形适配器设置:提高NVIDIA Optimus笔记本电脑性能

69、vMix教程:设计虚拟演播室背景如何使用uvmaps进行设置

70、视频号放大招:PC版微信就能电脑直播,臊起来臊起来

71、如何发起百度直播:支持横屏、竖屏推流,关键还是免费的

72、vMix技巧:字幕功能巧用秒变提词器

73、如何在vMix中使用SRT URL推流和拉流,微赞实战演练

74、微信视频号PC端直播正式更新,支持PC端竖屏直播了

75、vMix通话音频质量技巧提示,并提供新的vMix Call网站

76、vMix虚拟集制作教程:用PS制作自己的虚拟演播室

vMix高级教程:脚本

01、vMix高级应用教程:脚本(第一期)

02、vMix高级脚本应用教程:如何插入广告视频(第二期)

03、vMix高级脚本应用教程:徽标与标题运用(第三期)

04、vMix高级脚本应用教程:自动更新天气预报(第四期)

img

传输区:

01、4机位多功能混合光纤布线示范连接与注意事项

02、HDMI光端机与导播切换台连接应用教程

03、现场5000人规模:首次实战无人值守2机位,浅谈无人化直播的方向

04、低成本的公里级4K无线图传测试,或许你的方案正好需要

05、HDMI光纤线的采购与使用,4K传输的最佳解决方案

06、vMix音频输入设置与音频连接线的分享,能有效避免翻车

直播必备

01、直播必备神器:高视T80聚合图传系统及K60聚合路由器

02、V66视频直播一体机使用指南V2.0

03、智合影音 4K便携一体机解决方案

04、无线图传使用指南

05、推荐采集卡:BMD、美乐威、天创不一样的地方

06、开启vMix TALLY灯的正确姿势,USB接口,省钱省力还特方便

09、智合X1 HDX8采集卡终结版,七大优势舍我其谁

10、单路4K60HZ :1080P120,144,240HZ/ 2K 144HZ采集卡发布

11、原创雷电3采集卡发售:4路SDI/HDMI同步发行,爽得不行

12、Z4限量版正式发售:专业声卡,8路聚合,5GWiFi、一个都不少

img

vMIx 答疑区

01、选择简体中文版和怎么添加视频等素材

02、推流的时候发生错误!地址填对的?怎么回事?

03、解决办法:卸载VMIX软件重新安装后打开出现的错误

04、vMix底部的警告CPU GPU超载消息是什么?

05、疑难杂症:启动vMix时类未注册错误,或许你也会遇见

06、vMix答疑:VMIX正版之间的差异与价格,附今日正版价格

07、vMix答疑:序列号可以安装在多台PC上吗?看官方答复

08、vMix答疑:vMix可以在Mac上运行吗?答案是可以间接安装

09、vMix答疑:在Windows 10中添加Flash / RTMP输入时闪退或者死机

10、vMix答疑:在Win7上使用Desktop Capture时出错,代码:c000001d

11、vMix答疑:Windows 10更新后打开录制设置时,vMix关闭并显示错误消息 代码:KB4013429

12、快报:vMix发布23beta版,与22有啥不一样呢?附23下载地址

13、vMix答疑:vMix 23新功能和更改, 第一个支持SRT输入/输出的软件

14、vMix答疑:如何开启CPU、GPU报警及录制时间显示

15、vMix闪退、死机?不稳定?你可能没有注意到一些细节

16、vMix正版一号两机序列号如何管理,教程来了请收藏

17、使用多个USB采集捕获设备存在问题?你可能要先了解一下

18、使用vMix Call诊断连接问题,vMix呼叫防火墙要求

19、vMix答疑:Web浏览器输入音频不起作用,注意这两个原因即可

20、如何通过vMix在现场制作中使用SRT?SRT代表“安全可靠的传输”

21、vMix左下角的使用情况/性能统计信息是什么意思?

22、vMix为什么“推流”按钮有时显示橙色或琥珀色?越早知道越好

23、vMix添加网络摄像头:“系统资源不足,无法完成请求的服务”是什么意思?

24、使用vMix NDI桌面捕获时,PPt幻灯片有时不更新

25、vMix在多个素材切换时主音频没有声音?这个功能一定要关

26、笔记本安装vMix使用Web浏览器输入时黑屏,Nvidia Optimus图形显卡看过来

27、vMix每个版本中的“总输入量”和“摄像机输入”是什么意思?

28、请注意:vMix输入在某些笔记本电脑上可能会闪烁

29、vMix Call 呼叫安全:硬知识你要了解

30、vMix为什么在使用Blackmagic卡时看到黑屏或错误?

31、通过vMix接收UDP流某些传输时发生流错误

32、vMix答疑:安装了扩展程序的SRT中的HEVC错误

33、vMix音频混合基础知识和故障排除,这些不明白就白瞎

34、vMix答疑:添加音频输入时出现错误0x88890008

35、vMix答疑:来自两个NDI-HX摄像机的相同视频源

36、vMix答疑:如何在vMix中手动升级NDI版本

37、为什么在vMix中的输出上方和下方看到黑条?

38、PsF是什么意思?为什么vMix中添加摄像机素材有拖尾现象

39、安装或更新vMix时出错,一定要记住这一点

40、vMix是否支持可以使用8个以上的vMix Call呼叫?

41、官方答疑:vMix Call 呼叫管理器超时错误

42、vMix官方答疑:GT (标题设计师) PSD导入限制

43、盘点vMix最容易翻车那些事,老司机也常犯错

44、官方教程:什么是ISO记录?vMix支持吗?

45、底噪?噪音?电流声?如何排查直播中遇见的音频问题

46、vMix Desktop Capture:桌面捕获性能提示,铁律必知

47、诊断vMix掉帧:高渲染负载过多,11条建议教你怎么判断

48、vMix疑问:PowerPoint中的动画和过渡

49、vMix优化系统性能:提高工作效率,远离翻车

50、使用vMix Flash / RTMP拉流时闪退,解决办法看这里

51、视频不连贯,损坏,块状或空白?处理方法来了,请收藏

52、vMix官宣:全面停止flash拉流支持,附解决办法

53、vMix疑问:停止录制在某些显卡上不起作用,附解决办法

54、vMix24中添加慢动作回放错误提示

55、vMix解答:VST3插件“无法配置插件”

56、vMix 24检测:NDI的编码器隔离模式(FEIM)错误

20230804-字符串匹配算法(C语言实现)

前言

字符串匹配算法 又称模式匹配算法,该算法的目的是为了子串从主串中寻找是否有与其匹配的部分

其可分为BF暴力检索,RK 哈希检索,KMP BM 等等,本文仅介绍BF 算法和KMP 算法的视线,前者的时间复杂度是O(mn) ,后者的时间复杂度为O(m+n),本文就是对这两者的核心思路进行总结分析,以加强记忆。

算法的思路如下:

代码实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include<stdio.h>
#include<assert.h>
#include<string.h>

int BF(char* str, char* sub)//str代表主串,sub代表子串
{
assert(str&&sub);//断言
if (str == NULL || sub == NULL)//串为空值时直接返回-1
{
return -1;
}
int i = 0;//遍历主串
int j = 0;//遍历子串
int lenstr = strlen(str);//求出主串的长度
int lensub = strlen(sub);//求出子串的长度
while ((i < lenstr) && (j < lensub))//当子串遍历结束或主串遍历结束时,跳出循环
{
if (str[i] == sub[j])//匹配成功
{
i++;
j++;
}
else//匹配失败
{
i = i - j + 1;
j = 0;
}
}
if (j >= lensub)//如果是因为子串遍历结束而跳出循环,说明匹配成功,返回下标
{
return i - j;
}
else//匹配失败,返回-1
return -1;
}
int main()
{
printf("%d\n", BF("ababcabcdabcde", "abcd"));//匹配成功,预期返回下标5
printf("%d\n", BF("ababcabcdabcde", "abcds"));//匹配失败,返回-1
printf("%d\n", BF("ababcabcdabcde", "ab"));//匹配成功,返回下标0

return 0;
}

BF 算法缺点,有大量匹配无效,效率低

KMP 算法

  1. 算法介绍

KMP算法是一种改进的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R.Pratt同时发现,因此人们称它为克努特–莫里斯–普拉特操作(简称KMP算法)。KMP算法的关键是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的。具体实现就是实现一个next()函数,函数本身包含了模式串的局部匹配信息。时间复杂度O(m+n)。

  1. 算法思路

next 数组的求解

例:有一个字符串ababcabc ,求其对应的next 数组

解 第一个字符对应的next 数组值为-1,第二个字符对应的next 数组值为0 ,从第三个字符开始,判断第一个字符和第n-1 个字符是否有匹配的

数学分析:

假设next[i]=k,可推出p[0]…p[k-1]=p[x]…p[i-1],既k-1-0=i-1-x,得x=i-k

即p[0]…p[k-1]=p[i-k]…p[i-1]

若能证得p[i]==p[k],则可求得next[i+1]=k+1。

若p[i]!=p[k],next[i+1]=??

举个例子:

代码分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
void GetNext(char* sub, int* next, int lensub)/*sub代表子串;next是外部开辟的动态内存数组;lensub是子串长度*/
{
next[0] = -1;
next[1] = 0;
int i = 2;//当前i下标
int k = 0;//前一项的k

while(i < lensub)
{
if (k == -1 || sub[i - 1] == sub[k])//k回退到-1或前一项sub[i-1]==sub[k]
{
next[i] = k + 1;
i++;
k++;
}
else
{
k = next[k];//if条件不满足时则需将k回退到-1下标
}
}
}

附加知识:next 数组的优化

同样以例子来讲

图中所示,当i=5时匹配失败,若按照nextr 数组回退的话,到i=4时,依旧是a,匹配失败还得回退,每次回退都是相同的字符,这些回退无疑是无效的。而nextval数组就是对这一现象的优化。

3.整体代码的实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#include<stdio.h>
#include<assert.h>
#include<string.h>
#include<stdlib.h>
void GetNext(char* sub, int* next, int lensub)/*sub代表子串;next是外部开辟的动态内存数组;lensub是子串长度*/
{
next[0] = -1;
next[1] = 0;
int i = 2;//当前i下标
int k = 0;//前一项的k

while(i < lensub)
{
if (k == -1 || sub[i - 1] == sub[k])//k回退到-1或前一项sub[i-1]==sub[k]
{
next[i] = k + 1;
i++;
k++;
}
else
{
k = next[k];//if条件不满足时则需将k回退到-1下标
}
}
}

int KMP(char* str, char* sub, int pos)/*str:代表主串;sub:代表子串;pos:代表从主串的pos位置开始找*/
{
assert(str&&sub);//断言
if (str == NULL || sub == NULL)//字符串为空直接返回-1
return -1;
int lenstr = strlen(str);//求主串长度
int lensub = strlen(sub);//求子串长度
if (pos < 0 || pos >= lenstr)//pos位置不合法直接返回-1
return -1;

int *next = (int*)malloc(sizeof(int)*lensub);//开辟动态内存给next数组存放数据
assert(next);

GetNext(sub, next,lensub);//求出next数组

int i = pos;//遍历主串
int j = 0;//遍历子串

while (i < lenstr&&j < lensub)
{
if (j == -1 || str[i] == sub[j])
{
i++;
j++;
}
else
{
j = next[j];
}
}
free(next);
next = NULL;
if (j >= lensub)
{
return i - j;
}
return -1;
}

int main()
{
printf("%d\n", KMP("ababcabcdabcde", "abcd", 0));//预期返回5
printf("%d\n", KMP("ababcabcdabcde", "abcdf", 0));//预期返回-1
printf("%d\n", KMP("ababcabcdabcde", "ab", 0));//预期返回0
return 0;
}

总结

以上就是今天要讲的内容,本文介绍了关于字符串匹配的BF算法和KMP算法,通过比特大博哥的视频学习,对算法思路与实现代码进行理解和分析,简单学习记录。欢迎大家探讨指正!

20230804-使用strchr与strrchr函数查找单个字符

http://c.biancheng.net/view/340.html

使用 strchr 与 strrchr 函数查找单个字符

如果需要对字符串中的单个字符进行查找,那么应该使用 strchr 或 strrchr 函数。其中,strchr 函数原型的一般格式如下:
它表示在字符串 s 中查找字符 c,返回字符 c 第一次在字符串 s 中出现的位置,如果未找到字符 c,则返回 NULL。也就是说,strchr 函数在字符串 s 中从前到后(或者称为从左到右)查找字符 c,找到字符 c 第一次出现的位置就返回,返回值指向这个位置,如果找不到字符 c 就返回 NULL。

相对于 strchr 函数,strrchr 函数原型的一般格式如下:

1
char *strrchr(const char *s, int c);

与 strchr 函数一样,它同样表示在字符串 s 中查找字符 c,返回字符 c 第一次在字符串 s 中出现的位置,如果未找到字符 c,则返回 NULL。但两者唯一不同的是,strrchr 函数在字符串 s 中是从后到前(或者称为从右向左)查找字符 c,找到字符 c 第一次出现的位置就返回,返回值指向这个位置。下面的示例代码演示了两者之间的区别:

1
2
3
4
5
6
7
8
9
int main(void)
{
char str[] = "I welcome any ideas from readers, of course.";
char *lc = strchr(str, 'o');
printf("strchr: %s\n", lc);
char *rc = strrchr(str, 'o');
printf("strrchr: %s\n", rc);
return 0;
}

对于上面的示例代码,strchr 函数是按照从前到后的顺序进行查找,所以得到的结果为

“ome any ideas from readers,of course.”; 而 strrchr 函数则相反,它按照从后到前的顺序进行查找,所以得到的结果为“ourse.”。
示例代码运行结果为:strchr: ome any ideas from readers, of course.strrchr: ourse.

其实原因很简单,这里用的是字符的 ASCII 码(因为每个字符都对应着一个 ASCII 码),这样在传值的时候既可以传“char”类型的值,又可以传“int”类型的值(0 ~ 127)。

使用 strpbrk 函数查找多个字符

上面的 strchr 与 strrchr 函数解决了对字符串中单个字符的查找,那么需要查找多个字符时怎么办呢?
如果要查找多个字符,就需要使用 strpbrk 函数了。该函数在源字符串(s1)中按从前到后顺序找出最先含有搜索字符串(s2)中任一字符的位置并返回,空字符 null(‘\0’) 不包括在内,若找不到则返回空指针。其函数原型的一般格式如下:

1
char *strpbrk(const char *s1,const char *s2);

例如,在 strpbrk 函数的定义如下:

1
2
3
4
5
6
7
8
9
10
11
12
char *strpbrk (const char *s, const char *accept)
{
while (*s != '\0')
{
const char *a = accept;
while (*a != '\0')
if (*a++ == *s)
return (char *) s;
++s;
}
return NULL;
}

如上面的代码所示,strpbrk 数首先依次循环检查字符串 s 中的字符,当被检验的字符在字符串 accept 中也包含时(即if(*a++==*s)),则停止检验,并返回(char*)s。如果没有匹配字符,则返回空指针 NULL。这里需要注意的是,空字符 null('\0')不包括在内。函数的调用示例如下面的代码所示:

1
2
3
4
5
6
7
int main(void)
{
char str[] = "I welcome any ideas from readers, of course.";
char *rc=strpbrk(str,"come");
printf("%s\n",rc);
return 0;
}

很显然,示例代码的运行结果为“elcome any ideas from readers,of course.”。

使用 strstr 函数查找一个子串

相对于 strpbrk 函数,strstr 函数表示在字符串 haystack 中从前到后查找子串 needle 第一次出现的位置(不比较结束符 null('\0')),并返回指向第一次出现 needle 位置的指针,如果没找到则返回 NULL。其函数原型的一般格式如下:

1
char *strstr(const char *haystack, const char *needle);

strstr 函数的调用示例如下面的代码所示:

1
2
3
4
5
6
7
8
9
int main(void)
{
char str[] = "I welcome any ideas from readers, of course.";
char *c1=strstr(str, "come");
printf("come:%s\n",c1);
char *c2=strstr(str, "icome");
printf("icome:%s\n",c2);
return 0;
}

这里需要注意的是,因为 strstr 函数与 strpbrk 函数不同,strstr 函数匹配的是字符串,所以语句strstr(str,"icome")将返回 NULL。运行结果为:

strspn 函数表示从字符串 s 的第一个字符开始,逐个检查字符与字符串 accept 中的字符是否不相同,如果不相同,则停止检查,并返回以字符串 s 开头连续包含字符串 accept 内的字符数目。其函数原型的一般格式如下:

1
size_t strspn(const char *s, const char *accept);

例如,该函数的定义如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
size_t strspn (const char *s,const char *accept)
{
const char *p;
const char *a;
size_t count = 0;
for (p = s; *p != '\0'; ++p)
{
for (a = accept; *a != '\0'; ++a)
if (*p == *a)
break;
if (*a == '\0')
return count;
else
++count;
}
return count;
}

从上面的示例代码中可以看出,strspn 函数从字符串参数 s 的开头计算连续的字符,而这些字符完全是 accept 所指字符串中的字符。简单地说,如果 strspn 函数返回的数值为 n,则代表字符串 s 开头连续有 n 个字符都属于字符串 accept 内的字符。

函数的调用示例如下面的代码所示:

1
2
3
4
5
6
7
8
9
int main(void)
{
char str[] = "I welcome any ideas from readers, of course.";
printf("I wel:%d\n",strspn(str,"I wel"));
printf("Iwel:%d\n",strspn(str,"Iwel"));
printf("welcome:%d\n",strspn(str,"welcome"));
printf("5:%d\n",strspn(str,"5"));
return 0;
}

在上面的示例代码中,因为 strspn 函数返回的是以字符串 s 开头连续包含字符串 accept 内的字符数目。而源字符串 str 中的“I”与“welcome”之间有一个空格(即“I welcome”),所以,语句“strspn(str,”Iwel”)”将返回 1,而语句“strspn(str,”I wel”)”将返回 5。因此,输出结果为:I wel:5Iwel:1welcome:05:0

相对于 strspn 函数,strcspn 函数与之相反,它表示从字符串 s 第一个字符开始,逐个检查字符与 reject 中的字符是否相同,如果相同,则停止检查,并返回以字符串 s 开头连续不含字符串 reject 内的字符数目。其函数原型的一般格式如下:

1
size_t strcspn(const char *s, const char *reject);

该函数的定义如下:

1
2
3
4
5
6
7
8
9
10
size_t strcspn (const char *s,const char *reject)
{
size_t count = 0;
while (*s != '\0')
if (strchr (reject, *s++) == NULL)
++count;
else
return count;
return count;
}

从上面的代码中不难发现,strcspn 函数正好与 strspn 函数相反。strcspn 函数从字符串参数 s 的开头计算连续的字符,而这些字符都完全不在参数 reject 所指的字符串中。简单地说,如果 strcspn 函数返回的数值为 n,则代表字符串 s 开头连续有 n 个字符都不包含字符串 reject 内的字符。

函数的调用示例如下面的代码所示:

1
2
3
4
5
6
7
8
9
int main(void)
{
char str[] = "I welcome any ideas from readers, of course.";
printf("I wel:%d\n",strcspn(str,"I wel"));
printf("Iwel:%d\n",strcspn(str,"Iwel"));
printf("welcome:%d\n",strcspn(str,"welcome"));
printf("5:%d\n",strcspn(str,"5"));
return 0;
}

在上面的示例代码中,因为 strcspn 函数返回的是以字符串 s 开头连续不包含字符串 accept 内的字符数目。因此,其运行结果为:

I wel:0
Iwel:0
welcome:2
5:45

由此可见,对于 strspn 函数,如果找到了 reject 与 s 不相同元素时,指针停止移动,并返回以字符串 s 开头连续包含字符串 accept 内的字符数目;而 strncspn 函数则是找到了 reject 与 s 相同元素时,指针停止移动,并返回以字符串 s 开头连续不包含字符串 accept 内的字符数目。这一点一定要注意,千万不要混淆了。

20230803-C语言如何实现动态数组

提出问题

请问在c语言里如何实现动态大小的数组啊,比如说int a[N];,这里N的值可以在程序中定,或者有什么方法可以实现类似的功能?总之只要在编译时不用制定数组大小就行。

分析问题

嵌入式系统的内存是宝贵的,内存是否高效率的使用,往往意味着嵌入式设备的高质量和高性能,有时我们所需的内存空间无法预先确定,这里使用静态数组的办法很难解决,所以高效的使用内存对我们来说是很重要的。

所以我们在自己编写C语言代码的时候,就应该学会使用动态数组,那么怎么实现呢?

静态数组与动态数组的区别

对于静态数组,一旦定义了,数组长度也就指定好了,系统将为它分配一个固定大小的空间,使用完无需释放,引用简单,但是创建后无法改变其大小,这在应用中是一个致命弱点!

对于动态数组,它可以随程序需要而重新指定大小,其创建麻烦,使用完必须由程序员自己释放,否则将会引起内存泄露。但其使用非常灵活,能根据程序需要动态分配大小。所以相对于静态数组的来说我们对于使用动态数组有很大的自由度。

动态数组的内存空间是从堆上分配的,通过执行代码而为其分配存储空间。当程序执行到这些语句时,才为其分配,程序员自己负责释放内存。

在创建动态数组的过程中要遵循以下原则:

  • 在创建的时候从外层往里层,逐层创建;
  • 在释放的时候从里层往外层,逐层释放。

如何创建动态数组?

下面是一个创建动态数组的例子,按照需求设置数组大小:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <stdio.h>
#include <stdlib.h>
int main(){
int arrLen;
int *array;
int i;
printf("please enter length:");
scanf_s("%d", &arrLen);

array = (int*)malloc( arrLen*sizeof(int) );
if(!array){
printf("create error!\n");
exit(1);
}
for(i=0; i<arrLen; i++){
array[i] = i+1;
}

for(i=0; i<arrLen; i++){
printf("%d ", array[i]);
}

printf("\n");
free(array);

system("pause");
return 0;
}

运行结果:

img

使用内存中的数据

上面的代码中,我们通过下标array[i]来引用数组元素,这个静态数组没有什么区别。另外还可以通过指针来引用数组元素,对上面的程序稍作修改:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <stdio.h>
#include <stdlib.h>
int main(){
int arrLen;
int *array;
int *arrayCopy;//用来指向具体的数组元素
int i;
printf("please enter length:");
scanf_s("%d", &arrLen);

arrayCopy = array = (int*)malloc( arrLen*sizeof(int) );
if(!array){
printf("create error!\n");
exit(1);
}

for(i=0; i<arrLen; i++){
*arrayCopy++ = i+1;
}

arrayCopy = array;//重置到数组首地址
for(i=0; i<arrLen; i++){
printf("%d ", *arrayCopy++);
}

printf("\n");
free(array);

system("pause");
return 0;
}

需要注意的是,free() 函数必须释放整块内存,多定义一个变量 arrayCopy,不断改变它的值,以指向不同的数组元素。这样可以保证 array 变量的值不变,始终指向内存首地址,用于free()整块内存。

当然也可以动态创建多维数组,其原理都是一样的,并且需要遵循创建与释放的原则。

20230802-cpp中cin的详细用法

1.cin简介

cin是C++编程语言中的标准输入流对象,即istream类的对象。cin主要用于从标准输入读取数据,这里的标准输入,指的是终端的键盘。此外,cout是流的对象,即ostream类的对象,cerr是标准错误输出流的对象,也是ostream 类的对象。这里的标准输出指的是终端键盘,标准错误输出指的是终端的屏幕。

在理解cin功能时,不得不提标准输入缓冲区。当我们从键盘输入字符串的时候需要敲一下回车键才能够将这个字符串送入到缓冲区中,那么敲入的这个回车键(\r)会被转换为一个换行符\n,这个换行符\n也会被存储在cin的缓冲区中并且被当成一个字符来计算!比如我们在键盘上敲下了123456这个字符串,然后敲一下回车键(\r)将这个字符串送入了缓冲区中,那么此时缓冲区中的字节个数是7 ,而不是6。

cin读取数据也是从缓冲区中获取数据,缓冲区为空时,cin的成员函数会阻塞等待数据的到来,一旦缓冲区中有数据,就触发cin的成员函数去读取数据。


2. cin的常用读取方法

使用cin从标准输入读取数据时,通常用到的方法有cin>>,cin.get,cin.getline。

2.1cin>>的用法

cin可以连续从键盘读取想要的数据,以空格、tab或换行作为分隔符。实例程序如下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>
using namespace std;

int main()
{
char a;
int b;
float c;
string
cin>>a>>b>>c;
cout<<a<<" "<<b<<" "<<c<<" "<<endl;

system("pause");
return 0;
}

在屏幕中一次输入:a[回车]11[回车]5.56[回车],程序将输出如下结果:

注意:
(1)cin>> 等价于cin.operator>>(),即调用成员函数operator>>()进行读取数据。
(2)当cin>>从缓冲区中读取数据时,若缓冲区中第一个字符是空格、tab或换行这些分隔符时,cin>>会将其忽略并清除,继续读取下一个字符,若缓冲区为空,则继续等待。但是如果读取成功,字符后面的分隔符是残留在缓冲区的,cin>>不做处理。
(3)不想略过空白字符,那就使用 noskipws 流控制。比如cin>>noskipws>>input;

验证程序见如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <string> 
#include <iostream>
using namespace std;

int main()
{
char a;
int b;
float c;
string str;
cin>>a>>b>>c>>str;
cout<<a<<" "<<b<<" "<<c<<" "<<str<<endl;

string test;
getline(cin,test);//不阻塞
cout<<"test:"<<test<<endl;
system("pause");
return 0;
}

从键盘输入:[回车][回车][回车]a[回车]5[回车]2.33[回车]hello[回车],输出结果是:

从结果可以看出,cin>>对缓冲区中的第一个换行符视而不见,采取的措施是忽略清除,继续阻塞等待缓冲区有效数据的到来。但是,getline()读取数据时,并非像cin>>那样忽略第一个换行符,getline()发现cin的缓冲区中有一个残留的换行符,不阻塞请求键盘输入,直接读取,送入目标字符串后,再将换行符替换为空字符’\0’,因此程序中的test为空串。

2.2 cin.get的用法

该函数有有多种重载形式,分为四种格式:无参,一参数,二参数,三个参数。常用的的函数原型如下:

1
2
3
4
int cin.get();
istream& cin.get(char& var);
istream& get ( char* s, streamsize n );
istream& get ( char* s, streamsize n, char delim )

其中streamsize 在VC++中被定义为long long型。另外,还有两个重载形式不怎么使用,就不详述了,函数原型如下:

1
2
istream& get ( streambuf& sb);
istream& get ( streambuf& sb, char delim );

2.2.1 cin.get读取一个字符

读取一个字符,可以使用cin.get或者cin.get(var),示例代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>
using namespace std;

int main()
{
char a;
char b;
a=cin.get();
cin.get(b);
cout<<a<<b<<endl;
system("pause");
return 0;
}

输入:e[回车],输出:

注意:
(1)从结果可以看出,cin.get()从输入缓冲区读取单个字符时不忽略分隔符,直接将其读取,就出现了如上情况,将换行符读入变量b,输出时打印两次。

(2)cin.get()的返回值是int类型,成功:读取字符的ASCII码值,遇到文件结束符时,返回EOF,即-1,Windows下标准输入输入文件结束符为Ctrl+z,Linux为Ctrl+d。cin.get(char var)如果成功返回的是cin对象,因此可以支持链式操作,如cin.get(b).get(c)。

2.2.2 cin.get读取一行

读取一行可以使用istream& get ( char* s, streamsize n )或者istream& get ( char* s, size_t n, streamsize delim )。二者的区别是前者默认以换行符结束,后者可指定结束符。n表示目标空间的大小。示例代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>
using namespace std;

int main()
{
char a;
char array[20]={NULL};
cin.get(array,20);
cin.get(a);
cout<<array<<" "<<(int)a<<endl;
system("pause");
return 0;
}

输入:123456789[回车],输出:

注意:
(1)从结果可以看出,cin.get(array,20);读取一行时,遇到换行符时结束读取,但是不对换行符进行处理,换行符仍然残留在输入缓冲区。第二次由cin.get()将换行符读入变量b,打印输入换行符的ASCII码值为10。这也是cin.get()读取一行与使用getline读取一行的区别所在。getline读取一行字符时,默认遇到\n时终止,并且将\n直接从输入缓冲区中删除掉,不会影响下面的输入处理。

(2)cin.get(str,size);读取一行时,只能将字符串读入C风格的字符串中,即char*,但是C++的getline函数可以将字符串读入C++风格的字符串中,即string类型。鉴于getline较cin.get()的这两种优点,建议使用getline进行行的读取。关于getline的用法,下文将进行详述。

2.3 cin.getline读取一行

函数作用:从标准输入设备键盘读取一串字符串,并以指定的结束符结束。
函数原型有两个:

1
2
3
istream& getline(char* s, streamsize count); //默认以换行符结束
istream& getline(char* s, streamsize count, char delim);

使用示例:

1
2
3
4
5
6
7
8
9
10
11
#include <iostream>
using namespace std;
int main()
{
char array[20]={NULL};
cin.getline(array,20); //或者指定结束符,使用下面一行
//cin.getline(array,20,'\n');
cout<<array<<endl;
system("pause");
return 0;
}

注意,cin.getline与cin.get的区别是,cin.getline不会将结束符或者换行符残留在输入缓冲区中。


3. cin的条件状态

使用cin读取键盘输入时,难免发生错误,一旦出错,cin将设置条件状态(condition state)。条件状态标识符号为:
goodbit:无错误
eofbit:已到达文件尾
failbit:非致命的输入/输出错误,可挽回
badbit:致命的输入/输出错误,无法挽回
若在输入输出类里.需要加iOS::标识符号。与这些条件状态对应的就是设置、读取和判断条件状态的流对象的成员函数。他们主要有:
s.eof():若流s的eofbit置位,则返回true;
s.fail():若流s的failbit置位,则返回true;
s.bad():若流s的badbit置位,则返回true;
s.good():若流s的goodbit置位,则返回true;
s.clear(flags):清空状态标志位,并将给定的标志位flags置为1,返回void。
s.setstate(flags):根据给定的flags条件状态标志位,将流s中对应的条件状态位置为1,返回void。
s.rdstate():返回流s的当前条件状态,返回值类型为strm::iostate。strm::iostate 机器相关的整形名,由各个iostream类定义,用于定义条件状态。

了解以上关于输入流的条件状态与相关操作函数,下面看一个因输入缓冲区未读取完造成的条件状态位failbit被置位,再通过clear()复位的例子。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>
using namespace std;

int main()
{
char ch, str[20];
cin.getline(str, 5);
cout<<"flag1:"<<cin.good()<<endl; // 查看goodbit状态,即是否有异常
cin.clear(); // 清除错误标志
cout<<"flag1:"<<cin.good()<<endl; // 清除标志后再查看异常状态
cin>>ch;
cout<<"str:"<<str<<endl;
cout<<"ch :"<<ch<<endl;

system("pause");
return 0;
}

输入:12345[回车],输出结果为:

可以看出,因输入缓冲区未读取完造成输入异常,通过clear()可以清除输入流对象cin的异常状态。,不影响后面的cin>>ch从输入缓冲区读取数据。因为cin.getline读取之后,输入缓冲区中残留的字符串是:5[换行],所以cin>>ch将5读取并存入ch,打印输入并输出5。

如果将clear()注释,cin>>ch;将读取失败,ch为空。
cin.clear()等同于cin.clear(ios::goodbit);因为cin.clear()的默认参数是ios::goodbit,所以不需显示传递,故而你最常看到的就是:
cin.clear()。


4. cin清空输入缓冲区

从上文中可以看出,上一次的输入操作很有可能是输入缓冲区中残留数据,影响下一次的输入。那么如何解决这个问题呢?自然而然,我们想到了在进行输入时,对输入缓冲区进行清空和状态条件的复位。条件状态的复位使用clear(),清空输入缓冲区应该使用:
函数原型:istream &ignore( streamsize num=1, int delim=EOF );
函数作用:跳过输入流中n个字符,或在遇到指定的终止字符时提前结束(此时跳过包括终止字符在内的若干字符)。
使用示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>
using namespace std;

int main()
{
char str1[20]={NULL},str2[20]={NULL};
cin.getline(str1,5);
cin.clear(); // 清除错误标志
cin.ignore(numeric_limits<std::streamsize>::max(),'\n'); //清除缓冲区的当前行
cin.getline(str2,20);
cout<<"str1:"<<str1<<endl;
cout<<"str2:"<<str2<<endl;
system("pause");
return 0;
}

程序输入:12345[回车]success[回车],程序输出:

注意:
(1)程序中使用cin.ignore清空了输入缓冲区的当前行,使上次的输入残留下的数据没有影响到下一次的输入,这就是ignore()函数的主要作用。其中,numeric_limits::max()不过是头文件定义的流使用的最大值,你也可以用一个足够大的整数代替它。
如果想清空输入缓冲区,去掉换行符,使用:
cin.ignore(numeric_limits< std::streamsize>::max()); 清除cin里所有内容。

(2)cin.ignore();当输入缓冲区没有数据时,也会阻塞等待数据的到来。

(3)有个疑问,网上很多资料说调用cin.sync()即可清空输入缓冲区,本人测试了一下,VC++可以,但是在linux下使用GNU C++却不行,无奈之下,linux下就选择了cin.ignore()。


5.其它从标准输入读取一行字符串的方法

5.1 getline读取一行

C++中定义了一个在std名字空间的全局函数getline,因为这个getline函数的参数使用了string字符串,所以声明在了< string>头文件中了。

getline利用cin可以从标准输入设备键盘读取一行,当遇到如下三种情况会结束读操作:1)到文件结束,2)遇到函数的定界符,3)输入达到最大限度。

函数原型有两个重载形式:

1
2
istream& getline ( istream& is, string& str);//默认以换行符结束
istream& getline ( istream& is, string& str, char delim);

使用示例:

1
2
3
4
5
6
7
8
9
10
11
12
#include <string> 
#include <iostream>
using namespace std;

int main()
{
string str;
getline(cin,str);
cout<<str<<endl;
system("pause");
return 0;
}

输入:hello world[回车],输出:

注意,getline遇到结束符时,会将结束符一并读入指定的string中,再将结束符替换为空字符。因此,进行从键盘读取一行字符时,建议使用getline,较为安全。但是,最好还是要进行标准输入的安全检查,提高程序容错能力。

cin.getline()类似,但是cin.getline()属于istream流,而getline()属于string流,是不一样的两个函数。

5.2 gets读取一行

gets是C中的库函数,在< stdio.h>申明,从标准输入设备读字符串,可以无限读取,不会判断上限,以回车结束或者EOF时停止读取,所以程序员应该确保buffer的空间足够大,以便在执行读操作时不发生溢出。
函数原型:char *gets( char *buffer );
使用示例:

1
2
3
4
5
6
7
8
9
10
#include <iostream>
using namespace std;
int main()
{
char array[20]={NULL};
gets(array);
cout<<array<<endl;
system("pause");
return 0;
}

输入:I am lvlv[回车],输出:

由于该函数是C的库函数,所以不建议使用,既然是C++程序,就尽量使用C++的库函数吧。

20230802-VisualStudio2022构建调试C++项目

入门篇

开发-编写和编辑代码

项目和解决方案

项目和解决方案基本设置

visual studio 2022 调试快速入门

批量编辑修改代码,查看类试图,查看定义代码和引用情况

查找和替换,
插入代码片段

波浪线错误自动修正

20230720-METAFONT教程

可以输出如下格式

svg png eps ps 包括所有alyph 全放在一张上的以及单个glyph 一张

raw data 存储为json 格式,还有metric 信息以及 outline bitmap data
OTF TTF PFB 这个目前会通过libfontforge 或otfcc 实现

以mf 资源存储:以otf 存储 = 1:10


字体对于我们到底是什么
字体是一种可以用以表现特定目的资源
而对于另外一些人而言,字体其实可以是一种程序产物,是一种数据,但也可以本身是程序产物,是一种数据,但也可以本身就是程序

对于metafont 而言,字体其实就是第三种形态的东西

这个meta 的意思就是第三种,你们大可以理解为是一种高阶的字体描述语言,那么低阶 是什么,低阶其实可以理解为字体的点阵形式或者矢量形式本身

metafont 的这个meta ,其实归根到底是通过一系列算法生成bezier 曲线,然后通过转换变为点阵的,正因为只能输出点阵,所以很多人以为metafont 是一种过时的东西,但是呢,其实历史上也是有过多例生成曲线的实验性质的项目 mf2ps mflua 但是大多数没有坚持下来

第二个准备知识就是bezier 曲线,这个是比较基础的计算机图形学的概念了,在一般教科书中都能够找到,但是有一点必须说明,metafont 之中使用的是3次bezier 曲线来做的,而且,METAFONT中的所有线都是用bezier描述,也就是说,就连直线也是用四个点描述的。这个在某方面会觉得多余,但是等到我的扩展版METAFONT出来之后,是可以在运行的时候开相应的flag做优化的。还有一个比较有意思的东西,就是现在的TrueType以及OpenType,其实都是可以转换为METAFONT进行输出的,当然输出来的曲线形式和原始的并没有差别,但是这个东西很少有人去做了。

第三个准备知识,是metafont 中的一些概念,比如说pen 和绘制曲线的东西,上一段所说的,是最简单的,按照你输入的完备的曲线构成的path 输出,metafont 的威力就在于可以使用pen 来绕着一个path 进行绘制,实际上画出包络线,这种底层细节实际上是被隐藏在plain 格式之中了,大部分人基本上没有写过metafont 的宏

第四个准备知识,是METAFONT语言本身。拿现在比较流行的观念来看,其实TeX和METAFONT本身就是领域特定语言,在语法上其实要求并没有那么高的,宏语言是足够的。但是,对比下来,METAFONT的一般语法还是要比TeX好学的,语法是类似于当时的AOGOL的,还是比较好写出结构化的字体程序的。

精心设计好的metafont 字体系统,能够大大较低字体制作的人工成本

  • Copyrights © 2015-2024 TeX_baitu
  • 访问人数: | 浏览次数:

请我喝杯咖啡吧~