#c #string #shell #valgrind #strtok
#c #строка #оболочка #valgrind #strtok
Вопрос:
Я пытаюсь написать свою собственную оболочку на C. У меня проблема. Я написал свою собственную функцию _strtok, которая использует strtok, но возвращает все токены в виде массива строк. Для тестирования я использую строку «ls -laR», определенную в функции main. Я получаю ошибку valgrind «Недопустимая запись размера 8» при попытке malloc количество символов во втором указателе в массиве строк с именем «Doubl». Почему он это делает? Я выделяю нужное количество указателей на строки в массиве doubl. Любая информация или помощь будут оценены
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
char **_strtok(char *str, char *delim)
{
char **doubl;
char *s = str;
char *string;
int i = 0;
while (*s)
{
if (*s == *delim)
i ;
s ;
}
doubl = malloc(sizeof(char *) * i 1);
i = 0;
string = strtok(str, delim);
while (1)
{
doubl[i] = malloc(sizeof(char) * strlen(string) 1);
strcpy(doubl[i], string);
i ;
if (string == NULL)
break;
string = strtok(NULL, delim);
}
return (doubl);
}
char *get_path(char **env)
{
char **check = env;
char *path = NULL;
char pth[] = "PATH";
int i, j, stop = 0;
for (i = 0; check[i] amp;amp; stop == 0; i )
{
for (j = 0; j < 4 amp;amp; stop == 0; j )
{
if (check[i][j] != pth[j])
break;
if (check[i][j] == pth[j] amp;amp; j == 3)
{
path = malloc(strlen(check[i]));
strcpy(path, check[i]);
stop = 1;
}
}
}
return (path);
}
char **cmd_to_arg(char **cmd, char **env)
{
/* FREE PATH BEFORE END */
char *path = get_path(env);
char *slash = "/";
char **args = NULL, **check = _strtok(path, ":"), **checkStart = check, **cmdStart = cmd;
int status = -1, i = 0, j;
while (*checkStart)
{
strcat(*checkStart, slash);
strcat(*checkStart, cmd[0]);
status = access(*checkStart, F_OK | X_OK);
printf("%sn", *checkStart);
if (status == 0)
break;
checkStart ;
}
for(;*cmdStart; i , cmdStart )
printf("%dn", i);
args = malloc(sizeof(char *) * i);
args[0] = malloc(strlen(*checkStart));
strcpy(args[0], *checkStart);
puts(args[0]);
for (j = 1; j < i amp;amp; cmd[j] != NULL; j )
{
//printf("%dn", j);
args[j] = malloc(strlen(cmd[j]) * sizeof(char));
strcpy(args[j], cmd[j]);
puts(args[j]);
}
return (args);
}
int main(int ac, char **av, char **env)
{
(void)ac, (void)av, (void)env;
char line[] = "ls laR";
//size_t size = 0;
char **cmd; //**cmdStart;
//int i = 0, j = 0;
cmd = _strtok(line, " ");
cmd = cmd_to_arg(cmd, env);
return (0);
}
Комментарии:
1. Сколько указателей вы записываете в doubl? i 1? doubl достаточно велик только для i указателей плюс один дополнительный байт.
2. Примечание: в
_strtok
,if (*s == *delim)
проверяет только текущий символ строкиs
на соответствие первому разделителю [другие разделители не проверяются]. Итак, передача" "
работает, но" t"
[или" ,"
] не будет3. Код в
cmd_to_arg
ожидаетNULL
, что в концеcheck
[точно так же, какargv
] будет установлен терминатор. Но_strtok
не выделяет для него пространство и не устанавливает его4. И
doubl = malloc(sizeof(char *) * i 1);
слишком короткий. Из-за приоритета оператора это эквивалентно:doubl = malloc((sizeof(char *) * i) 1);
то, что вы хотите, это:doubl = malloc(sizeof(char *) * (i 1));
5. Но это все равно не дает места для
NULL
, поэтому вы хотите:doubl = malloc(sizeof(char *) * (i 2));
И, вы хотите:doubl[i] = NULL;
в конце функции.