在我的自定义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() 动态优化内存使用。
防止缓冲区溢出: 消除可能导致错误的固定大小限制。