OSTEP Projects:Reverse

本文将介绍操作系统导论(Operating Systems: Three Easy Pieces)作者所开源的操作系统相关课程项目 的 Reverse 部分,包含个人的代码实现和设计思路。

思路

题目的要求很简单:按行读取数据,读取完成后将所读取到的所有行反向输出(行间反向,行内不变)。但代码实现上却包含不少细节。

首先是核心问题:如何将读取到行反向输出?首先可以确定的一点是:在所有行读取完成之前,读取到的每一个行都需要进行保存。那么,利用什么数据结构进行保存呢?我们需要这个数据结构能够确定输入的不同行之间的前后相对关系,因此想到使用线性表。由于最终读取到的行数是不确定的,因此不能使用一个固定大小的数组,而应该使用可变长的线性表,如链表、动态数组。而又因为可变数组的扩容操作比较耗时,且我们并不需要对元素进行随机访问,只需要最后输出的时候进行顺序遍历,因此链表就成为了最佳选择。

反转的具体实现可以参考经典问题反转链表,设定一个前驱结点 pre 和当前结点 cur,每次读取到新的行,就动态申请存储该行数据的内存空间,并将 cur 指向这块内存空间,然后将 cur 的 next 域指向 pre,然后 pre 再指向 cur,以便进行下一行的操作。

根据 README 的说明,当输入文件和输出文件是同一个文件时,程序打印相关错误信息并退出。这里一个简单的想法是使用 strcmp(argv[1], argv[2]) 判断两个参数字符串是否相同,但文件路径的表示方式并不是唯一的,如 ./t1.txtt1.txt 字符串不同,但表示的却是同一个文件。一个正确的做法是使用 stat() 函数,用以获取文件的状态信息,并对比输入与输出文件的状态信息是否相同。

最后,输入输出部分代码的实现可以封装为一个函数,并引入参数 FILE*,其中标准输入(stdin)和标准输出(stdout)可以看作是一个抽象的文件,并使用 fprintf() 进行文件写入。

代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>typedef struct LineNode {char* line_buf;struct LineNode* next;
} line_node;// 判断两个路径是否表示同一个文件
int is_same_file(const char* file1, const char* file2) {struct stat sb1, sb2;stat(file1, &sb1);stat(file2, &sb2);return sb1.st_dev == sb2.st_dev && sb1.st_ino == sb2.st_ino; // 设备ID和inode号均相同
}// 从文件fp中读取行数据
line_node* read_from_file(FILE* fp) {size_t sz = 0;line_node* cur = NULL; // 当前结点line_node* pre = NULL; // 前置结点while (1) {cur = (line_node*)malloc(sizeof(line_node*));if (cur == NULL) {fprintf(stderr, "malloc failed\n");exit(1);}if (getline(&(cur->line_buf), &sz, fp) == -1) { // 读到文件末尾,删去当前无效结点并结束循环line_node* temp = cur;cur = pre;free(temp);break;}cur->next = pre; // 链表反转pre = cur;}return cur;
}// 写入反转后的数据到文件fp
void write_to_file(line_node* cur, FILE* fp) {while (cur != NULL) {fprintf(fp, "%s", cur->line_buf);line_node* temp = cur;cur = cur->next;free(temp);}
}int main(int argc, char* argv[]) {line_node* cur = NULL;if (argc == 1) {cur = read_from_file(stdin);write_to_file(cur, stdout);}else if (argc >= 2 && argc <= 3) {FILE* fp = fopen(argv[1], "r");if (fp == NULL) {fprintf(stderr, "reverse: cannot open file '%s'\n", argv[1]);exit(1);}cur = read_from_file(fp);if (argc == 2) {write_to_file(cur, stdout);}else {FILE* fp2 = fopen(argv[2], "w");if (fp2 == NULL) {fprintf(stderr, "reverse: cannot open file '%s'\n", argv[2]);exit(1);}if (is_same_file(argv[1], argv[2])) {fprintf(stderr, "reverse: input and output file must differ\n");exit(1);}write_to_file(cur, fp2);fclose(fp2);}fclose(fp);}else {fprintf(stderr, "usage: reverse <input> <output>\n");exit(1);}return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/7074.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

75.网络游戏逆向分析与漏洞攻防-角色与怪物信息的更新-伪造服务端更新属性消息欺骗客户端

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 如果看不懂、不知道现在做的什么&#xff0c;那就跟着做完看效果&#xff0c;代码看不懂是正常的&#xff0c;只要会抄就行&#xff0c;抄着抄着就能懂了 内容…

wordpress外贸网站建设主机选择的注意事项

在为WordPress外贸网站建设选择主机时&#xff0c;您需要注意以下几点&#xff1a; 服务器地理位置&#xff1a; 选择一个靠近目标客户群的服务器位置&#xff0c;这将有助于提高网站的加载速度和可靠性。通常&#xff0c;如果您的目标客户群是国外用户&#xff0c;建议选择美…

UE5(射线检测)学习笔记

这一篇会讲解射线检测点击事件、离开悬停、进入悬停事件的检测&#xff0c;以及关闭射线检测的事件&#xff0c;和射线检测蓝图的基础讲解。 创建一个简单的第三人称模板 创建一个射线检测的文件夹RadiationInspection&#xff0c;并且右键蓝图-场景组件-命名为BPC_Radiation…

语音识别简介

⚠申明&#xff1a; 未经许可&#xff0c;禁止以任何形式转载&#xff0c;若要引用&#xff0c;请标注链接地址。 全文共计3077字&#xff0c;阅读大概需要3分钟 &#x1f308;更多学习内容&#xff0c; 欢迎&#x1f44f;关注&#x1f440;【文末】我的个人微信公众号&#xf…

MySQL没有初始化配置文件设置属性

情况描述 安装mysql的时候&#xff0c;为了速度&#xff0c;并没有配置my.ini或者my.cnf文件&#xff0c;数据库因为断电&#xff0c;导致数据都看不见了&#xff0c;一直提示不存在&#xff0c;这时候需要修改配置文件&#xff0c;将innodb_force_recovery设置为0到6的值&…

淘宝商品评论数据获取:从API调用到应用实践

在电商的世界里&#xff0c;用户评论是洞察商品质量的一扇窗。淘宝&#xff0c;作为中国最大的在线购物平台&#xff0c;其海量的商品评论数据尤为宝贵。本文将带您走进淘宝商品评论数据的获取之旅&#xff0c;从API调用的基础知识到实际应用的代码示例&#xff0c;一探究竟。 …

Pycharm debug 运行报错 (RuntimeError: cannot release un-acquired lock)

问题描述&#xff1a; 最近再跑一个 flask应用&#xff0c;Pycharm 运行没问题&#xff0c;debug断点启动时报错 如下&#xff1a; 解决方案&#xff1a; 在环境变量中增加 GEVENT_SUPPORTTrue 启动成功&#xff01;

[激光原理与应用-92]:振镜的光路图原理

目录 一、振镜的光路 二、振镜的工作原理 2.1 概述 2.2 焊接头 2.3 准直聚焦头-直吹头 2.4 准直聚焦头分类——按应用分 2.4.1 准直聚焦头分类——功能分类 2.4.2 准直聚焦头镜片 2.4.3 振镜焊接头 2.4.4 振镜分类&#xff1a; 2.4.5 动态聚焦系统演示&#xff08;素…

MQ如何保证可靠性

&#x1f4dd;个人主页&#xff1a;五敷有你 &#x1f525;系列专栏&#xff1a;MQ ⛺️稳中求进&#xff0c;晒太阳 消息到达MQ以后&#xff0c;如果MQ不能及时保存&#xff0c;也会导致消息丢失&#xff0c;所以MQ的可靠性也非常重要。 2.数据持久化 为了提高性能&a…

被苹果商店打回20多个包,App Store都干了啥!

本次被拒的App涉及金融、教育、游戏等各个领域&#xff0c;其中既有首发产品也有更新产品&#xff0c;原因多涉及疑似切支付、马甲包等问题&#xff1b;不过也有部分开发者反映遭到”误伤”&#xff0c;正常包体也被打回。 从今年1月底开始&#xff0c;许多开发者发现在向苹果…

Typescript语法二

继承 继承是⾯向对象编程中的重要机制&#xff0c;允许⼀个类&#xff08;⼦类或派⽣类&#xff09;继承另⼀个类&#xff08;⽗类或基类&#xff09;的属性和⽅法。⼦类可以直接使⽤⽗类的特性&#xff0c;并根据需要添加新的特性或覆盖现有的特性。这种机制赋予⾯向对象程序良…

头歌 实验六 Java流式编程与网络程序设计

实验六 Java流式编程与网络程序设计 制作不易&#xff01;点个关注&#xff0c;给大家带来更多的价值 第1关 字节输入/输出流实现数据的保存和读取 package step1;import java.io.*; import java.util.*;public class SortArray {public static void main(String[] args) {/…

getchar和putchar函数详解

getchar和putchar函数详解 1.getchar函数1.1函数概述1.2函数返回值1.3函数注意事项1.4函数的使用 2.putchar函数2.1函数概述2.2函数返回值2.3函数使用实例 1.getchar函数 1.1函数概述 从一个流中读取一个字符&#xff0c;或者从标准输入中获得一个字符 函数原型&#xff1a; …

Sa-Token框架入门使用

说明&#xff1a;Sa-Token是一个轻量级java权限认证框架&#xff08;官方语&#xff09;&#xff0c;所谓权限认证框架&#xff0c;就是登录框架&#xff0c;像Shiro、Spring Security。本文介绍Sa-Token框架的入门使用&#xff0c;基于Spring Boot环境。 准备工作 首先&…

滑动窗口 | 1652. 拆炸弹 |LeetCode

文章目录 题目介绍暴力(可以过力扣竟然。不愧是简单题)&#xff1a;滑动窗口 祝你天天开心 题目介绍 你有一个炸弹需要拆除&#xff0c;时间紧迫&#xff01;你的情报员会给你一个长度为 n 的 循环 数组 code 以及一个密钥 k 。 为了获得正确的密码&#xff0c;你需要替换掉每…

第12章 消息服务 ❤❤❤❤

第12章 消息服务 12.1 JMS_ActiveMQ1. 简介2. ActiveMQ安装Linux安装命令问题1:网页访问不了问题2: 修改密码3. 整合SpringBoot3.1 依赖3.2 配置3.3 JmsComponent 组件3.4 测试12.2 AMQP_RabbitMQ1. 简介2. RabbitMQ

spring boot使用redis 存储数据时 字段为时间类型为LocalDateTime 发现存储到redis变成了对象

在项目中从redis获取带有LocalDateTime类型属性的对象时出现了以下异常&#xff1a; "createTime": {"dayOfYear":141,"dayOfWeek":"WEDNESDAY","month":"MAY","dayOfMonth":20,"year":2020…

代码随想录第四十五天|爬楼梯、零钱兑换、完全平方数

题目链接&#xff1a;57. 爬楼梯&#xff08;第八期模拟笔试&#xff09; 代码如下&#xff1a; 题目链接&#xff1a;. - 力扣&#xff08;LeetCode&#xff09; 代码如下&#xff1a; 题目链接&#xff1a;. - 力扣&#xff08;LeetCode&#xff09; 代码如下&#xff1a;…

Vue阶段练习:初始化渲染、获取焦点、记账清单

阶段练习主要承接Vue 生命周期-CSDN博客 &#xff0c;学习完该部分内容后&#xff0c;进行自我检测&#xff0c;每个练习主要分为效果显示、需求分析、静态代码、完整代码、总结 四个部分&#xff0c;效果显示和准备代码已给出&#xff0c;我们需要完成“完整代码”部分。 练习…

关系型数据库MySql分库分表带来的问题以及解决方案

水平分表 水平分表是什么&#xff1f; 将一张表横向拆分为多张表&#xff0c;拆分的表&#xff0c;依然在同一个库中。 例如&#xff0c;user表有400w条记录&#xff0c;将user表拆分成4张表&#xff0c;每张表100w条记录。拆分后的表名&#xff0c;分别叫做user_0、user1、u…