ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

Linux C项目 | 迷你命令行解释器 (2)

Linux C项目 | 迷你命令行解释器 (2) 模块二实现split_line( ) 拆分命令和参数模块一已经实现了获取一整行字符串命令但是后面执行程序的时候并不是直接拿这一整行字符串去执行程序而是需要得到一个一个的参数 如输入命令ls -l /home → 得到 ls-l /home 参数使用数组去存储它们这时候需要考虑这一个一个的参数应该怎么存放字符串也就是字符数组存放到内存使用 char * 可以表示一个字符串。得到的多个命令参数即多个字符串也就相当于多个char * 。现在要把这多个char * (char类型的指针)存放起来并且要方便管理访问 → 可以使用指针数组将这些char * 保存起来数组的每个元素是 char * 然后需要有一个指针去指向首元素方便管理访问即 char ** 一个指向char * 类型的指针画草图理解一下设计split_line( ) → 传入用户输入的命令行字符串 → 按照指定分隔符切分成多个参数保存 → 返回指向保存这些字符指针的数组指针1.需要用到C标准库提供的切割函数strtokstrtok(line, ) → 按空格切割返回值是切出来的字符串首地址没有内容了返回NULL使用方法char *token; // 需要字符指针去接收切割出来的字符串首地址 char line[] ls -l /home; token strtok(line, ); // 按空格切割 token → ls token strtok(NULL, ); // token → -l token strtok(NULL, ); // token → /home注意第一次调用传入line接下去要传NULL意思是继续切刚才那个字符串优化一下循环到切完char *token; // 需要字符指针去接收切割出来的字符串首地址 char line[] ls -l /home; token strtok(line, ); // 按空格切割 token → ls while(c ! NULL){ token strtok(NULL, ); }模块二第一版核心代码char **split_line(char *line){ // 形参char *line 用于接收传入的命令字符串首地址 返回值类型是char **返回一个指向char *数组的指针 #define TOK_BUFFER_SIZE 64 // 宏定义参数个数缓冲区大小 64即可因为参数个数不会很多 int bursize TOK_BUFFER_SIZE; // 初始化缓冲区 用一个变量去接收 因为不够用的时候需要扩容 char *token NULL; // 用于接收切割出来的字符首地址 int position 0; // 记录存放位置 // malloc一块存放字符指针的内存 char **tokens malloc(sizeof(char *) * bursize); // 用指向char *的指针变量去接收 // 有mallc就要进行检查 if(!tokens){ fputs(malloc申请内存失败\n,stderr); // 因为不需要格式化输出 这里使用fputs输出到标准错误流 exit(EXIT_FAILURE); // 异常退出 } // 切割 token strtok(line, ); // 按空格切割命令字符串 返回切割出来的字符首地址如果没有内容返回NULL // 后续的字符串循环切割 while(token ! NULL){ // 没切割完就继续循环切割 // 存放 先存放上次切割出来的字符串 tokens[position] token; position; // 继续后续切割 token strtok(NULL, ); } return tokens; // 返回指针数组 }核心逻辑实现了还有以下问题1.指针数组没有置空NULL无法判断结束2.还未处理超过64个参数的越界问题3.目前只能处理空格分隔的命令修改后的代码char **split_line(char *line){ // 形参char *line 用于接收传入的命令字符串首地址 返回值类型是char **返回一个指向char *数组的指针 #define TOK_BUFFER_SIZE 64 // 宏定义初始参数指针容量为64不够时动态扩容 #define TOK_DELIM \t\r\n\a // 宏定义所有分隔符 int bufsize TOK_BUFFER_SIZE; // 初始化缓冲区 用一个变量去接收 因为不够用的时候需要扩容 char *token NULL; // 用于接收切割出来的字符串首地址 int position 0; // 记录存放位置 // malloc一块存放字符指针的内存 char **tokens malloc(sizeof(char *) * bufsize); // 用指向char *的指针变量去接收 // 有mallc就要进行检查 if(!tokens){ fputs(malloc申请内存失败\n,stderr); // 因为不需要格式化输出 这里使用fputs输出到标准错误流 exit(EXIT_FAILURE); // 异常退出 } // 1.切割 token strtok(line,TOK_DELIM); // 按指定分隔符切割命令字符串 返回切割出来的字符首地址如果没有内容返回NULL // 后续的字符串循环切割 while(token ! NULL){ // 没切割完就继续循环切割 // 2.存放 先存放上次切割出来的字符串 tokens[position] token; position; // 数组满了进行扩容 if(position bufsize){ bufsize TOK_BUFFER_SIZE; tokens realloc(tokens,bufsize * sizeof(char *)); if(!tokens){ fputs(realloc申请内存失败\n,stderr); exit(EXIT_FAILURE); } } // 继续后续切割 token strtok(NULL,TOK_DELIM); } // 存放完后 将最后一个元素置空 才能够判断数组结束 tokens[position] NULL; return tokens; // 返回指针数组 }注意realloc的时候如果申请失败的话返回NULLtokens的指针指向NULL这样的话原来指向的内存地址就丢失了会发生内存泄漏因为realloc失败不会释放旧内存项目代码realloc失败之后就马上结束进程回收进程占用的内存包括泄漏的那块就内存所以不会造成太大问题模块二已设计开发完成梳理一下链路
返回列表