四时宝库

程序员的知识宝库

我如何用C语言构建简单Shell(二)

在我的自定义shell项目的这一部分中,我将解释如何在C中动态解析用户输入。在shell环境中正确解析输入是至关重要的,因为命令通常包含多个参数。我没有依赖固定大小的缓冲区,而是实现了动态内存分配方法以获得更好的灵活性。


理解parser函数

parser() 函数负责:
动态将用户命令分割成参数
高效管理内存分配和重新分配
返回参数数组以供进一步处理

代码分解

#ifndef PARSER_H
#define PARSER_H

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define arg_buffer_size 4

char **parser(char *command, int *argc);
void free_args(char **args, int argc);

#endif

o 头文件保护 (#ifndef PARSER_H): 防止多次包含。

o 常量定义 (arg_buffer_size): 设置参数存储的初始缓冲区大小。

o 函数原型: 声明用于分割输入的 parser() 函数和用于内存清理的 free_args()


parser()的实现

char **parser(char *command, int *argc)
{
    int size = arg_buffer_size;
    int length = 0;
    char **args = malloc(size * sizeof(char *));

o 内存分配 (malloc): 为字符串数组分配内存。

o 错误处理: 虽然没有明确显示,但应该检查 malloc 以防止失败。

    *argc = 0;
    char *token = strtok(command, " ");
    while (token)
    {
        if (*argc >= size)
        {
            size *= 2;
            args = realloc(args, size * sizeof(char *));
        }
        args[*argc] = strdup(token);
        (*argc)++;
        token = strtok(NULL, " ");
    }
    args[*argc] = NULL;
    return args;
}

1. 标记化输入

o 使用 strtok() 将输入分割成单独的参数。

o 遍历每个标记并动态存储它。

2. 动态扩展内存 (realloc)

o 如果参数计数超过分配的大小,缓冲区会加倍。

o realloc() 尝试安全地调整缓冲区大小。

3. 存储参数

o 使用 strdup() 复制每个标记以避免内存损坏。

o 最后一个参数设置为 NULL 以正确执行命令。


清理内存

void free_args(char **args, int argc)
{
    for (int i = 0; i < argc; i++)
    {
        free(args[i]);
    }
    free(args);
}

o 防止内存泄漏: 释放每个参数和整个数组以确保高效的内存管理。


将解析器集成到Shell中

parser() 函数集成到shell的主循环中,允许命令被正确处理。

int main(void)
{
    Command commands[] = {
        {"help", help_action},
        {"clr", clear_action},
        {"say", say_action},
        {"exit", exit_action},
        {"cwp", cwp_command},
        {"date", date_command},
        {"clone", clone_file_command},
        {"cut", cut_file_command},
        {"read", read_file_command},
        {"del", delete_file_command},
        {"open", open_program_command},
        {"list", list_of_directory}};

    int command_count = sizeof(commands) / sizeof(commands[0]);
    while (1)
    {
        int argc;
        printf("shell_of_mine => ");
        char *command = read_command();
        char **args = parser(command, &argc);
        execute_command(args, argc, commands, command_count);
        free_args(args, argc);
        free(command);
    }
    return 0;
}

o 主循环: 持续读取、解析和执行用户命令。

o 动态解析: 解析器动态提取参数,允许灵活的命令处理。

o 内存清理: free_args() 确保执行后释放分配的内存。


为什么采用这种方法?

处理任意命令长度: 与静态数组不同,动态分配确保灵活性。

高效的内存管理: 使用 realloc() 动态优化内存使用。

防止缓冲区溢出: 消除可能导致错误的固定大小限制。


发表评论:

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言
    友情链接