用C语言构建简单Shell:系统编程初学者指南(2-3)
我如何用C语言构建简单Shell——系统编程初学者指南 (2/3)
#cli #c #systemprogramming #memorymanagement
第2部分:在自定义Shell中解析用户输入(C编程)
在我的自定义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
头文件保护 (#ifndef PARSER_H): 防止多次包含。
常量定义 (arg_buffer_size): 设置参数存储的初始缓冲区大小。
函数原型: 声明用于分割输入的 parser() 函数和用于内存清理的 free_args()。
_parser()_ 的实现
- char **parser(char *command, int *argc)
- {
- int size = arg_buffer_size;
- int length = 0;
- char **args = malloc(size * sizeof(char *));
内存分配 (malloc): 为字符串数组分配内存。
错误处理: 虽然没有明确显示,但应该检查 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;
- }
标记化输入
使用 strtok() 将输入分割成单独的参数。
遍历每个标记并动态存储它。
动态扩展内存 (realloc)
如果参数计数超过分配的大小,缓冲区会加倍。
realloc() 尝试安全地调整缓冲区大小。
存储参数
使用 strdup() 复制每个标记以避免内存损坏。
最后一个参数设置为 NULL 以正确执行命令。
清理内存
- void free_args(char **args, int argc)
- {
- for (int i = 0; i < argc; i++)
- {
- free(args[i]);
- }
- free(args);
- }
防止内存泄漏: 释放每个参数和整个数组以确保高效的内存管理。
将解析器集成到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;
- }
主循环: 持续读取、解析和执行用户命令。
动态解析: 解析器动态提取参数,允许灵活的命令处理。
内存清理: free_args() 确保执行后释放分配的内存。
为什么采用这种方法?
📌 处理任意命令长度: 与静态数组不同,动态分配确保灵活性。
📌 高效的内存管理: 使用 realloc() 动态优化内存使用。
📌 防止缓冲区溢出: 消除可能导致错误的固定大小限制。
