“差生文具多”

“差生文具多”—用积极消费来掩盖自己的懒惰 假努力—用表象的勤奋来掩盖自己的懒惰 不要以战术上的勤奋掩饰战略上的懒惰

June 10, 2026

CS50群交流会感悟

CS50群交流会感悟 时间与注意力 比起按照时间来算,用有效注意力来计算时间更加准确.想要提高效率,一味的追求时间上的长度,是不太明智的选择 日常生活中要有效的分配自己的精力,尽量不在没有的地方浪费宝贵的精力. 当遇到瓶颈时,考虑三个方面 是否有足够的有效输入 是否有足够的有效输出 处理问题的核心能力不足 平时要注意获取信息差 学校: 比赛 项目 活动 职场 : 行业现状 技术趋势 优质资源 关于ACM竞赛 要综合自己的需求, 目标, 能力, 不要被周围同学学长给影响, 人云亦云 竞赛非常耗时间, 与cs课程往往不能兼顾 大一阶段要特别注意培养自己的代码实现能力 趁着大一时间多, 多学一些 现状 再简单的课能坚持下的人也是凤毛麟角 95%的人是’不学’的, 剩下又有80%是三天打鱼两天晒网的 行业 互联网的发展接近天花板, 公司开始"降本增效" ,新技术,新项目逐渐变少, 各公司开始稳定,裁员 ai行业 ,不需要大量算法人才, 而是技术的落地, 实现算力的提升, 需要的是高技术coding ai方向: 硬件(芯片, EDA软件, 车机系统) 与 软件(os,库,框架) 留意国外公司在做的事情 (MR), 国外ai发展领先国内一到两年 web开发 != CS, web开发用不到太多CS的知识

June 10, 2026

file descriptor

理解Linux的file descriptor(文件描述符) ​ 我们知道在Linux系统中一切皆可以看成是文件,文件又可分为:普通文件、目录文件、链接文件和设备文件。在操作这些所谓的文件的时候,我们每操作一次就找一次名字,这会耗费大量的时间和效率。所以Linux中规定每一个文件对应一个索引,这样要操作文件的时候,我们直接找到索引就可以对其进行操作了。 ​ 文件描述符(file descriptor)就是内核为了高效管理这些已经被打开的文件所创建的索引,其是一个非负整数(通常是小整数),用于指代被打开的文件,所有执行I/O操作的系统调用都通过文件描述符来实现。同时还规定系统刚刚启动的时候,0是标准输入,1是标准输出,2是标准错误。这意味着如果此时去打开一个新的文件,它的文件描述符会是3,再打开一个文件文件描述符就是4…… Linux内核对所有打开的文件有一个文件描述符表格,里面存储了每个文件描述符作为索引与一个打开文件相对应的关系,简单理解就是下图这样一个数组,文件描述符(索引)就是文件描述符表这个数组的下标,数组的内容就是指向一个个打开的文件的指针。 文件描述符指向了由系统内核维护的一个file table中的某个条目(entry)。这个解释可能过于抽象,不过在正式详细介绍fd之前,有必要先了解用户程序和系统内核之间的工作过程。 注: 本文描述的所有场景仅限于类unix系统环境,在windows中这玩意叫file handle(臭名昭著的翻译: 句柄)。 User space & Kernel space 现代操作系统会把内存划分为2个区域,分别为Use space(用户空间) 和 Kernel space(内核空间)。用户的程序在User space执行,系统内核在Kernel space中执行。 用户的程序没有权限直接访问硬件资源,但系统内核可以。比如读写本地文件需要访问磁盘,创建socket需要网卡等。因此用户程序想要读写文件,必须要向内核发起读写请求,这个过程叫system call。 内核收到用户程序system call时,负责访问硬件,并把结果返回给程序。 FileInputStream fis = new FileInputStream("/tmp/test.txt"); byte[] buf = new byte[256]; fis.read(buf); 上面代码的流程如下图所示 File Descriptor 上面简单介绍了User space和Kernel space,这对于理解fd有很大的帮助。fd会存在,就是因为用户程序无法直接访问硬件,因此当程序向内核发起system call打开一个文件时,在用户进程中必须有一个东西标识着打开的文件,这个东西就是fd。 file tables ​ 一个 Linux 进程启动后,会在内核空间中创建一个 PCB 控制块,PCB 内部有一个文件描述符表(File descriptor table),记录着当前进程所有可用的文件描述符,也即当前进程所有打开的文件。进程级的描述符表的每一条记录了单个进程所使用的文件描述符的相关信息,进程之间相互独立,一个进程使用了文件描述符3,另一个进程也可以用3。除了进程级的文件描述符表,系统还需要维护另外两张表:打开文件表、i-node 表。这两张表存储了每个打开文件的打开文件句柄(open file handle)。一个打开文件句柄存储了与一个打开文件相关的全部信息。 和fd相关的一共有3张表,分别是file descriptor、file table、inode table,如下图所示。 file descriptors file descriptors table由用户进程所有,每个进程都有一个这样的表,这里记录了进程打开的文件所代表的fd,fd的值映射到file table中的条目(entry)。 ...

June 10, 2026

linux

文件的10个关键系统调用 open/close read/write/lseek(随机查找) fstst(返回文件数据)/ftruncate(清空) unlink(删除文件)/mkdir / dup 文件系统的抽象 struct File { mode (permissions, type); size; user; group;//type数据结构的类型 timestamps(atime, mtime,ctime); content (bytes); }; map <string, File> // from file path to file 一种数据结构, 从路径到文件的映射

June 10, 2026

linux select函数

linux select函数 在Linux中,我们可以使用select函数实现I/O端口的复用,传递给 select函数的参数会告诉内核: 我们所关心的文件描述符 对每个描述符,我们所关心的状态。(我们是要想从一个文件描述符中读或者写,还是关注一个描述符中是否出现异常) 我们要等待多长时间。(我们可以等待无限长的时间,等待固定的一段时间,或者根本就不等待) 从 select函数返回后,内核告诉我们一下信息: 对我们的要求已经做好准备的描述符的个数 对于三种条件哪些描述符已经做好准备.(读,写,异常) 有了这些返回信息,我们可以调用合适的I/O函数(通常是 read 或 write),并且这些函数不会再阻塞. 函数声明 #include <sys/select.h> int select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,struct timeval *timeout); 返回值:做好准备的文件描述符的个数,超时为0,错误为 -1. 参数 struct timeval 首先我们先看一下最后一个参数。它指明我们要等待的时间: struct timeval{ long tv_sec; /*秒 */ long tv_usec; /*微秒 */ } 有三种情况: timeout == NULL 等待无限长的时间。等待可以被一个信号中断。当有一个描述符做好准备或者是捕获到一个信号时函数会返回。如果捕获到一个信号, select函数将返回 -1,并将变量 erro设为 EINTR。 timeout->tv_sec == 0 &&timeout->tv_usec == 0不等待,直接返回。加入描述符集的描述符都会被测试,并且返回满足要求的描述符的个数。这种方法通过轮询,无阻塞地获得了多个文件描述符状态。 timeout->tv_sec !=0 ||timeout->tv_usec!= 0 等待指定的时间。当有描述符符合条件或者超过超时时间的话,函数返回。在超时时间即将用完但又没有描述符合条件的话,返回 0。对于第一种情况,等待也会被信号所中断。 readset, writset, exceptse 中间的三个参数 readset, writset, exceptset,指向描述符集。这些参数指明了我们关心哪些描述符,和需要满足什么条件(可写,可读,异常)。一个文件描述集保存在 fd_set 类型中。fd_set类型变量每一位代表了一个描述符。我们也可以认为它只是一个由很多二进制位构成的数组。如下图所示: ...

June 10, 2026

Makefile 的基本概念

Makefile 是 make 工具的配置文件,主要用于定义如何构建和管理项目的编译过程。Makefile 是 C/C++ 编译项目中的重要工具,尤其在多文件、多模块的项目中,为了方便复杂项目的管理,可以通过自动化规则提高编译效率。 这篇文章是 Makefile 的入门教程的介绍,包括其基本语法、常用功能、以及实际使用中的高级技巧。 Makefile 的基本概念 安装 make: sudo apt-get update sudo apt-get install make 核心功能 自动化编译:根据文件的依赖关系自动决定哪些文件需要重新编译。 提高效率:只编译发生变化的部分。 多任务支持:可以定义清理、打包、测试等任务。 使用方法 运行make命令时,默认会读取当前目录下的Makefile 文件。 make # 执行默认的目标 make <target> # 执行指定的目标 例如: make clean # 执行 "clean" 目标 Makefile 的基本语法 1. 目标语法 Makefile 的基本语法如下: target: prerequisites commands target:目标文件或命令名称。例如可执行文件、目标文件或任务名称。 prerequisites:依赖文件或其他目标。只有依赖文件发生变化时,target 才会被重新生成。 commands:生成目标的命令(必须以 Tab 开头)。 示例: hello: hello.o gcc -o hello hello.o hello.o: hello.c gcc -c hello.c 在示例代码中: ...

June 10, 2026

MySQL

更新包管理器: 对于Ubuntu/Debian: sudo apt update 安装MySQL Server: 对于Ubuntu/Debian: sudo apt install mysql-server 启动MySQL服务: 对于Ubuntu/Debian: sudo systemctl start mysql 设置root密码: 运行以下命令: sudo mysql_secure_installation 验证安装: 运行以下命令登录MySQL: mysql -u root -p

June 10, 2026

一些网站

为什么Lisp语言如此先进? 一个前辈的官网

June 10, 2026

为什么叫补码

为什么叫补码(Two’s complement) 计算机的加减法运算天生是一个模2^N的同余类上的运算,满2^N会抛弃进位,那表示有符号数时使用同余类代表很正常吧,比如-1 = 2^N -1 (mod 2^N),-2 = 2^N-2 (mod 2^N),这实际上就是补码了。

June 10, 2026

关于位图存储与数组下标存储的探讨

关于位图存储与数组下标存储的探讨 最近在看《编程珠玑》,书中的第一章提到了位图。位图存储使用二进制位的位数信息,来表示数字。例如,存储1、3、4、6、8,这五个数字, 可以使用<1, 0, 1, 1, 0, 1, 0, 1>这样的向量来表示,这样可以大大减少存储空间, 只用了一个字节(8bit),就可以存储原来需要的8个数字才能表示的信息。 当我跟朋友谈到这个方法时,他却产生了质疑,他觉得这样不如直接按照数组下标存储来的快。他认为数组下标直接存储,直接一步完成,二位图则需要每次位运算寻址,会非常费时间。于是我们就决定写一个程序,实际跑一下看看。 这是位图的代码 typedef struct { uint32_t *bits; size_t size; } Bitmap; Bitmap *create_bitmap(size_t max_num) { size_t num_words = (max_num + 31) / 32; // 计算需要多少个32位字 Bitmap *bm = malloc(sizeof(Bitmap)); if (!bm) { perror("Bitmap allocation failed"); exit(EXIT_FAILURE); } bm->bits = calloc(num_words, sizeof(uint32_t)); // 分配约 1亿位 ≈ 12.5MB bm->size = max_num; if (!bm->bits) { perror("Bitmap bits allocation failed"); exit(EXIT_FAILURE); } return bm; } void bitmap_set(Bitmap *bm, int num) { size_t word_idx = num / 32; size_t bit_idx = num % 32; bm->bits[word_idx] |= (1U << bit_idx); } int bitmap_get(const Bitmap *bm, int num) { size_t word_idx = num / 32; size_t bit_idx = num % 32; return (bm->bits[word_idx] >> bit_idx) & 1U; } 位运算把每个字节大小的内存当作为一组,使用除法判断组数, 再用对8取余,得出每组的位次 ...

June 10, 2026