应用bitmap实现的strtok

本文深入探讨了C++中用于字符串分割的`strtok`函数的工作原理,包括其内部实现机制、常见用法及注意事项。特别强调了函数的使用技巧和避免已知警告的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


// Basic.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

char string[] = "A string\tof ,,tokens\nand some more tokens";
char seps[] = " ,\t\n";
char *token;


char *strtok(char *str, const char *delim)
{
static char *last;
if (delim == NULL || (str == NULL && last == NULL))
return NULL;

if (str == NULL)
{
str = last;
}

char arr[32];
int i=0;
for(i=0; i < 32; i++)
{
arr[i] = '\0';
}
const char *dpos=delim;
while(*dpos)
{
arr[*dpos >> 3] |= (1 << (*dpos & 7));
dpos++;
}

while(*str && (arr[*str >> 3] & (1 << (*str & 7))) )
str++;

char *tar = str;

while(*str && !(arr[*str >> 3] & (1 << (*str & 7))))
str++;

if(*str != '\0')
{
*str = '\0';
last = str+1;
}
else{
last = NULL;
}

return tar;
}

void test_strtok()
{
printf( "Tokens:\n" );

// Establish string and get the first token:
token = strtok( string, seps ); // C4996
// Note: strtok is deprecated; consider using strtok_s instead
while( token != NULL )
{
// While there are tokens in "string"
printf( "%s\n", token );

// Get next token:
token = strtok( NULL, seps ); // C4996
}
}



int _tmain(int argc, _TCHAR* argv[])
{
test_strtok();
}


1.设计目的 通过模拟类 UNIX 文件系统的核心机制,理解 inode 索引结构与位示图(Bitmap)的协同工作原理,掌握文件创建、读写、删除等基本操作的实现逻辑,提升对操作系统文件管理模块的实践认知。 2.内容要求 文件系统功能:实现以下命令行操作: 命令格式 功能描述 mkfs 格式化文件系统,初始化磁盘块与元数据结构 touch <file> 创建空文件 write <file> <size> 向文件追加指定大小(KB)的数据,超出 12KB 时报错 “尚未实现间接块” read <file> 返回文件当前大小(KB) rm <file> 删除文件并回收占用的磁盘块 ls 列出 inode 表与空闲块位示图的状态 数据结构设计: 位示图(Bitmap):使用长度为DISK_SIZE的数组管理磁盘块,1表示已占用,0表示空闲; inode 结构:每个文件对应一个 inode,包含文件大小(KB)和直接块指针列表(最多 12 个块)。 系统限制: 总磁盘块数:DISK_SIZE = 128(每块 1KB); 单文件最大大小:12KB(仅支持直接块,不实现间接块索引); 元数据(inode 表、位示图)常驻内存,无需持久化存储。 3.关键概念与算法说明 inode:索引节点,存储文件元数据(大小、块指针等),不包含文件名(文件名由目录管理,本题简化为 inode 表直接映射文件名); 位示图(Bitmap):用二进制位表示磁盘块的占用状态,便于快速查找空闲块; 直接块:inode 中直接存储的磁盘块指针,本题限制最多 12 个,对应文件最大 12KB。 磁盘块管理 分配块(alloc_block):  遍历位示图,查找第一个值为 0 的块;  若找到,将其标记为 1 并返回块号;若全满,返回 None 并提示 “磁盘已满”。 回收块(free_block):将指定块号在位示图中标记为 0。 文件操作流程 write 命令:  检查文件是否存在,不存在则报错;  计算需要分配的块数(每 1KB 对应 1 块);  循环分配块,直到满足大小或达到直接块上限(12 块);  若块数超过 12,提示 “超出直接块上限”;若磁盘满,提示 “磁盘已满”。 rm 命令:  检查文件是否存在,不存在则报错;  遍历文件的块指针,逐个回收块(标记位示图为 0);  从 inode 表中删除该文件。 4.输入 / 输出样例 命令行交互样例 fs> mkfs 格式化完成 fs> touch test.txt fs> write test.txt 5 写入完成, 文件大小 5 KB fs> read test.txt test.txt: 5 KB fs> write test.txt 8 写入完成, 文件大小 12 KB fs> write test.txt 1 超出直接块上限 fs> ls ===== inode 表 ===== test.txt 12KB blocks:[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] ===== 位示图(1=占用) ===== 11111111111111111111111111111111 11111111111111110000000000000000 ...(剩余块为0) 错误处理样例 fs> write non_exist.txt 1 无此文件 fs> rm test.txt 已删除 fs> read test.txt 无此文件 fs> write test.txt 1 磁盘已满 # 假设此时所有块已占用 5.设计成果要求 程序功能: 实现所有指定命令,正确处理文件创建、读写、删除及块分配回收; 当文件大小超过 12KB 或磁盘空间不足时,给出明确错误提示。 输出规范: ls命令需清晰展示 inode 表(文件名、大小、块指针)和位示图(按块号顺序显示占用状态); 其他命令需返回操作结果(如 “写入完成”“磁盘已满” 等)。 代码规范: 注释清晰,函数命名符合功能(如alloc_block、free_block); 数据结构定义明确(Inode类、位示图数组)。 #include <stdio.h> #include <stdlib.h> #include <string.h> #define DISK_SIZE 128 // 磁盘总块数(128块,每块1KB,共128KB) #define MAX_BLOCKS 12 // 单文件最大块数(12块=12KB) #define MAX_FILES 32 // 最大文件数量 // Inode结构体:存储文件元数据 typedef struct { char name[32]; // 文件名 int size; // 文件当前大小(单位:KB) int blocks[MAX_BLOCKS]; // 直接块指针(-1表示未使用) } Inode; Inode inodes[MAX_FILES]; // inode表:存储所有文件的元数据 int bitmap[DISK_SIZE]; // 位示图:0=空闲块,1=已占用块 /** * 格式化文件系统 * 功能:初始化inode表和位示图,清空所有数据 */ void mkfs() { // 初始化inode表:所有inode置为空闲状态 for (int i = 0; i < MAX_FILES; i++) { strcpy(inodes[i].name, ""); // 清空文件名(表示空闲) inodes[i].size = 0; // 初始大小为0 memset(inodes[i].blocks, -1, sizeof(inodes[i].blocks)); // 块指针置为-1(未使用) } // 初始化位示图:所有磁盘块置为空闲(0) for (int i = 0; i < DISK_SIZE; i++) { bitmap[i] = 0; } printf("格式化完成\n"); } /** * 查找文件对应的inode索引 * 参数:文件名 * 返回:inode在表中的索引(-1表示未找到) */ int find_inode(const char *name) { for (int i = 0; i < MAX_FILES; i++) { if (strcmp(inodes[i].name, name) == 0) { return i; // 找到文件,返回索引 } } return -1; // 未找到文件 } /** * 分配一个空闲磁盘块 * 返回:分配的块号(-1表示磁盘已满) */ int alloc_block() { for (int i = 0; i < DISK_SIZE; i++) { if (bitmap[i] == 0) { // 找到空闲块(0表示空闲) bitmap[i] = 1; // 标记为已占用(1表示占用) return i; // 返回块号 } } return -1; // 无空闲块,返回-1 } /** * 回收磁盘块 * 参数:需要回收的块号 */ void free_block(int block_num) { if (block_num >= 0 && block_num < DISK_SIZE) { // 检查块号合法性 bitmap[block_num] = 0; // 标记为空闲 } } /** * 创建空文件(touch命令) * 参数:文件名 */ void touch(const char *filename) { // 检查文件是否已存在 if (find_inode(filename) != -1) { printf("文件已存在\n"); return; } // 查找空闲inode for (int i = 0; i < MAX_FILES; i++) { if (strlen(inodes[i].name) == 0) { // 找到空闲inode(文件名为空) strcpy(inodes[i].name, filename); // 设置文件名 inodes[i].size = 0; // 初始大小为0 memset(inodes[i].blocks, -1, sizeof(inodes[i].blocks)); // 块指针置为-1 printf("文件 %s 创建成功\n", filename); return; } } printf("文件表已满\n"); } /** * 向文件追加数据(write命令) * 参数:文件名,追加的大小(KB) * 说明:每次写入的是“追加大小”,而非“目标总大小”,累加后不能超过12KB */ void write_file(const char *filename, int append_kb) { int idx = find_inode(filename); if (idx == -1) { printf("无此文件\n"); return; } Inode *node = &inodes[idx]; // 检查追加后是否超过最大限制(12KB) if (node->size + append_kb > MAX_BLOCKS) { // MAX_BLOCKS=12,即12KB printf("超出直接块上限\n"); return; } // 分配需要追加的块(每1KB对应1块) for (int i = 0; i < append_kb; i++) { int block = alloc_block(); if (block == -1) { // 磁盘已满,分配失败 printf("磁盘已满\n"); return; } // 将新块添加到inode的块列表(当前大小的位置) node->blocks[node->size + i] = block; } // 更新文件大小(累加追加的大小) node->size += append_kb; printf("写入完成, 文件大小 %d KB\n", node->size); } /** * 读取文件大小(read命令) * 参数:文件名 */ void read_file(const char *filename) { int idx = find_inode(filename); if (idx == -1) { printf("无此文件\n"); return; } printf("%s: %d KB\n", filename, inodes[idx].size); } /** * 删除文件(rm命令) * 参数:文件名 */ void rm_file(const char *filename) { int idx = find_inode(filename); if (idx == -1) { printf("无此文件\n"); return; } Inode *node = &inodes[idx]; // 回收文件占用的所有磁盘块 for (int i = 0; i < node->size; i++) { if (node->blocks[i] != -1) { free_block(node->blocks[i]); } } // 清空inode信息(标记为空闲) strcpy(node->name, ""); node->size = 0; memset(node->blocks, -1, sizeof(node->blocks)); printf("已删除\n"); } /** * 列出inode表和位示图状态(ls命令) */ void ls() { printf("===== inode 表 =====\n"); for (int i = 0; i < MAX_FILES; i++) { if (strlen(inodes[i].name) > 0) { // 只显示存在的文件 printf("%-10s %4dKB blocks:[", inodes[i].name, inodes[i].size); for (int j = 0; j < inodes[i].size; j++) { printf("%d", inodes[i].blocks[j]); if (j < inodes[i].size - 1) { printf(", "); } } printf("]\n"); } } printf("===== 位示图(1=占用) =====\n"); for (int i = 0; i < DISK_SIZE; i++) { printf("%d", bitmap[i]); if ((i + 1) % 32 == 0) { // 每32位换行,便于查看 printf("\n"); } } printf("\n"); } /** * 主函数:命令行交互 */ int main() { mkfs(); // 初始化文件系统 char input[100]; while (1) { printf("fs> "); if (!fgets(input, sizeof(input), stdin)) break; // 移除输入中的换行符 input[strcspn(input, "\n")] = 0; // 解析命令 if (strncmp(input, "mkfs", 4) == 0) { mkfs(); } else if (strncmp(input, "touch ", 6) == 0) { touch(input + 6); // 提取文件名(跳过"touch ") } else if (strncmp(input, "write ", 6) == 0) { // 解析"write 文件名 大小"格式 char *filename = strtok(input + 6, " "); char *size_str = strtok(NULL, " "); if (filename && size_str) { int append_kb = atoi(size_str); // 追加的大小(KB) write_file(filename, append_kb); } else { printf("参数错误,格式:write <file> <size>\n"); } } else if (strncmp(input, "read ", 5) == 0) { read_file(input + 5); // 提取文件名(跳过"read ") } else if (strncmp(input, "rm ", 3) == 0) { rm_file(input + 3); // 提取文件名(跳过"rm ") } else if (strncmp(input, "ls", 2) == 0) { ls(); } else if (strncmp(input, "exit", 4) == 0) { break; // 退出程序 } else { printf("未知命令\n"); } } getchar(); return 0; } 根据代码和说明,回答课程设计的问题:一、需求分析:说明文件系统模拟的目标与核心功能; 二、整体功能及设计(功能划分及流程图):绘制 inode 结构、位示图管理流程及命令执行流程图 三、编程实现(要求有注释):重点说明块分配 / 回收、文件读写的关键函数; 四、使用说明 五、结果分析
最新发布
07-02
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值