我正在用 C 语言构建一个命令行解析器,我在其中获取命令行输入并将其组织成一个结构体。该结构有一个命令成员,该成员包含一个结构,该结构具有第一个命令、其参数以及指向下一个命令结构的指针成员,依此类推。命令和相应的参数在输入字符串中由竖线分隔。每个命令结构体都有一个名为 command_args 的成员 char* 数组,它保存命令和所有参数。
我的函数在大多数情况下似乎都能正常工作,但在某些奇怪的情况下,命令将被替换为看似随机的字符串。我注意到它似乎不会在第一个命令中发生,并且仅在有多个参数时才会发生。使用调试器,我注意到,首先,命令被正确插入到结构中,但后来当函数到达第二个参数时,参数被正确插入到结构位置,但同时用不同的值替换命令。我注意到它似乎永远不会在第一个命令中发生(仅在后续命令中),并且仅在有多个参数时发生。
我已经包含了 .c 和 .h 文件以及输出示例,任何有关如何修复错误的帮助将不胜感激。
myshell_parser.c
#ifndef MYSHELL_PARSER_H
#define MYSHELL_PARSER_H
#include <stdbool.h>
#define MAX_LINE_LENGTH 512
#define MAX_ARGV_LENGTH (MAX_LINE_LENGTH / 2 + 1)
struct pipeline_command {
char *command_args[MAX_ARGV_LENGTH]; // arg[0] is command, rest are arguments
char *redirect_in_path; // NULL or Name of file to redirect in from
char *redirect_out_path; // NULL or Name of a file to redirect out to
struct pipeline_command *next; // next command in the pipeline. NULL if done
};
struct pipeline {
struct pipeline_command *commands; // first command
bool is_background; // TRUE if should execue in background
};
void pipeline_free(struct pipeline *pipeline);
struct pipeline *pipeline_build(const char *command_line);
#endif /* MYSHELL_PARSER_H */
myshell_parser.c
#include "myshell_parser.h"
#include "stddef.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
struct pipeline *pipeline_build(const char *command_line)
{
struct pipeline_command* current;
current = malloc(sizeof(struct pipeline_command));
struct pipeline* output;
output = malloc(sizeof(struct pipeline));
output->is_background = 0;
output->commands = current;
char currentStr[100] = "";
int argCount = 0;
bool redirOut = 0;
bool redirIn = 0;
bool strFin = 0;
for(int i = 0; command_line[i] != 0; i++)
{
if(command_line[i] == '&')
{
output->is_background = 1;
}
if(command_line[i] != ' ' && command_line[i] != '|' && command_line[i] != '<' && command_line[i] != '>' && command_line[i] != '\n' && command_line[i] != '&')
{
strFin = 0;
char temp[2];
temp[0] = command_line[i];
temp[1] = 0;
strcat(currentStr, temp);
}
if(((command_line[i+1] != ' ' && command_line[i] == ' ') || command_line[i] == '|' || command_line[i] == '\n' || command_line[i + 1] == 0 || command_line[i] == '<' || command_line[i] == '>' || command_line[i] == '&') && currentStr[0] != 0)
{
strFin = 1;
}
if(strFin)
{
if(currentStr[0] == 0)
{
continue;
}
if(!redirOut && !redirIn)
{
current->command_args[argCount] = strdup(currentStr);
strFin = 0;
argCount++;
//currentStr.clear();
currentStr[0] = 0;
}
else if(redirOut)
{
current->redirect_out_path = strdup(currentStr);
currentStr[0] = 0;
redirOut = 0;
strFin = 0;
}
else if(redirIn)
{
current->redirect_in_path = strdup(currentStr);
currentStr[0] = 0;
redirIn = 0;
strFin = 0;
}
}
if(command_line[i] == '|')
{
argCount = 0;
struct pipeline_command* nextc;
nextc = malloc(sizeof(struct pipeline));
current->next = nextc;
current = nextc;
}
else if(command_line[i] == '>')
{
redirOut = 1;
argCount = 0;
}
else if(command_line[i] == '<')
{
redirIn = 1;
argCount = 0;
}
}
// printf("out: %s\n", output->commands->next->command_args[0]);
// TODO: Implement this function
return output;
}
void pipeline_free(struct pipeline *pipeline)
{
struct pipeline_command* current = pipeline->commands;
struct pipeline_command* temp = current;
while(current != NULL){
temp = current;
current = current->next;
for(int i = 0; temp->command_args[i] != NULL; i++)
{
free(temp->command_args[i]);
free(temp->redirect_in_path);
free(temp->redirect_out_path);
}
free(temp);
}
free(pipeline);
// TODO: Implement this function
}
输入:
struct pipeline *my_pipeline = pipeline_build("cat arg1 arg2 arg3 < input.txt | grep arg1 arg2 arg3 | ls arg1 arg2 arg3 > Output.txt &");
输出:
mypipeline->commands->next->command_args[0] 返回“�”而不是“grep”
mypipeline->commands->next->next->command_args[0] 返回“�”而不是“ls”
但是,mypipeline->commands->command_args[0]按预期返回“cat”
您的代码具有未定义的行为,因为您尝试分配太小的内存块。结果,您写入了您无权访问的内存,任何事情都可能发生。
我们来看看这部分代码。
if(command_line[i] == '|')
{
argCount = 0;
struct pipeline_command* nextc;
nextc = malloc(sizeof(struct pipeline));
current->next = nextc;
current = nextc;
}
你
malloc
的内存大小为struct pipeline
,但你的指针是struct pipeline_command
类型。例如,在使用 gcc 的 x86_64 上,sizeof(struct pipeline)
为 16,而 sizeof(struct pipeline_command)
为 2080,offsetof(struct pipeline_command, next)
为 2072,因此您已经在下一行中访问无效内存。
为了避免此类错误,您可以直接将
sizeof
运算符与表达式而不是类型一起使用。
改变
nextc = malloc(sizeof(struct pipeline));
到
nextc = malloc(sizeof *nextc);