我是编程新手,作为一项任务,我被告知要做一个迷你 Bash。我决定做一个解析器,以防要分析的命令中没有词法错误,将填充一个 char*** (据我所知它将是一个字符串矩阵)。
我遇到的问题是,在某个时候我得到了一个我不理解的 sysmalloc 断言。我的代码非常糟糕(直到现在我从来没有做过免费的),但我认为它至少应该运行并使用 valgrind 告诉我我有内存泄漏。
我开始学习如何正确使用 C 指针,所以请多关照。如果有人知道问题出在哪里(它必须在解析器函数中),我将非常感谢他们向我解释。这是代码(如果有人需要查看更多代码,请告诉我):
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>
#include <readline/readline.h>
#include <readline/history.h>
#include <unistd.h>
#include <stdbool.h>
char*** parser(char*);
size_t token_counter(const char const *, char);
bool double_occurrence(char*, char, size_t);
bool line_semantic_correctness(char*);
bool arg_semantic_correctness(char*, int);
int main(int argc, char *argv[]){
char a[]={"cat /etc/passwd | grep -i \"boo\" | grep bash suca blyat andrea e frocio | a b c d e f g h i j k l m n o p q r s t u v w x y z | <file1 <file2 suca"};
char*** to_parse = parser(a);
int cmd_index = 0;
if(to_parse != NULL){
while(to_parse[cmd_index] != NULL){
int arg_index = 0;
printf("cmd %d\n", cmd_index);
while(to_parse[cmd_index][arg_index] != NULL){
printf("%s\n", to_parse[cmd_index][arg_index]);
++arg_index;
}
++cmd_index;
}
}
}
char*** parser(char* line){
if(!line_semantic_correctness(line))
return NULL;
char*** mtrx = NULL;
size_t cmds_num = token_counter(line, '|'); //counts how many non '|' tokens are present in the command
size_t rowsto_alloc = cmds_num+1;
if((mtrx=malloc(rowsto_alloc*sizeof(char**))) == NULL){
perror("");
return NULL;
}
mtrx[cmds_num]=NULL;
char* cmd;
char* cmd_context;
int cmd_index = 0;
for(cmd=strtok_r(line, "|", &cmd_context); cmd!=NULL;
cmd=strtok_r(NULL, "|", &cmd_context)){
size_t args_num = token_counter(cmd, ' ');
//counts how many non ' ' tokens are present in the command
size_t colsto_alloc = args_num+1;
if((mtrx[cmd_index]=malloc(colsto_alloc*sizeof(char*))) == NULL){
perror("");
//free?
return NULL;
}
mtrx[cmd_index][cmds_num] = NULL;
char** toredirect = NULL;
size_t toredirect_sz = 1;
char* arg;
char* arg_context;
int arg_index = 0;
for(arg=strtok_r(cmd, " ", &arg_context); arg!=NULL; arg=strtok_r(NULL, " ", &arg_context)){
if(!arg_semantic_correctness(arg, arg_index)){ //analyzes a particular command and returns false when it's not a valid
perror("");
//MEGA FREE: da implementare
return NULL;
}
size_t arg_sz = strlen(arg) + 1;
//if in a command I have redirections written like "<file1" or ">file2" I save them in a double pointer and after analyzing the particular command I push them at the end
//of the corresponding row in my triple pointer
if((arg[0] == '<' ) || (arg[0] == '>' )){
size_t torealloc = toredirect_sz + 1;
if((toredirect=realloc(toredirect, torealloc*sizeof(char*))) == NULL){
perror("");
//free da fare
return NULL;
}
toredirect[toredirect_sz] = NULL;
if((toredirect[toredirect_sz-1] = malloc(arg_sz)) == NULL){
perror("");
//free da fare
return NULL;
}
strncpy(toredirect[toredirect_sz-1], arg, arg_sz);
++toredirect_sz;
}
//in the case the particular argument of a command is not a redirection, I put it directly on the triple pointer
else{
//AFTER THIS ALLOCATION I GET THE SYSMALLOC ASSERTION (when trying to add the second command to the triple pointer)
if((mtrx[cmd_index][arg_index] = malloc(arg_sz)) == NULL){
perror("");
//mega free!!!
return NULL;
}
strncpy(mtrx[cmd_index][arg_index], arg, arg_sz);
++arg_index;
}
}
for(int i = 0; arg_index+i < args_num; ++i){
size_t tocopy_sz = strlen(toredirect[i]) + 1;
if((mtrx[cmd_index][arg_index+i] = malloc(tocopy_sz*sizeof(char))) == NULL){
perror("");
//mega free!!!
return NULL;
}
strncpy(mtrx[cmd_index][arg_index+i], toredirect[i], tocopy_sz);
}
//FREE DI REDIRECTIONS !!!!!!!
++cmd_index;
}
return mtrx;
}
size_t token_counter(const char const * str, char delim){
size_t tok_num = 0;
size_t str_sz = strlen(str);
bool increment = true;
for(int i = 0; i < str_sz; ++i){
if(str[i] == delim){
increment = true;
continue;
}
else if(increment == true){
++tok_num;
increment = false;
}
}
return tok_num;
}
bool double_occurrence(char* str, char occ, size_t line_sz){
for(int i = 0; i < (line_sz - 1); ++i){
if((str[i] == occ) && (str[i+1] == occ))
return true;
}
return false;
}
bool line_semantic_correctness(char* line){
if(line == NULL){
perror("");
return false;
}
if(line[0] == '\0'){
perror("");
return false;
}
size_t line_size = strlen(line);
if(double_occurrence(line, '|', line_size)){
perror("");
return false;
}
if((line[0] == '|') || (line[line_size - 1] == '|')){
perror("");
return false;
}
return true;
}
// se restituisce false, RICORDIAMOCI di fare la mega FREE
bool arg_semantic_correctness(char* arg, int arg_index){
switch(arg_index){
case 0:
if(arg[0] == '\0'){
perror("");
return false;
}
default:
//controllo redirezioni senza file attaccati
if(strlen(arg) == 1){
if((arg[0] == '<') || (arg[0] == '>')){
perror("");
return false;
}
}
}
return true;
}
99 if((mtrx[cmd_index][arg_index] = malloc(arg_sz)) == NULL){
(gdb) p cmd_index
$10 = 0
(gdb) p arg_index
$11 = 1
(gdb) n
104 strncpy(mtrx[cmd_index][arg_index], arg, arg_sz);
(gdb) c
Continuing.
Breakpoint 2, parser (line=0x7fffffffdfc0 "cat") at main.c:99
99 if((mtrx[cmd_index][arg_index] = malloc(arg_sz)) == NULL){
(gdb) p cmd_index
$12 = 1
(gdb) p arg_index
$13 = 0
(gdb) p arg_sz
$14 = 5
(gdb) n
也许错误是你不能将 char*** 与数组一起使用,因为系统不知道 array[] 或 array[][] 或 array[][][] 中的大小
就像 int** in array[12] 和 array[3][4] 是不同的
你需要用 char[][][] 初始化这个 char***
和
char a[]={"cat /etc/passwd | grep -i \"boo\" | grep bash andrea e | a b c d e f g h i j k l m n o p q r s t u v w x y z | <file1 <file2 suca"};
char* argv 中的这个不是 char 数组,它是字符串数组,就像
argv[0] = ".\a.out"
argv[1] = "cat"
argv[2] = "/etc/passwd"
......