文件缓冲区
前置博客 基础IO 为什么有缓冲因为磁盘的读写与内存的读写操作速度相比,磁盘的读写是相差数量级的慢,所以为了提高内存多次,频繁读写磁盘文件的效率,缓冲区被投入使用。尤其是内存内容写入磁盘时,常常先写入内存级缓冲区,再在特定规则下一次性将缓冲区的内容写入磁盘 **本文以C语言提供的用户级缓冲区为例介绍缓冲区 缓冲区的刷新规则首先当一个进程正常退出时,会先刷新缓冲区再关闭文件,此时必定有一次刷新 而当进程运行时缓冲区的刷新策略主要有以下三种 无缓冲 内容直接写入文件 行缓冲 输入一般内容不刷新,遇到\n时刷新一次缓冲区 全缓冲 缓冲区有容量限制,满了之后就刷新 认识一下C语言的缓冲区这里的系统环境是Linux 刷新规则运行如下代码 12345678910111213#include <stdio.h>#include <unistd.h>int main(){ FILE* pfile = fopen("file.txt","w");//打开空文件 fprintf(stdout,"stdout ...
Linux文件系统
文件系统的组织方式 这里介绍一下Block Group里的分区内容 超级块(Super Block): 存放文件系统本身的结构信息。记录的信息主要有:bolck(数据块) 和 inode(属性块)的总量,未使用的block和inode的数量,一个block和inode的大小,最近一次挂载的时间,最近一次写入数据的时间,最近一次检验磁盘的时间等其他文件系统的相关信息。Super Block的信息被破坏,可以说整个文件系统结构就被破坏了 GDT(Group Descriptor Table): 块组描述符,描述块组属性信息。这里不作详细介绍 块位图(Block Bitmap):位图中的比特位记录着Data Block中哪个数据块已经被占用,哪个数据块没有被占用 inode位图(inode Bitmap):每个比特位表示一个inode是否空闲可用。 inode表(inode Table):每一个inode存放了各自文件的属性,如文件大小,所有者,最近修改时间等 数据区:存放文件内容 Linux系统中文件的增删查改Linux中,每一个文件都有自己的inode,而每一个inode有自己的in ...
C语言文件操作
用户级文件操作C语言的文件操作也是用户级的文件操作,通过FILE对象来管理每一个被打开的文件,以及提供了用户级文件缓冲区,因此还涉及到冲刷缓冲区等问题 FILE 类FILE类描述了一个文件流。里面存储了文件控制所需的信息: 指向自身缓冲区的的指针 位置指示器 状态指示器 所以C语言中对文件的管理就是对FILE对象的管理 基础操作 - 针对一般文件基础示例1234567891011#include <stdio.h>int main(){ FILE* pfile = fopen("file.txt", "w");//"w"模式打开文件file.txt int code = 1; const char* msg = "this is a msg"; fprintf(pfile, "get msg : %s code:%d", msg, code);//格式化输出字符串 fclose(pfile);//冲刷缓冲区并关闭文件 return 0;} 以上代码创建 ...
=C++= sizeof关键字详解
简介sizeof作为C/C++关键字,基本用法是求字节大小,但仅仅这一项用法在细节上就有很多说法了 求内置类型变量的大小有两种写法,以int a = 0的变量a为例 sizeof a sizeof(a) 都可以求变量a的大小,但注意,该变量的大小仅与变量类型有关,而与值无关 求内置类型的大小求类型大小时必须加上括号 例如sizeof(int) 求数组的大小 当数组声明在全局或sizeof处于数组声明语句的局部作用范围时,能够用sizeof(<数组名>)求数组大小 当数组名经过函数传参或加减常量运算后,退化为指针变量,类型大小在32位机器中为4,64位机器中为8 12345678910111213141516171819#include <iostream>using namespace std;int g_arr[10] = { 0 };void func(int st_arr[]){ cout << sizeof(st_arr) << endl;//此处退化为指针变量,输出4或8} ...
基础IO
共识原理 文件 = 内容 + 属性 被打开的文件需要加载到内存中 内存中的文件需要被操作系统管理 用户级文件接口详见C++文件操作 详见C语言文件操作 Linux系统调用接口fd 文件描述符 与访问文件的本质 fd(file descriptor),即文件描述符,下文的系统调用接口经常以fd命名变量,fd是整形变量,作为数组下标,用于管理打开的文件 可以看到,一个进程通过struct files _struct里的指针数组,管理多个同时打开的文件 且每个进程启动时,会默认打开三个文件,且默认fd固定 stdout read所需头文件#include <unistd.h>声明ssize_t read(int fd, void *buf, size_t count); 参数 fd即为目标文件的文件描述符 buf为要从文件读取字节到的内存地址 count为最大读取字节数 返回值 若成功,返回读取文件的字节数,类型为ssize_t,是层层封装的long int 若失败,返回-1,并设置errno的值 write所需头文件#include <unistd ...
初识动静态库
静态库(.a)程序在编译链接的时候把库的代码链接到可执行文件中。编译出的程序运行时不再需要静态库 生成和使用静态库这里使用gcc编译获得.o链接文件,再用gnu归档工具中的ar指令配合-rc选项(replace and create)封装库文件,最后借助makefile简化文件目录的封装操作 使用第三方库时,还可以使用ar -tv查看库中的目录列表 t:列出静态库中的文件 v:verbose 详细信息 使用静态库: gcc编译时使用第三方静态库必须包含以下选项: -I指定头文件目录 -L指定库路径 -l指定库名(不加空格),库名要把文件名前面去掉lib,后面去掉.a才是真正的库名 否则编译器不知道头文件在哪,或者不知道链接哪个库 库搜索路径库的搜索会按照一定的顺序 从左到右搜索-L指定的目录。 由环境变量指定的目录 (LIBRARY_PATH) 由系统指定的目录 /usr/lib /usr/local/lib 样例测试程序(共5个文件) 12345678910111213141516171819202122232425262728293031323334353637// ...
fork子进程,进程退出与等待
认识fork()头文件<unistd.h>提供的fork()函数用于从已有的原进程创建一个新的子进程,而原进程在关系式称为父进程 fork()的返回值12#include <unistd.h>pid_t id = fork(); 父子进程中fork()函数的返回值(此处用变量id储存)是不同的: 父进程里id的值为子进程的PID,其值>0;子进程里id值固定为0 id > 0 父进程 id == 0 子进程 id < 0 fork()失败 分流 利用父子进程中fork()返回值的不同,可以用if...else...进行分流,让父子进程执行不同的代码 fork()的过程进程调用fork,当控制转移到内核中的fork代码后,内核做 分配新的内存块和内核数据结构给子进程 将父进程部分数据结构内容拷贝至子进程 添加子进程到系统进程列表当中 fork返回,开始调度器调度 当一个进程调用fork之后,就有一对二进制代码相同的父子进程。而且它们都运行到相同的地方。但每个进程都可以独立地继续运行代码,并按代码分流至不同的代码段 但这两个进程谁先执行 ...
环境变量
基本概念 环境变量(environment variables)一般是指在操作系统中用来指定操作系统运行环境的一些参数 环境变量通常具有某些特殊用途,还有在系统当中通常具有全局特性 构成:环境变量是一系列字符串的统称,所以一个环境变量由变量名和值构成 这么说还是太抽象了,我们接下来会举几个具体样例,体会环境变量在获取系统全局的变量,系统指令路径等方面的作用 常见环境变量 变量名 功能 PATH 指定命令的搜索路径 HOME 指定用户的主工作目录(即用户登陆到Linux系统中时,默认的目录) USER 当前用户名 SHELL 当前Shell,它的值通常是/bin/bash PWD 当前工作目录 操作系统变量查看环境变量echo $NAME NAME为变量名 以PATH为例,查看PATH的值的指令为 1echo $PATH https://picbed0521.oss-cn-shanghai.aliyuncs.com/blogpic/PixPin_2024-07-08_12-46-35.png 可以看到PATH的内容为多个文件路径,互相以:分隔 而若要查看 ...
初识进程
操作系统平台:Linux服务器系统: CentOS 7 概念抽象程序程序 = 代码 + 数据 程序是储存在硬盘上的可执行文件 进程将程序加载到内存后,就在内存中程序的就是进程。也就是说一个正在运行的程序就能叫做进程 结构关系如下 如图,操作系统为了管理内存中的进程,使用了PCB结构体来描述进程,通过管理PCB来管理进程,依然是先描述再组织 PCB:进程控制块的数据结构(process control block) 所以实际上:进程=PCB+代码和数据 对于代码和数据没什么好说的,接下来主要讨论PCB task_structLinux平台下的PCB叫做task_struct task_struct内容分类: 标示符: 描述本进程的唯一标示符,用来区别其他进程。 状态: 任务状态,退出代码,退出信号等。 优先级: 相对于其他进程的优先级。 程序计数器: 程序中即将被执行的下一条指令的地址。 内存指针: 包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针 上下文数据: 进程执行时处理器的寄存器中的数据。 I/O状态信息: 包括显示的I/ ...
C/C++ static关键字的使用
因为static的用法又多又杂,值得单出一篇博客用以汇总 C/C++ 通用用法局部变量->全局属性当对原本声明在函数栈帧里的变量使用static修饰时,该变量的存储空间会改变到静态区,不会随着函数栈帧的销毁而销毁。 初始化:初次调用声明语句时会执行声明操作,而之后再执行到该语句处时会自动跳过。 作用范围:与不加static时的作用范围相同,还是局部可用 销毁:和全局变量一样在main函数的栈帧销毁时一并销毁 全局变量->限制访问原本同级文件夹下的源文件可以用extern关键字互相获取全局变量,但如果用static修饰本地全局变量,那么这个全局变量只能在本文件调用,而其它文件看不到它 全局函数->限制访问原本同级文件夹下的源文件可以用extern关键字声明函数,然后去其它源文件的全局函数中寻找实现方式,但如果用static修饰本地全局函数,那么这个全局函数的实现只能在本文件调用,而其它文件看不到它 C++类和对象成员变量->静态成员 (全局变量)原本声明的成员变量在实例化后,属于由类实例化出来的对象,生命周期与所属对象相同,但在加了static后 ...
归并排序
时间复杂度: O(nlogn)空间复杂度: O(n)稳定性: 稳定实现语言: C/C++ 原理思想这里采用的是分治的思想,但与快速排序相反的是,归并排序采用的是先分治再合并。 已知在有额外空间的情况下,合并两个有序数组得到一个新的较长有序数组是很高效的。 所以能不能把一个任意数组分成由左右两个有序数组组成然后合并成有序数组呢? 显然不能,大部分情况并不能分成两个有序数组,但如果在此之前用同样的方法(这里采用递归)事先排序左右两部分呢?大部分情况依然不能,因此这个递归会一直递推下去,最终待排序区间不断缩小,到只剩一个或零个元素,此时就可以将其看为有序数组了,也就是说递归在这里停止,可以一路合并有序数组一路回归上去了 分治这里使用左右指针控制待排序区间(迭代器也行),并采用递归的方式形象地完成分治操作 123456789101112131415161718void _MergeSort(vector<int>& arr,int left,int right,vector<int>&tmp){ //分治 if(le ...
=Linux=一步步自己写一个shell程序
系统:阿里云服务器Linux CentOs 7 编辑器: vim 编译器: gcc (支持C99) 文件本次写的程序较为简单,所以只使用一个源文件 所以在shell中touch一个makefile和一个myshell.c shell 12touch makefiletouch myshell.c 然后编辑makefile文件 makefile 1234561 myshell:myshell.c gcc -o $@ $^ -std=c99.PHONY:cleanclean: rm -f myshell 头文件本程序因函数较杂,会include较多头文件 myshell.c 12345#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <assert.h> 宏定义为了统一修改部分参数,以及使参数更易读,这里使用部分宏定义 myshell. ...
堆排序
背景知识 知道什么是大堆/小堆 掌握如何将数组与完全二叉树的映射关系 掌握向上调整法和向下调整法 大堆/小堆大堆的特性:每一个节点的值都比左右孩子都大,根的值是整个大堆中最大的小堆的特性:每一个节点的值都比左右孩子都小,根的值是整个大堆中最小的 后面以大堆为例 数组映射成完全二叉树任何一个数组可以看成一个完全二叉树,下标0为二叉树的根 而非常方便的是,已知一个节点的下标,可以利用数学关系求出根或孩子的下标 下标关系如下(变量均为下标) parent = (child-1)/2 left_child = parent*2+1 right_child = parent*2+2 建堆方法向上调整法在已有一个大堆的前提下,把一个新的数据插入到堆的最后一个节点(此时破坏大堆的结构),再一路向上调整,可以重新建堆 123456789101112131415161718template<class T>void adjust_up(vector<T>& arr, int child){ int parent = (child - ...
C++文件操作
注:追求代码简洁,有一致的C++风格,可参阅本篇博客,若追求更高的读写效率,建议参阅C语言篇 但文章还没写 本篇文章主要研究头文件fstream中的函数和类 目前C++文件操作主要有两种流派,一种是声明fstream对象,另一种是分开声明ifstream和ofstream 注意,本文代码为了简洁,都是在展开std命名空间的前提下书写 fstream的使用先写一段示例代码 12345678910111213141516171819202122#include <iostream>#include <fstream>using namespace std;int main(){ fstream f("file.txt", ios::out);//调用构造函数以out模式打开文件file.txt 注:out模式下file.txt 会自动创建 string str = "This is a sentence";//在内存中准备一段字符串 f << str;//将字符串从内存写入文件 f.close();//关 ...
通过设计list类深入理解iterator迭代器
前置博客:从构建一个Date类入门C++类与对象设计模式介绍:TODO Iterator迭代器实际上也是一种设计模式,它提供了一种方法顺序访问一个聚合对象中各个元素 下面先迅速地搓一个list类 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859template <class T>//先用模板创建一个节点类struct ListNode{ T _val; ListNode<T>* _next; ListNode<T>* _prev; //提供全缺省的默认构造函数 ListNode(const T& val = T()) :_val(val), _next(nullptr), _prev(nullptr) {}};//用ListNode构造list类template <class T>class list{ typ ...
vim基础指令集
Vim是一款文本编辑器,下面介绍在vim界面中的常用指令 三种模式:命令模式(Command Mode) 插入模式(Insert Mode 命令行模式(Command-Line Mode)(这里称命令行模式为底行模式) 三者关系如下图 命令模式vim界面中多摁几次ESC就能退出其它模式回到命令模式,在这个模式下可以使用一系列vim快捷键 底行模式tips:不管目前是什么模式,先狂按ESC,回到命令模式,然后输入:进入底行模式,准备开始输命令 命令组成 保存:w->强制保存!w 退出:q->强制退出:!q 保存并退出:wq-.强制保存并退出:!wq 对比:vs +(源文件路径) 插入模式在命令模式下按键盘i进入插入模式,执行正常的文本编辑功能
从构建一个Date类入门C++类与对象
类的定义12345678910111213141516171819class Date{public: void Init(int year = 1,int month = 1,int day = 1) { _year = year; _month = month; _day = day; } void Print() { cout << _year << ":" << _month << ":" << _day << endl; }private: int _year; int _month; int _day;}; 抽象数据类型(类)通过如上代码,我们就在源代码中通过class声明了一个抽象数据类型Date,简称类,那么封装一个类有什么好处呢?好处是类把相关的操作分为两类: 类的设计者:负责考虑类的具体 ...
指针详解
这篇质量不太行:( 内存和地址在了解指针之前,先讲讲内存是如何管理的 首先因为内存很大(一般有几个G),所以为了高效管理,有了内存单元的概念。而这个单元的大小,正好是一个字节。 因为一个比特位就是一个二进制位,太小了,超过一个字节,在处理char这样一个字节长的变量很麻烦。 定下长度后,就可以给内存单元编号,而每个内存单元获得的独一无二的编号,便是它的地址,以声明了一个变量a为例,示意图如下 变量的地址上图中a占4个字节,每个字节都有自己的地址,但要找到a其实只需要找到第一个地址就行了,实际上在C语言中也是如此,a的地址就是首字节地址,即图中的0x000000AF88DFF6A4 关于几个名词在C语言中称地址为指针,储存地址的变量叫指针变量,平时也简称指针,此时强调的是指针变量里储存的地址,而不是这个变量。 指针变量的组成指针变量也要拆成两部分来看 一个是变量的值,在同一个程序中,所有指针变量的值的长度都是一样的,都指向了某一个内存中的字节, 至于具体多长,取决于环境:32位程序是4个字节,64位程序是8个字节 另一个是变量的类型,类型决定编译器从值所指向的字节,向后总共读几个字节 ...
=C入门=深入研究 字符串与字符数组
什么是字符串初见字符串我们最先遇到的字符串,一般是hello_world程序中用到的"hello world",也就是两个双引号括起来的一串字符,输出时的占位符是%s,可以直接拿去传值,代码如下 1printf("%s","hello world"); 声明字符串变量有时我们想要先把字符串存起来,再进行操作,那么就使用字符数组,并在初始化的时候把字符串传给它,这样在创建数组时会编译器会自动分配内存给它,代码如下 1char str[] = "abcdef"; 此时我们也可以开启VS的调试,并打开内存和监视窗口观察字符串是如何在内存中储存的,如下图 通过观察可以发现,C语⾔字符串的字符串有个规定(特点),就是以字符\0结尾,无论是初始化数组时,还是在分配内存时,都有\0的位置。 strlen()函数依据以\0为字符串结尾的规则,strlen函数就可以计算字符串的长度,它会从字符串的第一个字符向后扫描,直到遇到\0结束,且\0不进入计数,最后返回字符串的长度,代码如下 1234#include <st ...
=C语言实践= 手把手教你做高端cmd简单扫雷
直接开始吧!多文件项目扫雷项目内容较多,需要调用的函数也较多,采用多文件的方式,可以使代码条理清晰,并且易于管理和维护。文件如下 game.h用于宏定义,函数声明,引入头文件等 game.c用于函数的具体实现 front.c用于实现程序的主干部分 other.c用于实现其他杂项函数,这里我用于实现menu()函数,主要内容太花了 注 .c结尾的源文件均需加一句#include "game.h" 头文件本次用到的头文件有stdio.h stdlib.h time.h windows.h和自己建的game.h 均在文件game.h中#include define宏定义为了便于阅读和维护代码,在game.h中的宏定义如下 1234567891011121314151617181920//显示行列#define ROW 9#define COL 9//实际数组大小#define ROWS ROW+2#define COLS COL + 2//地雷信息#define Bomb '*'#define Blank ' '//难度#defi ...
玩转N组输入和多组输入
引入当我们在写IO型OJ时,多组输入便是我们绕过不开的话题了,但不用担心,可能初见多组输入会觉得难以理解,但用多了之后就会发现,多组输入 花样并不多,混熟了就很简单了 先看看一组输入输出如何完成的 如图:一组输入时,用scanf获取一组输入,并在主体部分完成数据的处理,产生结果,最后用printf输出产生的一组结果。 以下用实现加法的程序做演示 12345678910#include <stdio.h>int main(){ int a,b; scanf("%d %d",&a,&b);//获取一组输入 int sum = a + b;//产生结果 printf("%d\n",sum);//输出结果 return 0;} 然后升级到N组输入有的OJ题在一个测试文件中会先输入一个n,告诉你接下来有n组输入,你就要产生n组输出,也就是说要将一组输入输出重复性地完成n次。难道我们要把代码重复n次吗?显然不现实。 所以是时候使用循环了,具体用法如下 如图,先用一个scanf获 ...
=C语言= 整型变量与过大的整数
整型家族在使用C语言写程序时,会储存各种长度的整型,而在整型家族中,长度的比较如下 char < short <= int <= long <long long 整型是如何储存在内存中的以char为例 char的长度为1个字节,8个比特位,其中最高位是符号位,0表示正数,1表示负数,剩下的位数用于储存变量的绝对值 而当使用无符号整型(带前缀unsigned)时,只需把符号位也用于存值即可 能够储存的最大正整数int长度为4字节,能够储存的最大值为2的31次方-1,即2,147,483,647 unsigned int能够储存的最大值为4294967295 unsigned long long长度为8字节,能够储存的最大值为2的64次方-1,即18,446,744,073,709,551,615 限制虽然unsigned long long已经很大了,但当遇到指数,阶乘之类的运算时仍然可能存不下!(光21!就比unsigned long long长了) 思路过大的整数,可能出现在程序的过程中,也可能出现在输出中,对于过程,可以尝试改变实现思路,让过程中不出现 ...
如何在VS里使用scanf
VS里怎么连scanf都用不了?不少刚接触Visual Studio的可能发现使用scanf会报错(如下) vs告诉你说scanf不安全,然后你会发现vs给你提供了scanf_s去代替scanf,但是,只有vs能编译scanf_s,可移植性太差了,所以我们要用回scanf,所以要怎么不让它报错呢?可以在源文件开头添加一行宏定义(如下) #define _CRT_SECURE_NO_WARNINGS 1 这样就能关闭报错了,但请先别急着走,每次都要复制粘贴一句宏定义太麻烦了,想一劳永逸的请往下看。 修改newc++file.cpp来自动添加宏定义先来看怎么做:首先搜索找到电脑中叫做newc++file.cpp的文件。(这里推荐使用everything) 后半段路径应与图片一致,注意不是快捷方式 注意:由于权限原因,无法直接修改此文件 所以先将这个文件复制粘贴到别处,例如桌面,下文用副本代称。 用记事本类软件(记事本就行)打开副本,在第一行输入上文提到的宏定义代码#define _CRT_SECURE_NO_WARNINGS 1,然后ctrl+s保存。 关闭编辑窗口,将该副本移 ...
=回顾-前端=从简陋的html到单网页再到全栈开发
👉点我去作业一 👉点我去作业二 👉点我去作业三(抱歉,还没部署到服务器里,这个只能在我自己的电脑里用) 👉点我去作业四 其实这依然是个博客 粗糙的作业一当时只学过html,css,js的快速入门,对盒子<div>的玩法还不太熟,还只会用浮动盒子float和绝对定位,结局就是写两句html就得清除浮动233,甚至<lenged>也不认识,结果手动用css给实现了。总之就挺简陋的 精致(并不)作业二用vscode写作业二的时候,写一半发现鼠标悬停在tag时,它会给出去往MDN对应参考页的连接,然后就开始一边写一边阅读MDN,结果一发不可收拾,开始读的时间比写的时间还长。最后成功学到神器bushiflex弹性盒子模型。。 但还没完,除了参阅文档,我还多次在B站首页和MC百度百科首页打开F12,查看,学习他们是如何布局盒子的,别说,学成品也挺有用的,对盒子的排版,嵌套的想法成熟多了 结合二者,照着图片做一个网页便没什么问题了。那个作业二我甚至直接弃掉了初版(已经把顶部做好了)version2基本完全采用flex盒子。比较遗憾的是,虽然每个菜单按钮都加了超链接, ...
avatar
副驾supdriver
动物界 脊索动物门 哺乳纲 灵长目 人科 人属 智人种
我github还蛮大的
公告
主域名:
supdriver.top
网站资讯
文章数目 :
75
已运行时间 :
本站总字数 :
188k
本站总访问量 :
最后更新时间 :